dex2jar源码解析----解析dex文件<一>

时间:2021-08-19 17:17:13

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<String> remainsOptions = new ArrayList<String>();        Set<Option> requiredOpts = collectRequriedOptions(optMap);//收集必须的参数        Option needArgOpt = null;        for (String s : args) {            if (needArgOpt != null) {//是否需要参数                needArgOpt.field.set(this, convert(s, needArgOpt.field.getType()));                needArgOpt = null;            } else if (s.startsWith("-")) {// its a short or long option                Option opt = optMap.get(s);//获取对应的Option                requiredOpts.remove(opt);//从requiredOpts移除该选项                if (opt == null) {                    System.err.println("ERROR: Unrecognized option: " + s);                    throw new HelpException();                } else {                    if (opt.hasArg) {                        needArgOpt = opt;                    } else {                        opt.field.set(this, true);                    }                }            } else {                remainsOptions.add(s);            }        }        if (needArgOpt != null) {//命令行解析失败            System.err.println("ERROR: Option " + needArgOpt.getOptAndLongOpt() + " need an argument value");            throw new HelpException();        }        this.remainingArgs = remainsOptions.toArray(new String[remainsOptions.size()]);        if (this.printHelp) {            throw new HelpException();        }        if (!requiredOpts.isEmpty()) {//必须选项列表不为空,说明条件未满足            StringBuilder sb = new StringBuilder();            sb.append("ERROR: Options: ");            boolean first = true;            for (Option option : requiredOpts) {                if (first) {                    first = false;                } else {                    sb.append(" and ");                }                sb.append(option.getOptAndLongOpt());            }            sb.append(" is required");            System.err.println(sb.toString());            throw new HelpException();        }    }
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<String, DexFileReader> 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");    }


我们看下reader的构造函数

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);

开始dex到jar的转换

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("<clinit>")) {                    // 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();    }

这里根据前面读到的class的数量,调用另外一个accept函数访问该类
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;            }        }    }

找了调用dv的visit,dv是DexFileNode

    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<Integer, Integer> fieldAnnotationPositions;        Map<Integer, Integer> methodAnnotationPositions;        Map<Integer, Integer> paramAnnotationPositions;        if ((config & SKIP_ANNOTATION) == 0) {//是否忽略注释 用来保存方法或者参数的注解,后面解析要用到            // 获取注解            fieldAnnotationPositions = new HashMap<Integer, Integer>();            methodAnnotationPositions = new HashMap<Integer, Integer>();            paramAnnotationPositions = new HashMap<Integer, Integer>();            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<Integer, Integer> 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字段 所属类 类型 名称    }

这里要结合前面的dex文件结构,解析Field字段


下一步是acceptMethod

 private int acceptMethod(ByteBuffer in, int lastIndex, DexClassVisitor cv, Map<Integer, Integer> methodAnnos,                             Map<Integer, Integer> 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 <clinit> or <init> but not marked as ACC_CONSTRUCTOR,        if (0 == (method_access_flags & DexConstants.ACC_CONSTRUCTOR)                && (method.getName().equals("<init>") || method.getName().equals("<clinit>"))) {            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("<clinit>");                    }                    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    }

这里同样要根据前面分析的dex文件结构中的方法字段结构进行解析

然后调用

DexMethodVisitor dmv = cv.visitMethod(method_access_flags, method);
    @Override//访问方法,主要是添加访问标志    public DexMethodVisitor visitMethod(int accessFlags, Method method) {        if (methods == null) {            methods = new ArrayList<DexMethodNode>();        }        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<Integer, DexLabel> labelsMap = new TreeMap<Integer, DexLabel>();        Set<Integer> handlers = new HashSet<Integer>();        // 处理异常处理        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<Integer, DexLabel> labelsMap,                            Set<Integer> handlers,                            Method method) {        Queue<Integer> q = new LinkedList<Integer>();        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<Integer, DexLabel> labelsMap, Queue<Integer> 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            }        }    }

这里主要是获取指令的操作码,根据操作码获取指令 的格式,是否是跳转,switch指令,指令的格式等

指令格式定义了如下类型

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文件中的字段 ,方法,方法中的代码都解析完了,dex中的指令都解析成了 DexStmtNode。包括dex指令中用到的寄存器等,都保存在响应的dexStmtNode指令中。

先分析到这里,后面在分析dex转换为IR,以及优化后在转jvm指令,并写入class文件打成jar 包