Dex2jar命令在Dex2jarCmd.java文件中
public static void main(String... args) {
new Dex2jarCmd().doMain(args);
}
这里调用它的toMain函数,可以传递一些参数选项,选项大概有:
@Opt(opt = "e", longOpt = "exception-file", description = "detail exception file, default is $current_dir/[file-name]-error.zip", argName = "file")
private Path exceptionFile;
@Opt(opt = "f", longOpt = "force", hasArg = false, description = "force overwrite")
private boolean forceOverwrite = false;
@Opt(opt = "n", longOpt = "not-handle-exception", hasArg = false, description = "not handle any exceptions thrown by dex2jar")
private boolean notHandleException = false;
@Opt(opt = "o", longOpt = "output", description = "output .jar file, default is $current_dir/[file-name]-dex2jar.jar", argName = "out-jar-file")
private Path output;
@Opt(opt = "r", longOpt = "reuse-reg", hasArg = false, description = "reuse register while generate java .class file")
private boolean reuseReg = false;
@Opt(opt = "s", hasArg = false, description = "same with --topological-sort/-ts")
private boolean topologicalSort1 = false;
@Opt(opt = "ts", longOpt = "topological-sort", hasArg = false, description = "sort block by topological, that will generate more readable code, default enabled")
private boolean topologicalSort = false;
@Opt(opt = "d", longOpt = "debug-info", hasArg = false, description = "translate debug info")
private boolean debugInfo = false;
@Opt(opt = "p", longOpt = "print-ir", hasArg = false, description = "print ir to System.out")
private boolean printIR = false;
@Opt(opt = "os", longOpt = "optmize-synchronized", hasArg = false, description = "optimize-synchronized")
private boolean optmizeSynchronized = false;
@Opt(opt = "nc", longOpt = "no-code", hasArg = false, description = "")
private boolean noCode = false;
Dex2jarCmd继承于BaseCmd
doMain函数实现在BaseCmd.java中
public void doMain(String... args) {
try {
initOptions();
parseSetArgs(args);
doCommandLine();
} catch (HelpException e) {
String msg = e.getMessage();
if (msg != null && msg.length() > 0) {
System.err.println("ERROR: " + msg);
}
usage();
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
initOptions调用initOptionFromClass,传递的是当前的Class
protected void initOptionFromClass(Class> clz) {
if (clz == null) {
return;
} else {
initOptionFromClass(clz.getSuperclass());
}
Syntax syntax = clz.getAnnotation(Syntax.class);
if (syntax != null) {
this.cmdLineSyntax = syntax.syntax();
this.cmdName = syntax.cmd();
this.desc = syntax.desc();
this.onlineHelp = syntax.onlineHelp();
}
Field[] fs = clz.getDeclaredFields();
for (Field f : fs) {
Opt opt = f.getAnnotation(Opt.class);
if (opt != null) {
f.setAccessible(true);
Option option = new Option();
option.field = f;
option.description = opt.description();
option.hasArg = opt.hasArg();
option.required = opt.required();
if ("".equals(opt.longOpt()) && "".equals(opt.opt())) { // into automode
option.longOpt = fromCamel(f.getName());
if (f.getType().equals(boolean.class)) {
option.hasArg=false;
try {
if (f.getBoolean(this)) {
throw new RuntimeException("the value of " + f + " must be false, as it is declared as no args");
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
checkConflict(option, "--" + option.longOpt);
continue;
}
if (!opt.hasArg()) {
if (!f.getType().equals(boolean.class)) {
throw new RuntimeException("the type of " + f
+ " must be boolean, as it is declared as no args");
}
try {
if (f.getBoolean(this)) {
throw new RuntimeException("the value of " + f + " must be false, as it is declared as no args");
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
boolean haveLongOpt = false;
if (!"".equals(opt.longOpt())) {
option.longOpt = opt.longOpt();
checkConflict(option, "--" + option.longOpt);
haveLongOpt = true;
}
if (!"".equals(opt.argName())) {
option.argName = opt.argName();
}
if (!"".equals(opt.opt())) {
option.opt = opt.opt();
checkConflict(option, "-" + option.opt);
} else {
if (!haveLongOpt) {
throw new RuntimeException("opt or longOpt is not set in @Opt(...) " + f);
}
}
}
}
}
这里主要是解析里面的Syntax和Opt注解,对于opt主要是解析代码中定义的opt,把相应的信息保存到optMap,如是否是必须的,是否有参数等
回到doMain
parseSetArgs继续解析我们穿进去的参数
protected void parseSetArgs(String... args) throws IllegalArgumentException, IllegalAccessException {
this.orginalArgs = args;
List remainsOptions = new ArrayList();
Set
parseSetArgs首先收集必须的参数
然后对于我们传进去的参数,依次解析各个选项,如果是必须的选项,则从前面收集的必须选项中移除,表明该必须选项已经存在
最后doMain调用doCommandLine执行dex2jar的解析操作,doCommandLine有子类实现
protected void doCommandLine() throws Exception {
if (remainingArgs.length == 0) {//没有剩余的参数了?
usage();
return;
}
if ((exceptionFile != null || output != null) && remainingArgs.length != 1) {//-e/-o只能有一个文件
System.err.println("-e/-o can only used with one file");
return;
}
if (debugInfo && reuseReg) {//这两个选项不能同时使用
System.err.println("-d/-r can not use together");
return;
}
Path currentDir = new File(".").toPath();//获取当前目录
if (output != null) {//输出文件是否存在
if (Files.exists(output) && !forceOverwrite) {
System.err.println(output + " exists, use --force to overwrite");
return;
}
} else {
for (String fileName : remainingArgs) {
Path file = currentDir.resolve(getBaseName(new File(fileName).toPath()) + "-dex2jar.jar");
//输出文件的名字,如果文件已经存在 则说明要覆盖写--force参数
if (Files.exists(file) && !forceOverwrite) {
System.err.println(file + " exists, use to overwrite");
return;
}
}
}
for (String fileName : remainingArgs) {
// long baseTS = System.currentTimeMillis();
String baseName = getBaseName(new File(fileName).toPath());//去掉后缀之后的名字
Path file = output == null ? currentDir.resolve(baseName + "-dex2jar.jar") : output;//输出文件名
System.err.println("dex2jar " + fileName + " -> " + file);
BaseDexFileReader reader = MultiDexFileReader.open(Files.readAllBytes(new File(fileName).toPath()));
BaksmaliBaseDexExceptionHandler handler = notHandleException ? null : new BaksmaliBaseDexExceptionHandler();
Dex2jar.from(reader).withExceptionHandler(handler).reUseReg(reuseReg).topoLogicalSort()
.skipDebug(!debugInfo).optimizeSynchronized(this.optmizeSynchronized).printIR(printIR)
.noCode(noCode).to(file);
if (!notHandleException) {
if (handler.hasException()) {
Path errorFile = exceptionFile == null ? currentDir.resolve(baseName + "-error.zip")
: exceptionFile;
System.err.println("Detail Error Information in File " + errorFile);
System.err.println(BaksmaliBaseDexExceptionHandler.REPORT_MESSAGE);
handler.dump(errorFile, orginalArgs);
}
}
// long endTS = System.currentTimeMillis();
// System.err.println(String.format("%.2f", (float) (endTS - baseTS) / 1000));
}
}
这里进行一些检查,MultiDexFileReader.open根据文件的后缀新建合适的reader
public static BaseDexFileReader open(byte[] data) throws IOException {
if (data.length < 3) {
throw new IOException("File too small to be a dex/zip");
}
if ("dex".equals(new String(data, 0, 3, StandardCharsets.ISO_8859_1))) {// dex
return new DexFileReader(data);//dex文件
} else if ("PK".equals(new String(data, 0, 2, StandardCharsets.ISO_8859_1))) {// ZIP
TreeMap dexFileReaders = new TreeMap<>();
try (ZipFile zipFile = new ZipFile(data)) {
for (ZipEntry e : zipFile.entries()) {
String entryName = e.getName();
if (entryName.startsWith("classes") && entryName.endsWith(".dex")) {
if (!dexFileReaders.containsKey(entryName)) { // only the first one
dexFileReaders.put(entryName, new DexFileReader(toByteArray(zipFile.getInputStream(e))));
}
}
}
}
if (dexFileReaders.size() == 0) {
throw new IOException("Can not find classes.dex in zip file");
} else if (dexFileReaders.size() == 1) {
return dexFileReaders.firstEntry().getValue();
} else {
return new MultiDexFileReader(dexFileReaders.values());
}
}
throw new IOException("the src file not a .dex or zip file");
}
public DexFileReader(ByteBuffer in) {
in.position(0);
in = in.asReadOnlyBuffer().order(ByteOrder.LITTLE_ENDIAN);//小端模式
int magic = in.getInt() & 0x00FFFFFF;
if (magic == MAGIC_DEX) {//dex
;
} else if (magic == MAGIC_ODEX) {
throw new DexException("Not support odex");
} else {
throw new DexException("not support magic.");
}
int version = in.getInt() & 0x00FFFFFF;//版本号
if (version != MAGIC_035 && version != MAGIC_036) {
throw new DexException("not support version.");
}
// skip uint checksum
// and 20 bytes signature
// and uint file_size
// and uint header_size 0x70
skip(in, 4 + 20 + 4 + 4);
int endian_tag = in.getInt();
if (endian_tag != ENDIAN_CONSTANT) {
throw new DexException("not support endian_tag");
}
// skip uint link_size
// and uint link_off
// and uint map_off
skip(in, 4 + 4 + 4);
//获取各个区段的大小和偏移
string_ids_size = in.getInt();
int string_ids_off = in.getInt();
type_ids_size = in.getInt();
int type_ids_off = in.getInt();
int proto_ids_size = in.getInt();
int proto_ids_off = in.getInt();
field_ids_size = in.getInt();
int field_ids_off = in.getInt();
method_ids_size = in.getInt();
int method_ids_off = in.getInt();
class_defs_size = in.getInt();
int class_defs_off = in.getInt();
// skip uint data_size data_off
//获取偏移和长度获取各个块的buffer
stringIdIn = slice(in, string_ids_off, string_ids_size * 4);
typeIdIn = slice(in, type_ids_off, type_ids_size * 4);
protoIdIn = slice(in, proto_ids_off, proto_ids_size * 12);
fieldIdIn = slice(in, field_ids_off, field_ids_size * 8);
methoIdIn = slice(in, method_ids_off, method_ids_size * 8);
classDefIn = slice(in, class_defs_off, class_defs_size * 32);
//下面又定义了几个buffer后面使用之前会改变position位置
in.position(0);
annotationsDirectoryItemIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN);
annotationSetItemIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN);
annotationItemIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN);
annotationSetRefListIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN);
classDataIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN);
codeItemIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN);
stringDataIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN);
encodedArrayItemIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN);
typeListIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN);
debugInfoIn = in.duplicate().order(ByteOrder.LITTLE_ENDIAN);
}
这里主要是解析dex的头
Dex2jar.from(reader).withExceptionHandler(handler).reUseReg(reuseReg).topoLogicalSort()
.skipDebug(!debugInfo).optimizeSynchronized(this.optmizeSynchronized).printIR(printIR)
.noCode(noCode).to(file);
from通过reader新建一个Dex2jar,后面会调用它的doTranslate开始进行dex2jar的转换
exceptionHandler用来在解析发生异常时进行处理
然后其他的都是一些解析过程中用到的选项的配置
to开始启动解析
public void to(Path file) throws IOException {//把解析后的文件写入 .\classes-dex2jar.jar
if (Files.exists(file) && Files.isDirectory(file)) {//已经存在或者为目录
doTranslate(file);
} else {
try (FileSystem fs = createZip(file)) {
doTranslate(fs.getPath("/"));
}
}
}
最终调用doTranslate
private void doTranslate(final Path dist) throws IOException {
DexFileNode fileNode = new DexFileNode();//创建一个DexFileNode的访问者
try {
reader.accept(fileNode, readerConfig | DexFileReader.IGNORE_READ_EXCEPTION);
} catch (Exception ex) {
exceptionHandler.handleFileException(ex);
}
ClassVisitorFactory cvf = new ClassVisitorFactory() {
@Override
public ClassVisitor create(final String name) {
return new ClassVisitor(Opcodes.ASM4, new ClassWriter(ClassWriter.COMPUTE_MAXS)) {
@Override
public void visitEnd() {
super.visitEnd();
ClassWriter cw = (ClassWriter) super.cv;
byte[] data;
try {
// FIXME handle 'java.lang.RuntimeException: Method code too large!'
data = cw.toByteArray();
} catch (Exception ex) {
System.err.println(String.format("ASM fail to generate .class file: %s", name));
exceptionHandler.handleFileException(ex);
return;
}
try {
Path dist1 = dist.resolve(name + ".class");
Path parent = dist1.getParent();
if (parent != null && !Files.exists(parent)) {
Files.createDirectories(parent);
}
Files.write(dist1, data);
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
};
}
};
new ExDex2Asm(exceptionHandler) {
public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
if ((readerConfig & DexFileReader.SKIP_CODE) != 0 && methodNode.method.getName().equals("")) {
// also skip clinit
return;
}
super.convertCode(methodNode, mv);
}
@Override
public void optimize(IrMethod irMethod) {
T_cleanLabel.transform(irMethod);
if (0 != (v3Config & V3.TOPOLOGICAL_SORT)) {
// T_topologicalSort.transform(irMethod);
}
T_deadCode.transform(irMethod);
T_removeLocal.transform(irMethod);
T_removeConst.transform(irMethod);
T_zero.transform(irMethod);
if (T_npe.transformReportChanged(irMethod)) {
T_deadCode.transform(irMethod);
T_removeLocal.transform(irMethod);
T_removeConst.transform(irMethod);
}
T_new.transform(irMethod);
T_fillArray.transform(irMethod);
T_agg.transform(irMethod);
T_multiArray.transform(irMethod);
T_voidInvoke.transform(irMethod);
if (0 != (v3Config & V3.PRINT_IR)) {
int i = 0;
for (Stmt p : irMethod.stmts) {
if (p.st == Stmt.ST.LABEL) {
LabelStmt labelStmt = (LabelStmt) p;
labelStmt.displayName = "L" + i++;
}
}
System.out.println(irMethod);
}
T_type.transform(irMethod);
T_unssa.transform(irMethod);
T_ir2jRegAssign.transform(irMethod);
T_trimEx.transform(irMethod);
}
@Override
public void ir2j(IrMethod irMethod, MethodVisitor mv) {
new IR2JConverter(0 != (V3.OPTIMIZE_SYNCHRONIZED & v3Config)).convert(irMethod, mv);
}
}.convertDex(fileNode, cvf);
}
这里开始主要是调用reader.accept进行dex文件的解析
然后后面的是把解析的dex文件转换为一个中间的IR格式,进行优化后再转换为jvm指令 进而输出到class文件,这个我们下一篇在看
我们先看accept方法
@Override
public void accept(DexFileVisitor dv, int config) {//使用指定的访问者访问dex文件
for (int cid = 0; cid < class_defs_size; cid++) {//总共有多少个类
accept(dv, cid, config);
}
dv.visitEnd();
}
public void accept(DexFileVisitor dv, int classIdx, int config) {
classDefIn.position(classIdx * 32);//一个类结构占32未
int class_idx = classDefIn.getInt(); /* 类的类型,指向DexTypeId列表的索引 */
int access_flags = classDefIn.getInt();/* 访问标志 */
int superclass_idx = classDefIn.getInt(); /* 父类类型,指向DexTypeId列表的索引 */
int interfaces_off = classDefIn.getInt();/* 接口,指向DexTypeList的偏移 */
int source_file_idx = classDefIn.getInt();/* 源文件名,指向DexStringId列表的索引 */
int annotations_off = classDefIn.getInt();/* 注解,指向DexAnnotationsDirectoryItem结构 */
int class_data_off = classDefIn.getInt();/* 指向DexClassData结构的偏移 */
int static_values_off = classDefIn.getInt(); /* 指向DexEncodedArray结构的偏移 */
String className = getType(class_idx);//根据索引获取类名
String superClassName = getType(superclass_idx);//根据索引获取父类名
String[] interfaceNames = getTypeList(interfaces_off);//根据索引获取接口列表
try {
DexClassVisitor dcv = dv.visit(access_flags, className, superClassName, interfaceNames);
if (dcv != null)// 不为null
{
acceptClass(dcv, source_file_idx, annotations_off, class_data_off, static_values_off, config);
dcv.visitEnd();
}
} catch (Exception ex) {
DexException dexException = new DexException(ex, "Error process class: [%d]%s", class_idx, className);
if (0 != (config & IGNORE_READ_EXCEPTION)) {
niceExceptionMessage(dexException, 0);
} else {
throw dexException;
}
}
}
public DexClassVisitor visit(int access_flags, String className, String superClass, String[] interfaceNames) {
DexClassNode cn = new DexClassNode(access_flags, className, superClass, interfaceNames);//新建一个DexClassNode
clzs.add(cn);//添加到clzs
return cn;
}
新建一个DexClassNode
public DexClassNode(int access, String className, String superClass, String[] interfaceNames) {
super();
this.access = access;
this.className = className;
this.superClass = superClass;
this.interfaceNames = interfaceNames;
}
回到前面的accept,调用acceptClass
private void acceptClass(DexClassVisitor dcv, int source_file_idx, int annotations_off, int class_data_off,
int static_values_off, int config) {
if ((config & SKIP_DEBUG) == 0) {//忽略调试
// 获取源文件
if (source_file_idx != -1) {
dcv.visitSource(this.getString(source_file_idx));
}
}
Map fieldAnnotationPositions;
Map methodAnnotationPositions;
Map paramAnnotationPositions;
if ((config & SKIP_ANNOTATION) == 0) {//是否忽略注释 用来保存方法或者参数的注解,后面解析要用到
// 获取注解
fieldAnnotationPositions = new HashMap();
methodAnnotationPositions = new HashMap();
paramAnnotationPositions = new HashMap();
if (annotations_off != 0) { // annotations_directory_item是否有注释
annotationsDirectoryItemIn.position(annotations_off);//注解偏移
int class_annotations_off = annotationsDirectoryItemIn.getInt();//类注解偏移
int field_annotation_size = annotationsDirectoryItemIn.getInt();//字段注解数量
int method_annotation_size = annotationsDirectoryItemIn.getInt();//方法注解数量
int parameter_annotation_size = annotationsDirectoryItemIn.getInt();//参数注解数量
for (int i = 0; i < field_annotation_size; i++) {//把注解对应的字段的idx和注解偏移对应起来
int field_idx = annotationsDirectoryItemIn.getInt();
int field_annotations_offset = annotationsDirectoryItemIn.getInt();
fieldAnnotationPositions.put(field_idx, field_annotations_offset);
}
for (int i = 0; i < method_annotation_size; i++) {//把注解对应的方法的idx和注解偏移对应起来
int method_idx = annotationsDirectoryItemIn.getInt();
int method_annotation_offset = annotationsDirectoryItemIn.getInt();
methodAnnotationPositions.put(method_idx, method_annotation_offset);
}
for (int i = 0; i < parameter_annotation_size; i++) {//把注解对应的参数变量的idx和注解偏移对应起来
int method_idx = annotationsDirectoryItemIn.getInt();
int parameter_annotation_offset = annotationsDirectoryItemIn.getInt();
paramAnnotationPositions.put(method_idx, parameter_annotation_offset);
}
if (class_annotations_off != 0) {//读取类的注解
try {
read_annotation_set_item(class_annotations_off, dcv);
} catch (Exception e) {
throw new DexException("error on reading Annotation of class ", e);
}
}
}
} else {
fieldAnnotationPositions = null;
methodAnnotationPositions = null;
paramAnnotationPositions = null;
}
if (class_data_off != 0) {//类的详细信息
ByteBuffer in = classDataIn;
in.position(class_data_off);//调整到class的data偏移处
int static_fields = (int) readULeb128i(in);/* 静态字段个数 */
int instance_fields = (int) readULeb128i(in);/* 实例字段个数 */
int direct_methods = (int) readULeb128i(in); /* 直接方法个数 */
int virtual_methods = (int) readULeb128i(in);/* 虚方法个数 */
{
int lastIndex = 0;
{
Object[] constant = null;
if ((config & SKIP_FIELD_CONSTANT) == 0) {//是否忽略常量
if (static_values_off != 0) {//读取常量,final修饰的
constant = read_encoded_array_item(static_values_off);
}
}
for (int i = 0; i < static_fields; i++) {//静态字段
Object value = null;
if (constant != null && i < constant.length) {
value = constant[i];
}
lastIndex = acceptField(in, lastIndex, dcv, fieldAnnotationPositions, value, config);//获取静态字段
}
}
lastIndex = 0;
for (int i = 0; i < instance_fields; i++) {//获取实例字段
lastIndex = acceptField(in, lastIndex, dcv, fieldAnnotationPositions, null, config);
}
lastIndex = 0;
boolean firstMethod = true;
for (int i = 0; i < direct_methods; i++) {//获取直接方法
lastIndex = acceptMethod(in, lastIndex, dcv, methodAnnotationPositions, paramAnnotationPositions,
config, firstMethod);
firstMethod = false;
}
lastIndex = 0;
firstMethod = true;
for (int i = 0; i < virtual_methods; i++) {
lastIndex = acceptMethod(in, lastIndex, dcv, methodAnnotationPositions, paramAnnotationPositions,
config, firstMethod);
firstMethod = false;
}
}
}
}
这里主要是依次调用acceptField解析字段,acceptMethod解析方法
先看acceptField
private int acceptField(ByteBuffer in, int lastIndex, DexClassVisitor dcv,
Map fieldAnnotationPositions, Object value, int config) {
int diff = (int) readULeb128i(in);
int field_access_flags = (int) readULeb128i(in);
int field_id = lastIndex + diff;
Field field = getField(field_id);
// //////////////////////////////////////////////////////////////
DexFieldVisitor dfv = dcv.visitField(field_access_flags, field, value);//访问一个字段 filed中保存了字段的原型,这里传递访问标志 和值
if (dfv != null) {
if ((config & SKIP_ANNOTATION) == 0) {//忽略字段注释
Integer annotation_offset = fieldAnnotationPositions.get(field_id);
if (annotation_offset != null) {
try {
read_annotation_set_item(annotation_offset, dfv);//把注释设置到字段
} catch (Exception e) {
throw new DexException(e, "while accept annotation in field:%s.", field.toString());
}
}
}
dfv.visitEnd();//访问结束
}
// //////////////////////////////////////////////////////////////
return field_id;
}
private Field getField(int id) {
fieldIdIn.position(id * 8);//一个filed占8个字节
int owner_idx = 0xFFFF & fieldIdIn.getShort();/* 类的类型,指向DexTypeId列表的索引 */
int type_idx = 0xFFFF & fieldIdIn.getShort();/* 字段类型,指向DexTypeId列表的索引 */
int name_idx = fieldIdIn.getInt(); /* 字段名,指向DexStringId列表的索引 */
return new Field(getType(owner_idx), getString(name_idx), getType(type_idx));//创建一个Field字段 所属类 类型 名称
}
下一步是acceptMethod
private int acceptMethod(ByteBuffer in, int lastIndex, DexClassVisitor cv, Map methodAnnos,
Map parameterAnnos, int config, boolean firstMethod) {
int offset = in.position();
int diff = (int) readULeb128i(in);
int method_access_flags = (int) readULeb128i(in);/* 访问标志 */
int code_off = (int) readULeb128i(in);/* 指向DexCode结构的偏移 */
int method_id = lastIndex + diff;/* 指向DexMethodId的索引 */
Method method = getMethod(method_id);//获取一个Method
// issue 200, methods may have same signature, we only need to keep the first one
if (!firstMethod && diff == 0) { // detect a duplicated method
WARN("GLITCH: duplicated method %s @%08x", method.toString(), offset);
if ((config & KEEP_ALL_METHODS) == 0) {
WARN("WARN: skip method %s @%08x", method.toString(), offset);
return method_id;
}
}
// issue 195, a or but not marked as ACC_CONSTRUCTOR,
if (0 == (method_access_flags & DexConstants.ACC_CONSTRUCTOR)
&& (method.getName().equals("") || method.getName().equals(""))) {
WARN("GLITCH: method %s @%08x not marked as ACC_CONSTRUCTOR", method.toString(), offset);
}
try {
DexMethodVisitor dmv = cv.visitMethod(method_access_flags, method);
if (dmv != null) {
if ((config & SKIP_ANNOTATION) == 0) {//是否忽略
Integer annotation_offset = methodAnnos.get(method_id);//方法的注释
if (annotation_offset != null) {
try {
read_annotation_set_item(annotation_offset, dmv);
} catch (Exception e) {
throw new DexException(e, "while accept annotation in method:%s.", method.toString());
}
}
Integer parameter_annotation_offset = parameterAnnos.get(method_id);//参数的注释
if (parameter_annotation_offset != null) {
try {
read_annotation_set_ref_list(parameter_annotation_offset, dmv);
} catch (Exception e) {
throw new DexException(e, "while accept parameter annotation in method:%s.",
method.toString());
}
}
}
if (code_off != 0) {//exCode结构
boolean keep = true;
if (0 != (SKIP_CODE & config)) {//是否忽略code
keep = 0 != (KEEP_CLINIT & config) && method.getName().equals("");
}
if (keep) {
DexCodeVisitor dcv = dmv.visitCode();
if (dcv != null) {
try {
acceptCode(code_off, dcv, config, (method_access_flags & DexConstants.ACC_STATIC) != 0,
method);//访问code
} catch (Exception e) {
throw new DexException(e, "while accept code in method:[%s] @%08x", method.toString(),
code_off);
}
}
}
}
dmv.visitEnd();
}
} catch (Exception e) {
throw new DexException(e, "while accept method:[%s]", method.toString());
}
return method_id;
}
//根据methodid获取Method
private Method getMethod(int id) {
methoIdIn.position(id * 8);//调整位置
int owner_idx = 0xFFFF & methoIdIn.getShort(); /* 类的类型,指向DexTypeId列表的索引 */
int proto_idx = 0xFFFF & methoIdIn.getShort(); /* 声明类型,指向DexProtoId列表的索引 */
int name_idx = methoIdIn.getInt(); /* 方法名,指向DexStringId列表的索引 */
String[] parameterTypes;
String returnType;
//DexProtoId占12个字节,跳过前面的shortyIdx
protoIdIn.position(proto_idx * 12 + 4); // move to position and skip shorty_idx
int return_type_idx = protoIdIn.getInt();/* 返回类型 指向DexTypeId列表的索引 */
int parameters_off = protoIdIn.getInt();/* 参数列表 指向DexTypeList的偏移 */
returnType = getType(return_type_idx);
parameterTypes = getTypeList(parameters_off);
return new Method(getType(owner_idx), getString(name_idx), parameterTypes, returnType);//新建一个Method
}
然后调用
DexMethodVisitor dmv = cv.visitMethod(method_access_flags, method);
@Override//访问方法,主要是添加访问标志
public DexMethodVisitor visitMethod(int accessFlags, Method method) {
if (methods == null) {
methods = new ArrayList();
}
DexMethodNode methodNode = new DexMethodNode(accessFlags, method);//新建一个DexMethodNode
methods.add(methodNode);
return methodNode;
}
对于Method,这里主要是解析里面的Code,acceptCode
/* package */void acceptCode(int code_off, DexCodeVisitor dcv, int config, boolean isStatic, Method method) {
ByteBuffer in = codeItemIn;
in.position(code_off);
int registers_size = 0xFFFF & in.getShort();/* 使用的寄存器个数 */
in.getShort();// ins_size ushort/* 参数个数 */
in.getShort();// outs_size ushort/* 调用其他方法时使用的寄存器个数 */
int tries_size = 0xFFFF & in.getShort();/* Try/Catch个数 */
int debug_info_off = in.getInt();/* 指向调试信息的偏移 */
int insns = in.getInt();/*指令集个数,以2字节为单位 */
byte[] insnsArray = new byte[insns * 2];//一个指令占两位
in.get(insnsArray); /* 指令集 */
dcv.visitRegister(registers_size);//访问寄存器
BitSet nextInsn = new BitSet();
Map labelsMap = new TreeMap();
Set handlers = new HashSet();
// 处理异常处理
if (tries_size > 0) {
if ((insns & 0x01) != 0) {// skip padding
in.getShort();
}
findTryCatch(in, dcv, tries_size, insns, labelsMap, handlers);
}
// 处理debug信息
if (debug_info_off != 0 && (0 == (config & SKIP_DEBUG))) {
DexDebugVisitor ddv = dcv.visitDebug();
if (ddv != null) {
read_debug_info(debug_info_off, registers_size, isStatic, method, labelsMap, ddv);
ddv.visitEnd();
}
}
BitSet badOps = new BitSet();
findLabels(insnsArray, nextInsn, badOps, labelsMap, handlers, method);
acceptInsn(insnsArray, dcv, nextInsn, badOps, labelsMap);
dcv.visitEnd();
}
对于acceptCode,主要是调用findLabels找到里面的跳转xiangg 的标签
然后调用acceptInsn解析code里面的指令
先看findLabels
//找到方法中所有指令的起始位置,如有跳转指令则添加到labelsMap
private void findLabels(byte[] insns, BitSet nextBit, BitSet badOps, Map labelsMap,
Set handlers,
Method method) {
Queue q = new LinkedList();
q.add(0);//首先从索引0开始 第一个指令
q.addAll(handlers);//handlers是前面异常处理添加的
handlers.clear();
while (!q.isEmpty()) {
int offset = q.poll();
if (nextBit.get(offset)) {
continue;
} else {
nextBit.set(offset);
}
try {
travelInsn(labelsMap, q, insns, offset);
} catch (IndexOutOfBoundsException indexOutOfRange) {
badOps.set(offset);
WARN("GLITCH: %04x %s | not enough space for reading instruction", offset, method.toString());
} catch (BadOpException badOp) {
badOps.set(offset);
WARN("GLITCH: %04x %s | %s", offset, method.toString(), badOp.getMessage());
}
}
}
从0索引开始,依次解析里面包含的跳转相关的指令
主要是调用travelInsn
//分析当前指令,没有结束的话把下一条指令偏移加入队列,如果有跳转或者分支指令添加到labelsMap表
private void travelInsn(Map labelsMap, Queue q, byte[] insns, int offset) {
int u1offset = offset * 2;//指令是16的倍数,指令格式说明了该指令由多少个16位组成
if (u1offset >= insns.length) {//已经大于指令长度
throw new IndexOutOfBoundsException();
}
int opcode = 0xFF & insns[u1offset];//获取操作码索引(低8位)http://blog.csdn.net/hudashi/article/details/52184035
Op op = null;
if (opcode < Op.ops.length) {
op = Op.ops[opcode];//获取对应的指令
}
if (op == null || op.format == null) {
throw new BadOpException("zero-width instruction op=0x%02x", opcode);
}
int target;
boolean canContinue = true;
if (op.canBranch()) {//是否是跳转指令 labelsMap用来存放跳转指令的标签
switch (op.format) {
case kFmt10t:
target = offset + insns[u1offset + 1];
if (target < 0 || target * 2 > insns.length) {
throw new BadOpException("jump out of insns %s -> %04x", op, target);
}
q.add(target);
order(labelsMap, target);
break;
case kFmt20t:
case kFmt21t://2个16位字节(4个byte 4 * 8) 1个 寄存器 t表示跳转分支指令
target = offset + sshort(insns, u1offset + 2);//跳转的指令偏移,如果成功,则跳过下面不满足条件的指令 target表示跳转到的地址
if (target < 0 || target * 2 > insns.length) {
throw new BadOpException("jump out of insns %s -> %04x", op, target);
}
q.add(target);//添加到队列
order(labelsMap, target);//添加到调整lablesMap
break;
case kFmt22t:
target = offset + sshort(insns, u1offset + 2);
int u = ubyte(insns, u1offset + 1);
boolean cmpSameReg = (u & 0x0F) == ((u >> 4) & 0x0F);
boolean skipTarget = false;
if (cmpSameReg) {
switch (op) {
case IF_EQ:
case IF_GE:
case IF_LE:
// means always jump, equals to goto
canContinue = false;
break;
case IF_NE:
case IF_GT:
case IF_LT:
// means always not jump
skipTarget = true;
break;
default:
break;
}
}
if (!skipTarget) {
if (target < 0 || target * 2 > insns.length) {
throw new BadOpException("jump out of insns %s -> %04x", op, target);
}
q.add(target);
order(labelsMap, target);
}
break;
case kFmt30t:
case kFmt31t:
target = offset + sint(insns, u1offset + 2);
if (target < 0 || target * 2 > insns.length) {
throw new BadOpException("jump out of insns %s -> %04x", op, target);
}
q.add(target);
order(labelsMap, target);
break;
default:
break;
}
}
if (op.canSwitch()) {//分支指令 labelsMap 也存分支标签
order(labelsMap, offset + op.format.size);// 首先把当前指令的大小偏移+大小是下一个指令
int u1SwitchData = 2 * (offset + sint(insns, u1offset + 2));// index table的偏移(32位 4*8)(offset+指令(8位一个byte)
// +寄存器
// (8位一个byte))
if (u1SwitchData + 2 < insns.length) {
switch (insns[u1SwitchData + 1]) {//根据该字段确定switch类型
case 0x01: // packed-switch-data case常量彼此相邻,使用了一个index索引表
{
int size = ushort(insns, u1SwitchData + 2);//case常量个数
int b = u1SwitchData + 8;// targets
for (int i = 0; i < size; i++) {//把case分支跳转添加到队列和labelsMap
target = offset + sint(insns, b + i * 4);
if (target < 0 || target * 2 > insns.length) {
throw new BadOpException("jump out of insns %s -> %04x", op, target);
}
q.add(target);
order(labelsMap, target);
}
break;
}
case 0x02:// sparse-switch-data case常量不相邻
{
int size = ushort(insns, u1SwitchData + 2);
int b = u1SwitchData + 4 + 4 * size;// targets
for (int i = 0; i < size; i++) {
target = offset + sint(insns, b + i * 4);
if (target < 0 || target * 2 > insns.length) {
throw new BadOpException("jump out of insns %s -> %04x", op, target);
}
q.add(target);
order(labelsMap, target);
}
break;
}
default:
throw new BadOpException("bad payload for %s", op);
}
} else {
throw new BadOpException("bad payload offset for %s", op);
}
}
if (canContinue) {//是否继续
int idx = Integer.MAX_VALUE;
switch (op.indexType) {//索引类型
case kIndexStringRef://字符串索引
if (op.format == InstructionFormat.kFmt31c) {
idx = uint(insns, u1offset + 2);
} else {// other
idx = ushort(insns, u1offset + 2);
}
canContinue = idx >= 0 && idx < string_ids_size;
break;
case kIndexTypeRef://类型索引
idx = ushort(insns, u1offset + 2);
canContinue = idx < type_ids_size;
break;
case kIndexMethodRef://方法索引
idx = ushort(insns, u1offset + 2);
canContinue = idx < method_ids_size;
break;
case kIndexFieldRef://字段索引
idx = ushort(insns, u1offset + 2);//读取字(指令偏移2字节)
canContinue = idx < field_ids_size;//小于字段总数 则可以继续
break;
default:
}
if (!canContinue) {
throw new BadOpException("index-out-of-range for %s index: %d", op, idx);
}
}
if (canContinue && op.canContinue()) {//是否继续执行
if (op == Op.NOP) {//是否是空操作
switch (insns[u1offset + 1]) {
case 0x00:
q.add(offset + op.format.size);
break;
case 0x01: {
int size = ushort(insns, u1offset + 2);
q.add(offset + (size * 2) + 4);
break;
}
case 0x02: {
int size = ushort(insns, u1offset + 2);
q.add(offset + (size * 4) + 2);
break;
}
case 0x03: {
int element_width = ushort(insns, u1offset + 2);
int size = uint(insns, u1offset + 4);
q.add(offset + (size * element_width + 1) / 2 + 4);
break;
}
}
} else {
q.add(offset + op.format.size);//把指令偏移和大小之和添加到q
}
}
}
指令格式定义了如下类型
public enum InstructionFormat {//op表示一个8位的操作码
// kFmt00x(0), // unknown format (also used for "breakpoint" opcode)
kFmt10x(1), // op 该指令由一个16进制 使用0个寄存器 无额外数据
kFmt12x(1), // op vA, vB 该指令由一个16进制 使用2个寄存器 无额外数据
kFmt11n(1), // op vA, #+B 该指令由一个16进制 使用1个寄存器 有一个4位立即数
kFmt11x(1), // op vAA 该指令由一个16进制 使用1个寄存器(占8位) 无额外数据
kFmt10t(1), // op +AA 该指令由一个16进制 使用0个寄存器 跳转(占8位)
// kFmt20bc(2), // [opt] op AA, thing@BBBB
kFmt20t(2), // op +AAAA该指令由2个16进制 使用0个寄存器 跳转(占8位)
kFmt22x(2), // op vAA, vBBBB
kFmt21t(2), // op vAA, +BBBB 有2个16进制组成,使用一个寄存器,跳转分支指令
kFmt21s(2), // op vAA, #+BBBB
kFmt21h(2), // op vAA, #+BBBB00000[00000000]
kFmt21c(2), // op vAA, thing@BBBB
kFmt23x(2), // op vAA, vBB, vCC
kFmt22b(2), // op vAA, vBB, #+CC
kFmt22t(2), // op vA, vB, +CCCC
kFmt22s(2), // op vA, vB, #+CCCC
kFmt22c(2), // op vA, vB, thing@CCCC
// kFmt22cs(2), // [opt] op vA, vB, field offset CCCC
kFmt30t(3), // op +AAAAAAAA
kFmt32x(3), // op vAAAA, vBBBB
kFmt31i(3), // op vAA, #+BBBBBBBB
kFmt31t(3), // op vAA, +BBBBBBBB
kFmt31c(3), // op vAA, string@BBBBBBBB
kFmt35c(3), // op {vC,vD,vE,vF,vG}, thing@BBBB
// kFmt35ms(3), // [opt] invoke-virtual+super
kFmt3rc(3), // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
// kFmt3rms(3), // [opt] invoke-virtual+super/range
kFmt51l(5), // op vAA, #+BBBBBBBBBBBBBBBB
// kFmt35mi(3), // [opt] inline invoke
// kFmt3rmi(3), // [opt] inline invoke/range
;
public int size;
InstructionFormat(int size) {
this.size = size;
}
};
然后下面是所有指令的定义
public enum Op implements CFG {
NOP(0x00, "nop", kFmt10x, kIndexNone, kInstrCanContinue, false), //
MOVE(0x01, "move", kFmt12x, kIndexNone, kInstrCanContinue, true), //
MOVE_FROM16(0x02, "move/from16", kFmt22x, kIndexNone, kInstrCanContinue, true), //
MOVE_16(0x03, "move/16", kFmt32x, kIndexNone, kInstrCanContinue, true), //
MOVE_WIDE(0x04, "move-wide", kFmt12x, kIndexNone, kInstrCanContinue, true), //
MOVE_WIDE_FROM16(0x05, "move-wide/from16", kFmt22x, kIndexNone, kInstrCanContinue, true), //
MOVE_WIDE_16(0x06, "move-wide/16", kFmt32x, kIndexNone, kInstrCanContinue, true), //
MOVE_OBJECT(0x07, "move-object", kFmt12x, kIndexNone, kInstrCanContinue, true), //
MOVE_OBJECT_FROM16(0x08, "move-object/from16", kFmt22x, kIndexNone, kInstrCanContinue, true), //
MOVE_OBJECT_16(0x09, "move-object/16", kFmt32x, kIndexNone, kInstrCanContinue, true), //
MOVE_RESULT(0x0a, "move-result", kFmt11x, kIndexNone, kInstrCanContinue, true), //
MOVE_RESULT_WIDE(0x0b, "move-result-wide", kFmt11x, kIndexNone, kInstrCanContinue, true), //
MOVE_RESULT_OBJECT(0x0c, "move-result-object", kFmt11x, kIndexNone, kInstrCanContinue, true), //
MOVE_EXCEPTION(0x0d, "move-exception", kFmt11x, kIndexNone, kInstrCanContinue, true), //
RETURN_VOID(0x0e, "return-void", kFmt10x, kIndexNone, kInstrCanReturn, false), //
RETURN(0x0f, "return", kFmt11x, kIndexNone, kInstrCanReturn, false), //
RETURN_WIDE(0x10, "return-wide", kFmt11x, kIndexNone, kInstrCanReturn, false), //
RETURN_OBJECT(0x11, "return-object", kFmt11x, kIndexNone, kInstrCanReturn, false), //
CONST_4(0x12, "const/4", kFmt11n, kIndexNone, kInstrCanContinue, true), //
CONST_16(0x13, "const/16", kFmt21s, kIndexNone, kInstrCanContinue, true), //
CONST(0x14, "const", kFmt31i, kIndexNone, kInstrCanContinue, true), //
CONST_HIGH16(0x15, "const/high16", kFmt21h, kIndexNone, kInstrCanContinue, true), //
CONST_WIDE_16(0x16, "const-wide/16", kFmt21s, kIndexNone, kInstrCanContinue, true), //
CONST_WIDE_32(0x17, "const-wide/32", kFmt31i, kIndexNone, kInstrCanContinue, true), //
CONST_WIDE(0x18, "const-wide", kFmt51l, kIndexNone, kInstrCanContinue, true), //
CONST_WIDE_HIGH16(0x19, "const-wide/high16", kFmt21h, kIndexNone, kInstrCanContinue, true), //
CONST_STRING(0x1a, "const-string", kFmt21c, kIndexStringRef, kInstrCanContinue | kInstrCanThrow, true), //
CONST_STRING_JUMBO(0x1b, "const-string/jumbo", kFmt31c, kIndexStringRef, kInstrCanContinue | kInstrCanThrow, true), //
CONST_CLASS(0x1c, "const-class", kFmt21c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), //
MONITOR_ENTER(0x1d, "monitor-enter", kFmt11x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), //
MONITOR_EXIT(0x1e, "monitor-exit", kFmt11x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), //
CHECK_CAST(0x1f, "check-cast", kFmt21c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), //
INSTANCE_OF(0x20, "instance-of", kFmt22c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), //
ARRAY_LENGTH(0x21, "array-length", kFmt12x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
NEW_INSTANCE(0x22, "new-instance", kFmt21c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), //
NEW_ARRAY(0x23, "new-array", kFmt22c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), //
FILLED_NEW_ARRAY(0x24, "filled-new-array", kFmt35c, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow, true), //
FILLED_NEW_ARRAY_RANGE(0x25, "filled-new-array/range", kFmt3rc, kIndexTypeRef, kInstrCanContinue | kInstrCanThrow,
true), //
FILL_ARRAY_DATA(0x26, "fill-array-data", kFmt31t, kIndexNone, kInstrCanContinue, false), //
THROW(0x27, "throw", kFmt11x, kIndexNone, kInstrCanThrow, false), //
GOTO(0x28, "goto", kFmt10t, kIndexNone, kInstrCanBranch, false), //
GOTO_16(0x29, "goto/16", kFmt20t, kIndexNone, kInstrCanBranch, false), //
GOTO_32(0x2a, "goto/32", kFmt30t, kIndexNone, kInstrCanBranch, false), //
PACKED_SWITCH(0x2b, "packed-switch", kFmt31t, kIndexNone, kInstrCanContinue | kInstrCanSwitch, false), //
SPARSE_SWITCH(0x2c, "sparse-switch", kFmt31t, kIndexNone, kInstrCanContinue | kInstrCanSwitch, false), //
CMPL_FLOAT(0x2d, "cmpl-float", kFmt23x, kIndexNone, kInstrCanContinue, false), //
CMPG_FLOAT(0x2e, "cmpg-float", kFmt23x, kIndexNone, kInstrCanContinue, false), //
CMPL_DOUBLE(0x2f, "cmpl-double", kFmt23x, kIndexNone, kInstrCanContinue, false), //
CMPG_DOUBLE(0x30, "cmpg-double", kFmt23x, kIndexNone, kInstrCanContinue, false), //
CMP_LONG(0x31, "cmp-long", kFmt23x, kIndexNone, kInstrCanContinue, false), //
IF_EQ(0x32, "if-eq", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
IF_NE(0x33, "if-ne", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
IF_LT(0x34, "if-lt", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
IF_GE(0x35, "if-ge", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
IF_GT(0x36, "if-gt", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
IF_LE(0x37, "if-le", kFmt22t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
IF_EQZ(0x38, "if-eqz", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
IF_NEZ(0x39, "if-nez", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
IF_LTZ(0x3a, "if-ltz", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
IF_GEZ(0x3b, "if-gez", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
IF_GTZ(0x3c, "if-gtz", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
IF_LEZ(0x3d, "if-lez", kFmt21t, kIndexNone, kInstrCanBranch | kInstrCanContinue, false), //
// UNUSED_3E(0x3e, "unused-3e", null, kIndexUnknown, 0, false), //
// UNUSED_3F(0x3f, "unused-3f", null, kIndexUnknown, 0, false), //
// UNUSED_40(0x40, "unused-40", null, kIndexUnknown, 0, false), //
// UNUSED_41(0x41, "unused-41", null, kIndexUnknown, 0, false), //
// UNUSED_42(0x42, "unused-42", null, kIndexUnknown, 0, false), //
// UNUSED_43(0x43, "unused-43", null, kIndexUnknown, 0, false), //
AGET(0x44, "aget", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AGET_WIDE(0x45, "aget-wide", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AGET_OBJECT(0x46, "aget-object", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AGET_BOOLEAN(0x47, "aget-boolean", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AGET_BYTE(0x48, "aget-byte", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AGET_CHAR(0x49, "aget-char", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AGET_SHORT(0x4a, "aget-short", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
APUT(0x4b, "aput", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), //
APUT_WIDE(0x4c, "aput-wide", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), //
APUT_OBJECT(0x4d, "aput-object", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), //
APUT_BOOLEAN(0x4e, "aput-boolean", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), //
APUT_BYTE(0x4f, "aput-byte", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), //
APUT_CHAR(0x50, "aput-char", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), //
APUT_SHORT(0x51, "aput-short", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, false), //
IGET(0x52, "iget", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
IGET_WIDE(0x53, "iget-wide", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
IGET_OBJECT(0x54, "iget-object", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
IGET_BOOLEAN(0x55, "iget-boolean", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
IGET_BYTE(0x56, "iget-byte", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
IGET_CHAR(0x57, "iget-char", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
IGET_SHORT(0x58, "iget-short", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
IPUT(0x59, "iput", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
IPUT_WIDE(0x5a, "iput-wide", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
IPUT_OBJECT(0x5b, "iput-object", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
IPUT_BOOLEAN(0x5c, "iput-boolean", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
IPUT_BYTE(0x5d, "iput-byte", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
IPUT_CHAR(0x5e, "iput-char", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
IPUT_SHORT(0x5f, "iput-short", kFmt22c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
SGET(0x60, "sget", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
SGET_WIDE(0x61, "sget-wide", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
SGET_OBJECT(0x62, "sget-object", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
SGET_BOOLEAN(0x63, "sget-boolean", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
SGET_BYTE(0x64, "sget-byte", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
SGET_CHAR(0x65, "sget-char", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
SGET_SHORT(0x66, "sget-short", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, true), //
SPUT(0x67, "sput", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
SPUT_WIDE(0x68, "sput-wide", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
SPUT_OBJECT(0x69, "sput-object", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
SPUT_BOOLEAN(0x6a, "sput-boolean", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
SPUT_BYTE(0x6b, "sput-byte", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
SPUT_CHAR(0x6c, "sput-char", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
SPUT_SHORT(0x6d, "sput-short", kFmt21c, kIndexFieldRef, kInstrCanContinue | kInstrCanThrow, false), //
INVOKE_VIRTUAL(0x6e, "invoke-virtual", kFmt35c, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke,
true), //
INVOKE_SUPER(0x6f, "invoke-super", kFmt35c, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke,
true), //
INVOKE_DIRECT(0x70, "invoke-direct", kFmt35c, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke,
true), //
INVOKE_STATIC(0x71, "invoke-static", kFmt35c, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow | kInstrInvoke,
true), //
INVOKE_INTERFACE(0x72, "invoke-interface", kFmt35c, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow
| kInstrInvoke, true), //
// UNUSED_73(0x73, "unused-73", null, kIndexUnknown, 0, false), //
INVOKE_VIRTUAL_RANGE(0x74, "invoke-virtual/range", kFmt3rc, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow
| kInstrInvoke, true), //
INVOKE_SUPER_RANGE(0x75, "invoke-super/range", kFmt3rc, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow
| kInstrInvoke, true), //
INVOKE_DIRECT_RANGE(0x76, "invoke-direct/range", kFmt3rc, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow
| kInstrInvoke, true), //
INVOKE_STATIC_RANGE(0x77, "invoke-static/range", kFmt3rc, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow
| kInstrInvoke, true), //
INVOKE_INTERFACE_RANGE(0x78, "invoke-interface/range", kFmt3rc, kIndexMethodRef, kInstrCanContinue | kInstrCanThrow
| kInstrInvoke, true), //
// UNUSED_79(0x79, "unused-79", null, kIndexUnknown, 0, false), //
// UNUSED_7A(0x7a, "unused-7a", null, kIndexUnknown, 0, false), //
NEG_INT(0x7b, "neg-int", kFmt12x, kIndexNone, kInstrCanContinue, true), //
NOT_INT(0x7c, "not-int", kFmt12x, kIndexNone, kInstrCanContinue, true), //
NEG_LONG(0x7d, "neg-long", kFmt12x, kIndexNone, kInstrCanContinue, true), //
NOT_LONG(0x7e, "not-long", kFmt12x, kIndexNone, kInstrCanContinue, true), //
NEG_FLOAT(0x7f, "neg-float", kFmt12x, kIndexNone, kInstrCanContinue, true), //
NEG_DOUBLE(0x80, "neg-double", kFmt12x, kIndexNone, kInstrCanContinue, true), //
INT_TO_LONG(0x81, "int-to-long", kFmt12x, kIndexNone, kInstrCanContinue, true), //
INT_TO_FLOAT(0x82, "int-to-float", kFmt12x, kIndexNone, kInstrCanContinue, true), //
INT_TO_DOUBLE(0x83, "int-to-double", kFmt12x, kIndexNone, kInstrCanContinue, true), //
LONG_TO_INT(0x84, "long-to-int", kFmt12x, kIndexNone, kInstrCanContinue, true), //
LONG_TO_FLOAT(0x85, "long-to-float", kFmt12x, kIndexNone, kInstrCanContinue, true), //
LONG_TO_DOUBLE(0x86, "long-to-double", kFmt12x, kIndexNone, kInstrCanContinue, true), //
FLOAT_TO_INT(0x87, "float-to-int", kFmt12x, kIndexNone, kInstrCanContinue, true), //
FLOAT_TO_LONG(0x88, "float-to-long", kFmt12x, kIndexNone, kInstrCanContinue, true), //
FLOAT_TO_DOUBLE(0x89, "float-to-double", kFmt12x, kIndexNone, kInstrCanContinue, true), //
DOUBLE_TO_INT(0x8a, "double-to-int", kFmt12x, kIndexNone, kInstrCanContinue, true), //
DOUBLE_TO_LONG(0x8b, "double-to-long", kFmt12x, kIndexNone, kInstrCanContinue, true), //
DOUBLE_TO_FLOAT(0x8c, "double-to-float", kFmt12x, kIndexNone, kInstrCanContinue, true), //
INT_TO_BYTE(0x8d, "int-to-byte", kFmt12x, kIndexNone, kInstrCanContinue, true), //
INT_TO_CHAR(0x8e, "int-to-char", kFmt12x, kIndexNone, kInstrCanContinue, true), //
INT_TO_SHORT(0x8f, "int-to-short", kFmt12x, kIndexNone, kInstrCanContinue, true), //
ADD_INT(0x90, "add-int", kFmt23x, kIndexNone, kInstrCanContinue, true), //
SUB_INT(0x91, "sub-int", kFmt23x, kIndexNone, kInstrCanContinue, true), //
MUL_INT(0x92, "mul-int", kFmt23x, kIndexNone, kInstrCanContinue, true), //
DIV_INT(0x93, "div-int", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
REM_INT(0x94, "rem-int", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AND_INT(0x95, "and-int", kFmt23x, kIndexNone, kInstrCanContinue, true), //
OR_INT(0x96, "or-int", kFmt23x, kIndexNone, kInstrCanContinue, true), //
XOR_INT(0x97, "xor-int", kFmt23x, kIndexNone, kInstrCanContinue, true), //
SHL_INT(0x98, "shl-int", kFmt23x, kIndexNone, kInstrCanContinue, true), //
SHR_INT(0x99, "shr-int", kFmt23x, kIndexNone, kInstrCanContinue, true), //
USHR_INT(0x9a, "ushr-int", kFmt23x, kIndexNone, kInstrCanContinue, true), //
ADD_LONG(0x9b, "add-long", kFmt23x, kIndexNone, kInstrCanContinue, true), //
SUB_LONG(0x9c, "sub-long", kFmt23x, kIndexNone, kInstrCanContinue, true), //
MUL_LONG(0x9d, "mul-long", kFmt23x, kIndexNone, kInstrCanContinue, true), //
DIV_LONG(0x9e, "div-long", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
REM_LONG(0x9f, "rem-long", kFmt23x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AND_LONG(0xa0, "and-long", kFmt23x, kIndexNone, kInstrCanContinue, true), //
OR_LONG(0xa1, "or-long", kFmt23x, kIndexNone, kInstrCanContinue, true), //
XOR_LONG(0xa2, "xor-long", kFmt23x, kIndexNone, kInstrCanContinue, true), //
SHL_LONG(0xa3, "shl-long", kFmt23x, kIndexNone, kInstrCanContinue, true), //
SHR_LONG(0xa4, "shr-long", kFmt23x, kIndexNone, kInstrCanContinue, true), //
USHR_LONG(0xa5, "ushr-long", kFmt23x, kIndexNone, kInstrCanContinue, true), //
ADD_FLOAT(0xa6, "add-float", kFmt23x, kIndexNone, kInstrCanContinue, true), //
SUB_FLOAT(0xa7, "sub-float", kFmt23x, kIndexNone, kInstrCanContinue, true), //
MUL_FLOAT(0xa8, "mul-float", kFmt23x, kIndexNone, kInstrCanContinue, true), //
DIV_FLOAT(0xa9, "div-float", kFmt23x, kIndexNone, kInstrCanContinue, true), //
REM_FLOAT(0xaa, "rem-float", kFmt23x, kIndexNone, kInstrCanContinue, true), //
ADD_DOUBLE(0xab, "add-double", kFmt23x, kIndexNone, kInstrCanContinue, true), //
SUB_DOUBLE(0xac, "sub-double", kFmt23x, kIndexNone, kInstrCanContinue, true), //
MUL_DOUBLE(0xad, "mul-double", kFmt23x, kIndexNone, kInstrCanContinue, true), //
DIV_DOUBLE(0xae, "div-double", kFmt23x, kIndexNone, kInstrCanContinue, true), //
REM_DOUBLE(0xaf, "rem-double", kFmt23x, kIndexNone, kInstrCanContinue, true), //
ADD_INT_2ADDR(0xb0, "add-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
SUB_INT_2ADDR(0xb1, "sub-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
MUL_INT_2ADDR(0xb2, "mul-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
DIV_INT_2ADDR(0xb3, "div-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
REM_INT_2ADDR(0xb4, "rem-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AND_INT_2ADDR(0xb5, "and-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
OR_INT_2ADDR(0xb6, "or-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
XOR_INT_2ADDR(0xb7, "xor-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
SHL_INT_2ADDR(0xb8, "shl-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
SHR_INT_2ADDR(0xb9, "shr-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
USHR_INT_2ADDR(0xba, "ushr-int/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
ADD_LONG_2ADDR(0xbb, "add-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
SUB_LONG_2ADDR(0xbc, "sub-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
MUL_LONG_2ADDR(0xbd, "mul-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
DIV_LONG_2ADDR(0xbe, "div-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
REM_LONG_2ADDR(0xbf, "rem-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AND_LONG_2ADDR(0xc0, "and-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
OR_LONG_2ADDR(0xc1, "or-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
XOR_LONG_2ADDR(0xc2, "xor-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
SHL_LONG_2ADDR(0xc3, "shl-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
SHR_LONG_2ADDR(0xc4, "shr-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
USHR_LONG_2ADDR(0xc5, "ushr-long/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
ADD_FLOAT_2ADDR(0xc6, "add-float/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
SUB_FLOAT_2ADDR(0xc7, "sub-float/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
MUL_FLOAT_2ADDR(0xc8, "mul-float/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
DIV_FLOAT_2ADDR(0xc9, "div-float/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
REM_FLOAT_2ADDR(0xca, "rem-float/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
ADD_DOUBLE_2ADDR(0xcb, "add-double/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
SUB_DOUBLE_2ADDR(0xcc, "sub-double/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
MUL_DOUBLE_2ADDR(0xcd, "mul-double/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
DIV_DOUBLE_2ADDR(0xce, "div-double/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
REM_DOUBLE_2ADDR(0xcf, "rem-double/2addr", kFmt12x, kIndexNone, kInstrCanContinue, true), //
ADD_INT_LIT16(0xd0, "add-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue, true), //
RSUB_INT(0xd1, "rsub-int", kFmt22s, kIndexNone, kInstrCanContinue, true), //
MUL_INT_LIT16(0xd2, "mul-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue, true), //
DIV_INT_LIT16(0xd3, "div-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
REM_INT_LIT16(0xd4, "rem-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AND_INT_LIT16(0xd5, "and-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue, true), //
OR_INT_LIT16(0xd6, "or-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue, true), //
XOR_INT_LIT16(0xd7, "xor-int/lit16", kFmt22s, kIndexNone, kInstrCanContinue, true), //
ADD_INT_LIT8(0xd8, "add-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), //
RSUB_INT_LIT8(0xd9, "rsub-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), //
MUL_INT_LIT8(0xda, "mul-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), //
DIV_INT_LIT8(0xdb, "div-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
REM_INT_LIT8(0xdc, "rem-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue | kInstrCanThrow, true), //
AND_INT_LIT8(0xdd, "and-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), //
OR_INT_LIT8(0xde, "or-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), //
XOR_INT_LIT8(0xdf, "xor-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), //
SHL_INT_LIT8(0xe0, "shl-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), //
SHR_INT_LIT8(0xe1, "shr-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), //
USHR_INT_LIT8(0xe2, "ushr-int/lit8", kFmt22b, kIndexNone, kInstrCanContinue, true), //
BAD_OP(-1, "bad-opcode", null, kIndexNone, 0, false), //
;
public int opcode;
public InstructionFormat format;
/* package */InstructionIndexType indexType;
/* package */int flags;
public String displayName;
public final static Op ops[] = new Op[256];
public boolean changeFrame;
static {
Op[] ops = Op.ops;
for (Op op : Op.values()) {
if (op.opcode >= 0) {
ops[op.opcode] = op;
}
}
}
public boolean canBranch() {
return 0 != (flags & kInstrCanBranch);
}
public boolean canContinue() {
return 0 != (flags & kInstrCanContinue);
}
public boolean canReturn() {
return 0 != (flags & kInstrCanReturn);
}
public boolean canSwitch() {
return 0 != (flags & kInstrCanSwitch);
}
public boolean canThrow() {
return 0 != (flags & kInstrCanThrow);
}
Op(int op, String displayName, InstructionFormat fmt, InstructionIndexType indexType, int flags, boolean changeFrame) {
this.opcode = op;
this.displayName = displayName;
this.format = fmt;
this.indexType = indexType;
this.flags = flags;
}
public String toString() {
return displayName;
}
}
是否可跳转,继续等
先分析到这里,后面在分析dex转换为IR,以及优化后在转jvm指令,并写入class文件打成jar 包