java 反编译器源码分析

来源:互联网 发布:cnc编程学徒招聘 编辑:程序博客网 时间:2024/05/19 18:15

简介

由于工作需要反编译分析 java 源码,于是需要反编译器做些改动,所以就有了这篇文章。这次要分析的反编译器是 Femflower,是著名 IDE Idea 的反编译器。源码也是从 Idea 开源部分抠出来的。[Github](https://github.com/JetBrains/intellij-community/tree/master/plugins/java-decompiler/engine)

数据结构

CodeConstants

package org.jetbrains.java.decompiler.code;
代码段,即字节码中的关键字,是所有关键字的父类型,例如 ALOAD,NEW,RET 等。其保存了所有字节码中关键字对应的 Constant,便于词法解析对应。

Instruction

package org.jetbrains.java.decompiler.code;

指令,CodeConstants 的子类型,对应字节码中的指令,同上例如 ALOAD,NEW,RET。众多指令的父类:这些 Instructions 将被保存在一个 Class[] 中。方法 ConstantsUtil. getInstructionInstance 从字节码数据中获取指令对应的 Instruction 类型。
private static Instruction getInstructionInstance(int opcode, int bytecode_version) {  try {    Instruction instr;    if ((opcode >= CodeConstants.opc_ifeq &&         opcode <= CodeConstants.opc_if_acmpne) ||        opcode == CodeConstants.opc_ifnull ||        opcode == CodeConstants.opc_ifnonnull) {      instr = new IfInstruction();    }    else {      Class cl = opcodeClasses[opcode];      if (opcode == CodeConstants.opc_invokedynamic && bytecode_version < CodeConstants.BYTECODE_JAVA_7) {        cl = null; // instruction unused in Java 6 and before      }      if (cl == null) {        instr = new Instruction();      }      else {        instr = (Instruction)cl.newInstance();      }    }    instr.opcode = opcode;    return instr;  }  catch (Exception ex) {    return null;  }}

InstructionSequence

指令片段,其实就是一段字节码的 Instruction 集合。

IMatchable

package org.jetbrains.java.decompiler.struct.match;

可匹配接口,在字节码中,除了上面的所说的指令一类的关键字,那些类似定义的类名,变量名,方法名被称为 Matchable 字段,可结构化的字段。Matchable 主要有两个实现,一是 Statement 分支结构,对应方法,Field,Var 的等声明,二是 Exprent 表达式,类似等于,Field 引用,New Object,if,等等。简单的说 Matchable 类似于指令后面的操作数,即 ALOAD {Mathable}。从字节码中匹配对应的 IMatchable 类型如下:
public IMatchable findObject(MatchNode matchNode, int index)

位于 Imatchbale 接口内。

Statement

package org.jetbrains.java.decompiler.modules.decompiler.stats;
分支结构,类似于 if,Switch,Synchronize,Try Catch等含有分支的结构。

Exprent

package org.jetbrains.java.decompiler.modules.decompiler.exps;
表达式,类似方法调用,变量引用,常量,赋值,New,return 等等都是表达式。

Struct

Struct 是比较重要的,描述了 Java 里面几个比较重要的结构,类型,方法体,Field。除此之外还有一个 Context,上下文,和文件的路径相关。

CosntantPool

常量池,常量池中除了保存了常量之外,还有 Field,Method 的一些关键信息,类成员的名称,Modifers 信息都需要到常量池中读取。

ControlFlowGraph

流程控制图,CFG,程序中有关流程控制例如,循环,if 判断等等,在类似于汇编的字节码中,程序顺序执行,流程控制也是以顺序执行 + 跳转的方式实现。也就是说在字节码中流程控制是一种扁平结构的代码段,而在 java 源码中是类似于图的立体分支结构。那么将字节码中的流程控制代码段转化为 java 代码的大致过程就是:

InstructionSequence 代码段 —(构建图)—> ControlFlowGraph —> Statement 分支语句。。。

/** * 将方法结构体 中的流程控制代码段 转化为分支语句 * @param mt * @param md * @param varProc * @return * @throws IOException   */public static RootStatement codeToJava(StructMethod mt, MethodDescriptor md, VarProcessor varProc) throws IOException {  StructClass cl = mt.getClassStruct();  boolean isInitializer = CodeConstants.CLINIT_NAME.equals(mt.getName()); // for now static initializer only  mt.expandData();  //获取方法体的指令片段  InstructionSequence seq = mt.getInstructionSequence();  //控制流程图  ControlFlowGraph graph = new ControlFlowGraph(seq);  //移除死循环的流程块  DeadCodeHelper.removeDeadBlocks(graph);  //内联方法程序跳转处理  graph.inlineJsr(mt);  // TODO: move to the start, before jsr inlining  DeadCodeHelper.connectDummyExitBlock(graph);  DeadCodeHelper.removeGotos(graph);  ExceptionDeobfuscator.removeCircularRanges(graph);  ExceptionDeobfuscator.restorePopRanges(graph);  if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_EMPTY_RANGES)) {    ExceptionDeobfuscator.removeEmptyRanges(graph);  }  if (DecompilerContext.getOption(IFernflowerPreferences.NO_EXCEPTIONS_RETURN)) {    // special case: single return instruction outside of a protected range    DeadCodeHelper.incorporateValueReturns(graph);  }  //      ExceptionDeobfuscator.restorePopRanges(graph);  ExceptionDeobfuscator.insertEmptyExceptionHandlerBlocks(graph);  DeadCodeHelper.mergeBasicBlocks(graph);  DecompilerContext.getCounterContainer().setCounter(CounterContainer.VAR_COUNTER, mt.getLocalVariables());  if (ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {    DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.Severity.WARN);  }  //流程控制快 -> 代码块  RootStatement root = DomHelper.parseGraph(graph);  //处理 finally 块  FinallyProcessor fProc = new FinallyProcessor(md, varProc);  while (fProc.iterateGraph(mt, root, graph)) {    root = DomHelper.parseGraph(graph);  }  // remove synchronized exception handler  // not until now because of comparison between synchronized statements in the finally cycle  DomHelper.removeSynchronizedHandler(root);  //      LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());  SequenceHelper.condenseSequences(root);  ClearStructHelper.clearStatements(root);  //表达式处理  ExprProcessor proc = new ExprProcessor(md, varProc);  proc.processStatement(root, cl);  SequenceHelper.condenseSequences(root);  //参数栈 v1 v2 v3 什么的  while (true) {    StackVarsProcessor stackProc = new StackVarsProcessor();    stackProc.simplifyStackVars(root, mt, cl);    varProc.setVarVersions(root);    if (!new PPandMMHelper().findPPandMM(root)) {      break;    }  }  while (true) {    LabelHelper.cleanUpEdges(root);    while (true) {      MergeHelper.enhanceLoops(root);      if (LoopExtractHelper.extractLoops(root)) {        continue;      }      if (!IfHelper.mergeAllIfs(root)) {        break;      }    }    if (DecompilerContext.getOption(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION)) {      if (IdeaNotNullHelper.removeHardcodedChecks(root, mt)) {        SequenceHelper.condenseSequences(root);        StackVarsProcessor stackProc = new StackVarsProcessor();        stackProc.simplifyStackVars(root, mt, cl);        varProc.setVarVersions(root);      }    }    LabelHelper.identifyLabels(root);    if (InlineSingleBlockHelper.inlineSingleBlocks(root)) {      continue;    }    // initializer may have at most one return point, so no transformation of method exits permitted    if (isInitializer || !ExitHelper.condenseExits(root)) {      break;    }    // FIXME: !!    //       if(!EliminateLoopsHelper.eliminateLoops(root)) {    //          break;    //       }  }  ExitHelper.removeRedundantReturns(root);  SecondaryFunctionsHelper.identifySecondaryFunctions(root, varProc);  varProc.setVarDefinitions(root);  // must be the last invocation, because it makes the statement structure inconsistent  // FIXME: new edge type needed  LabelHelper.replaceContinueWithBreak(root);  mt.releaseResources();  return root;}

BytecodeMappingTracer

BytecodeMappingTracer 是一个用于跟踪所写 java code 行数的追踪器,每当 TextBuffer写过一行时,tracer 内部的行数都被手动 +1,本来行数是不包括 Class 体上面的 package 语句和 import 语句的。由于需要自行添加 headlines 变量。

TextBuffer

TextBuffer 其实没什么好讲的,java code 的字符串最后都被塞到了这里,类似于 StringBuffer,不过加上了一些函数。需要注意的是对于表达式来说,表达式是一个树形的集合,将表达式树写成 java code 就是对树进行遍历,而每个表达式即树节点都是一个单独的 TextBuffer,最后由 append 拼接。所以想知道某个表达式在一行中具体的位置是比较困难的。 拿 ExitExprent 即 return 表达式来说:
@Overridepublic TextBuffer toJava(int indent, BytecodeMappingTracer tracer) {  tracer.addMapping(bytecode);  if (exitType == EXIT_RETURN) {    TextBuffer buffer = new TextBuffer("return");    if (retType.type != CodeConstants.TYPE_VOID) {      buffer.append(' ');      ExprProcessor.getCastedExprent(value, retType, buffer, indent, false, tracer);    }…………………………..    return buffer;  }

过程

遍历 .class 文件

  1. Femflower.decmpileContext
    //开始反编译
public void decompileContext() {  if (DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {    new IdentifierConverter().rename(structContext);  }  //从 Class 节点开始反编译  classesProcessor = new ClassesProcessor(structContext);  classesProcessor.visitor = visitor;  DecompilerContext.setClassProcessor(classesProcessor);  DecompilerContext.setStructContext(structContext);  structContext.saveContext();}
  1. StructContext.saveContext
public void saveContext() {  for (ContextUnit unit : units.values()) {    if (unit.isOwn()) {      unit.save();    }  }}
  1. ContextUnit.save
/** * 输入分发 */public void save() {  switch (type) {    //文件夹    case TYPE_FOLDER:      // create folder      resultSaver.saveFolder(filename);      // non-class files 无内容的文件,直接拷贝      for (String[] pair : otherEntries) {        resultSaver.copyFile(pair[0], filename, pair[1]);      }      // classes 类文件,需要解析      for (int i = 0; i < classes.size(); i++) {        StructClass cl = classes.get(i);        String entryName = decompiledData.getClassEntryName(cl, classEntries.get(i));        if (entryName != null) {          //反编译这个类 得到 java String          String content = decompiledData.getClassContent(cl);          if (content != null) {            int[] mapping = null;            if (DecompilerContext.getOption(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING)) {              mapping = DecompilerContext.getBytecodeSourceMapper().getOriginalLinesMapping();            }            //保存到本地            resultSaver.saveClassFile(filename, cl.qualifiedName, entryName, content, mapping);          }        }      }      break;    //jar 文件同下 zip 文件    case TYPE_JAR:    case TYPE_ZIP:      // create archive file      resultSaver.saveFolder(archivePath);      resultSaver.createArchive(archivePath, filename, manifest);      // directory entries 生成文件夹结构      for (String dirEntry : dirEntries) {        resultSaver.saveDirEntry(archivePath, filename, dirEntry);      }      // non-class entries 无内容文件 copy      for (String[] pair : otherEntries) {        if (type != TYPE_JAR || !JarFile.MANIFEST_NAME.equalsIgnoreCase(pair[1])) {          resultSaver.copyEntry(pair[0], archivePath, filename, pair[1]);        }      }      // classes 类文件      for (int i = 0; i < classes.size(); i++) {        StructClass cl = classes.get(i);        String entryName = decompiledData.getClassEntryName(cl, classEntries.get(i));        if (entryName != null) {          //反编译          String content = decompiledData.getClassContent(cl);          //保存          resultSaver.saveClassEntry(archivePath, filename, cl.qualifiedName, entryName, content);        }      }      //关闭 zip 文件      resultSaver.closeArchive(archivePath, filename);  }}

反编译一个类

对类基础结构的解析

  1. 入口
/**   * 反编译类文件    * @param cl   * @return   */@Overridepublic String getClassContent(StructClass cl) {  try {    TextBuffer buffer = new TextBuffer(ClassesProcessor.AVERAGE_CLASS_SIZE);    buffer.append(DecompilerContext.getProperty(IFernflowerPreferences.BANNER).toString());    classesProcessor.writeClass(cl, buffer);    return buffer.toString();  }  catch (Throwable ex) {    DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", ex);    return null;  }}
  1. ClassesProcessor.writeClass
    writeClass 函数逻辑比较清晰,先写 package xxxxx, 然后是 import xxxxxx, 最后是类结构。
/**   * 写类文件    * @param cl   * @param buffer   * @throws IOException   */public void writeClass(StructClass cl, TextBuffer buffer) throws IOException {  //class 树,包含父类,内部类外部类等等  ClassNode root = mapRootClasses.get(cl.qualifiedName);  if (root.type != ClassNode.CLASS_ROOT) {    return;  }  DecompilerContext.getLogger().startReadingClass(cl.qualifiedName);  try {    //import 语句的集合    ImportCollector importCollector = new ImportCollector(root);    DecompilerContext.setImportCollector(importCollector);    DecompilerContext.setCounterContainer(new CounterContainer());    DecompilerContext.setBytecodeSourceMapper(new BytecodeSourceMapper());    new LambdaProcessor().processClass(root);    // add simple class names to implicit import    addClassnameToImport(root, importCollector);    // build wrappers for all nested classes (that's where actual processing takes place) 实际拼装类代码的地方    initWrappers(root, null);    // build 内部类    new NestedClassProcessor().processClass(root, root);    // build 内部类 meber 引用    new NestedMemberAccess().propagateMemberAccess(root);    // 写 package 语句    int index = cl.qualifiedName.lastIndexOf("/");    if (index >= 0) {      String packageName = cl.qualifiedName.substring(0, index).replace('/', '.');      buffer.append("package ");      buffer.append(packageName);      buffer.append(";");      buffer.appendLineSeparator();      buffer.appendLineSeparator();    }    // 写 import 语句    int import_lines_written = importCollector.writeImports(buffer);    if (import_lines_written > 0) {      buffer.appendLineSeparator();    }    int offsetLines = buffer.countLines();    TextBuffer classBuffer = new TextBuffer(AVERAGE_CLASS_SIZE);    // 重点,解析 class 结构    new ClassWriter(visitor).classToJava(root, classBuffer, 0, null, offsetLines);    buffer.append(classBuffer);    if (DecompilerContext.getOption(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING)) {      BytecodeSourceMapper mapper = DecompilerContext.getBytecodeSourceMapper();      mapper.addTotalOffset(offsetLines);      if (DecompilerContext.getOption(IFernflowerPreferences.DUMP_ORIGINAL_LINES)) {        buffer.dumpOriginalLineNumbers(mapper.getOriginalLinesMapping());      }      if (DecompilerContext.getOption(IFernflowerPreferences.UNIT_TEST_MODE)) {        buffer.appendLineSeparator();        mapper.dumpMapping(buffer, true);      }    }  }  finally {    destroyWrappers(root);    DecompilerContext.getLogger().endReadingClass();  }}
  1. initWrappers
    ClassWrapper 对比 ClassNode 这个已知的 Class 数据结构多了 Class 内部,Method 外部的 Expert 表达式集合,以及 MethodWrapper 集合,而 MethodWrapper 与 MethodNode 的区别可以类推。
private final VBStyleCollection<Exprent, String> staticFieldInitializersprivate final VBStyleCollection<Exprent, String> dynamicFieldInitializersprivate final VBStyleCollection<MethodWrapper, String> methods

可以看到主要是 Field 定义右边的初始化表达式。

/**   *   * @param node 进入是 root class   * @throws IOException   */private static void initWrappers(ClassNode node, ClassNode root) throws IOException {  if (node.type == ClassNode.CLASS_LAMBDA) {    return;  }  ClassWrapper wrapper = new ClassWrapper(node.classStruct);  // 手动添加根类型  if (root == null) {      wrapper.rootClass = node.classStruct;      root = node;  } else {      wrapper.rootClass = root.classStruct;  }  //结构解析入口  wrapper.init();  node.wrapper = wrapper;  // 递归解析内部类  for (ClassNode nd : node.nested) {    initWrappers(nd, root);  }}
  1. ClassWrapper.init
/**   * 从字节码中解析类结构   * @throws IOException   */public void init() throws IOException {  DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS, classStruct);  DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_WRAPPER, this);  DecompilerContext.getLogger().startClass(classStruct.qualifiedName);  // collect field names  Set<String> setFieldNames = new HashSet<>();  for (StructField fd : classStruct.getFields()) {    setFieldNames.add(fd.getName());  }  int maxSec = Integer.parseInt(DecompilerContext.getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString());  boolean testMode = DecompilerContext.getOption(IFernflowerPreferences.UNIT_TEST_MODE);  // 拼装方法  for (StructMethod mt : classStruct.getMethods()) {    DecompilerContext.getLogger().startMethod(mt.getName() + " " + mt.getDescriptor());    // 参数名列表    VarNamesCollector vc = new VarNamesCollector();    DecompilerContext.setVarNamesCollector(vc);    // 引用计数器    CounterContainer counter = new CounterContainer();    DecompilerContext.setCounterContainer(counter);    // 方法描述, 根据方法全限定名    MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());    VarProcessor varProc = new VarProcessor(mt, md);    DecompilerContext.setProperty(DecompilerContext.CURRENT_VAR_PROCESSOR, varProc);    RootStatement root = null;    boolean isError = false;    try {      if (mt.containsCode()) {        if (maxSec == 0 || testMode) {          root = MethodProcessorRunnable.codeToJava(mt, md, varProc);        }        else {          MethodProcessorRunnable mtProc = new MethodProcessorRunnable(mt, md, varProc, DecompilerContext.getCurrentContext());          Thread mtThread = new Thread(mtProc, "Java decompiler");          //看门狗,当处理方法超过指定时间时,则认为处理失败超时,需要强行杀死线程.          long stopAt = System.currentTimeMillis() + maxSec * 1000;          mtThread.start();          while (!mtProc.isFinished()) {            try {              synchronized (mtProc.lock) {                // 看门狗每 0.2s 检查一次时间                mtProc.lock.wait(200);              }            }            catch (InterruptedException e) {              killThread(mtThread);              throw e;            }            //同上            if (System.currentTimeMillis() >= stopAt) {              String message = "Processing time limit exceeded for method " + mt.getName() + ", execution interrupted.";              DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.ERROR);              killThread(mtThread);              isError = true;              break;            }          }          if (!isError) {            root = mtProc.getResult();          }        }      }      else {        boolean thisVar = !mt.hasModifier(CodeConstants.ACC_STATIC);        int paramCount = 0;        if (thisVar) {          varProc.getThisVars().put(new VarVersionPair(0, 0), classStruct.qualifiedName);          paramCount = 1;        }        paramCount += md.params.length;        int varIndex = 0;        for (int i = 0; i < paramCount; i++) {          varProc.setVarName(new VarVersionPair(varIndex, 0), vc.getFreeName(varIndex));          if (thisVar) {            if (i == 0) {              varIndex++;            }            else {              varIndex += md.params[i - 1].stackSize;            }          }          else {            varIndex += md.params[i].stackSize;          }        }      }    }    catch (Throwable ex) {      DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be decompiled.", ex);      isError = true;    }    MethodWrapper methodWrapper = new MethodWrapper(root, varProc, mt, counter);    methodWrapper.decompiledWithErrors = isError;    methods.addWithKey(methodWrapper, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));    // rename vars so that no one has the same name as a field    varProc.refreshVarNames(new VarNamesCollector(setFieldNames));    // if debug information present and should be used    if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) {      StructLocalVariableTableAttribute attr = mt.getLocalVariableAttr();      if (attr != null) {        // only param names here        varProc.setDebugVarNames(attr.getMapParamNames());        // the rest is here        methodWrapper.getOrBuildGraph().iterateExprents(exprent -> {          List<Exprent> lst = exprent.getAllExprents(true);          lst.add(exprent);          lst.stream()            .filter(e -> e.type == Exprent.EXPRENT_VAR)            .forEach(e -> {              VarExprent varExprent = (VarExprent)e;              String name = varExprent.getDebugName(mt);              if (name != null) {                varProc.setVarName(varExprent.getVarVersionPair(), name);              }            });          return 0;        });      }    }    DecompilerContext.getLogger().endMethod();  }  DecompilerContext.getLogger().endClass();}

核心:ClassWritter

ClassWritter 主要解析了上面所说的类的最主要的直接成员,嵌套的内部类,Field,和 Method。有三个主要方法:1.classTojava:解析类结构本身,2.fieldTojava:解析 Field 3.methodTojava:解析 Method。

classTojava
classToJava 是 ClassWrite 类中其他函数的入口。其最后一个参数 headLines 是自行添加的。

/**   *   * @param node   * @param buffer   * @param indent 缩进 在 Class 块中就是 {}   * @param tracer   * @param headLines 头部行数   */public void classToJava(ClassNode node, TextBuffer buffer, int indent, BytecodeMappingTracer tracer, int headLines) {  ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);  DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node);  int startLine = tracer != null ? tracer.getCurrentSourceLine() : 0;  BytecodeMappingTracer dummy_tracer = new BytecodeMappingTracer(startLine, headLines);  dummy_tracer.visitor = visitor;  dummy_tracer.srcPath = node.getWrapper().rootClass.qualifiedName + ".java";  dummy_tracer.classKey = node.classStruct.qualifiedName;  dummy_tracer.methodKey = "";  try {      Type type = new Type();      type.setName(node.simpleName);      type.setKey(node.classStruct.qualifiedName);      type.setFullName(node.classStruct.qualifiedName.replaceAll("/", "."));      type.setPosition(new Position());    // last minute processing    invokeProcessors(node);    ClassWrapper wrapper = node.getWrapper();    StructClass cl = wrapper.getClassStruct();    DecompilerContext.getLogger().startWriteClass(cl.qualifiedName);    // write class definition    // 写方法描述 这里插入 TypeDefineNode    int start_class_def = buffer.length();    writeClassDefinition(node, buffer, indent, type);    type.getPosition().line = startLine + headLines;    boolean hasContent = false;    boolean enumFields = false;    dummy_tracer.incrementCurrentSourceLine(buffer.countLines(start_class_def));    // 写 Fields    for (StructField fd : cl.getFields()) {      // 是否是隐藏 field 如 this$0      boolean hide = fd.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||                     wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));      if (hide) continue;      // enum field      boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);      if (isEnum) {        if (enumFields) {          buffer.append(',').appendLineSeparator();          dummy_tracer.incrementCurrentSourceLine();        }        enumFields = true;      }      else if (enumFields) {        buffer.append(';');        buffer.appendLineSeparator();        buffer.appendLineSeparator();        dummy_tracer.incrementCurrentSourceLine(2);        enumFields = false;      }      // 写 Fields      fieldToJava(wrapper, cl, fd, buffer, indent + 1, dummy_tracer); // FIXME: insert real tracer      hasContent = true;    }    if (enumFields) {      buffer.append(';').appendLineSeparator();      dummy_tracer.incrementCurrentSourceLine();    }    // FIXME: fields don't matter at the moment    startLine += buffer.countLines(start_class_def);    // methods    for (StructMethod mt : cl.getMethods()) {      boolean hide = mt.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||                     mt.hasModifier(CodeConstants.ACC_BRIDGE) && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE) ||                     wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));      if (hide) continue;      int position = buffer.length();      int storedLine = startLine;      if (hasContent) {        buffer.appendLineSeparator();        startLine++;      }      BytecodeMappingTracer method_tracer = new BytecodeMappingTracer(startLine, headLines);      method_tracer.visitor = visitor;      method_tracer.srcPath = node.getWrapper().rootClass.qualifiedName + ".java";      method_tracer.classKey = node.classStruct.qualifiedName;      method_tracer.methodKey = "." + mt.getName() + mt.getDescriptor();      boolean methodSkipped = !methodToJava(node, mt, buffer, indent + 1, method_tracer);      if (!methodSkipped) {        hasContent = true;        addTracer(cl, mt, method_tracer);        startLine = method_tracer.getCurrentSourceLine();      }      else {        buffer.setLength(position);        startLine = storedLine;      }    }    // member classes 内部类    for (ClassNode inner : node.nested) {      if (inner.type == ClassNode.CLASS_MEMBER) {        StructClass innerCl = inner.classStruct;        boolean isSynthetic = (inner.access & CodeConstants.ACC_SYNTHETIC) != 0 || innerCl.isSynthetic() || inner.namelessConstructorStub;        boolean hide = isSynthetic && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||                       wrapper.getHiddenMembers().contains(innerCl.qualifiedName);        if (hide) continue;        if (hasContent) {          buffer.appendLineSeparator();          startLine++;        }        BytecodeMappingTracer class_tracer = new BytecodeMappingTracer(startLine, headLines);        class_tracer.visitor = visitor;        class_tracer.srcPath = node.getWrapper().rootClass.qualifiedName + ".java";        class_tracer.classKey = inner.classStruct.qualifiedName;        class_tracer.methodKey = "";        // 递归调用        classToJava(inner, buffer, indent + 1, class_tracer, headLines);        startLine = buffer.countLines();        hasContent = true;      }    }    buffer.appendIndent(indent).append('}');    if (node.type != ClassNode.CLASS_ANONYMOUS) {      buffer.appendLineSeparator();    }    if (visitor != null) {        visitor.typeDefine(type);    }  }  finally {    DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, outerNode);  }  DecompilerContext.getLogger().endWriteClass();}

classToField
写 Field ,需要注意的是 Field 的初始化即 = 右边的写则代理给了 Exprent.toJava 方法。

//写 Field 重点 ReferenceNode 切入点private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) {  Field field = new Field();  int start = buffer.length();  boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);  boolean isDeprecated = fd.getAttributes().containsKey("Deprecated");  boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);  field.setName(fd.getName());  field.setInterface(isInterface);  field.setEnum(isEnum);  field.setKey(cl.qualifiedName + "." + fd.getName());  field.setFullName(cl.qualifiedName.replaceAll("/", ".") + "." + fd.getName());  field.setMemberClass(tracer.classKey);  //写废弃 Annotation  if (isDeprecated) {    appendDeprecation(buffer, indent);  }  if (interceptor != null) {    String oldName = interceptor.getOldName(cl.qualifiedName + " " + fd.getName() + " " + fd.getDescriptor());    appendRenameComment(buffer, oldName, MType.FIELD, indent);  }  //匿名字段 多为编译器生成字段  if (fd.isSynthetic()) {    appendComment(buffer, "synthetic field", indent);  }  //写注解 插入点  appendAnnotations(buffer, indent, fd, TypeAnnotation.FIELD);  buffer.appendIndent(indent);  if (!isEnum) {    appendModifiers(buffer, fd.getAccessFlags(), FIELD_ALLOWED, isInterface, FIELD_EXCLUDED);  }  VarType fieldType = new VarType(fd.getDescriptor(), false);  field.setTypeKey(fieldType.value);  // field 全限定名  GenericFieldDescriptor descriptor = null;  if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {    StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)fd.getAttributes().getWithKey("Signature");    if (attr != null) {      descriptor = GenericMain.parseFieldSignature(attr.getSignature());    }  }  if (!isEnum) {    Position typePosition = new Position();    typePosition.line = tracer.getLinesInJavaSource();    field.setTypePosition(typePosition);    if (descriptor != null) {      //由 field 全限定名获取 field 类型的名称      typePosition.start = buffer.length();      String typeKey = GenericMain.getGenericCastTypeName(descriptor.type);      buffer.append(typeKey);      typePosition.end = buffer.length();    }    else {      typePosition.start = buffer.length();      String typeKey = ExprProcessor.getCastTypeName(fieldType);      buffer.append(typeKey);      typePosition.end = buffer.length();    }    buffer.append(' ');  }  int charStart = buffer.length();  //重点 写 field 的名字  buffer.append(fd.getName());  int charEnd = buffer.length();  int line = tracer.getLinesInJavaSource();  //行号增加  tracer.incrementCurrentSourceLine(buffer.countLines(start));  Position position = new Position();  position.start = charStart;  position.end = charEnd;  position.line = line;  position.src = wrapper.rootClass.qualifiedName + ".java";  field.setPosition(position);  //写初始化表达式 int a = {初始化表达式};  Exprent initializer;  if (fd.hasModifier(CodeConstants.ACC_STATIC)) {    field.setStatic(true);    initializer = wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));  }  else {    initializer = wrapper.getDynamicFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));  }  if (initializer != null) {    if (isEnum && initializer.type == Exprent.EXPRENT_NEW) {      NewExprent nexpr = (NewExprent)initializer;      nexpr.setEnumConst(true);      //写操作交由具体的表达式结构体代理      buffer.append(nexpr.toJava(indent, tracer));    }    else {      buffer.append(" = ");      // FIXME: special case field initializer. Can map to more than one method (constructor) and bytecode intruction.      buffer.append(initializer.toJava(indent, tracer));    }  }  else if (fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_STATIC)) {    StructConstantValueAttribute attr =      (StructConstantValueAttribute)fd.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_CONSTANT_VALUE);    if (attr != null) {      PrimitiveConstant constant = cl.getPool().getPrimitiveConstant(attr.getIndex());      buffer.append(" = ");      buffer.append(new ConstExprent(fieldType, constant.value, null).toJava(indent, tracer));    }  }  //结束  if (!isEnum) {    buffer.append(";").appendLineSeparator();    tracer.incrementCurrentSourceLine();  }  if (visitor != null) {      visitor.fieldDefine(field);  }}

methodToJava
同样的,Method 内部也有很多表达式,同样被代理给了 Exprent.toJava

/**   * 写 method   * @param node   * @param mt   * @param buffer   * @param indent   * @param tracer   * @return   */private boolean methodToJava(ClassNode node, StructMethod mt, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) {  Method method = new Method();  method.setName(mt.getName());  method.setPosition(new Position());  method.getPosition().src = node.getWrapper().rootClass.qualifiedName + ".java";  ClassWrapper wrapper = node.getWrapper();  StructClass cl = wrapper.getClassStruct();  MethodWrapper methodWrapper = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());  method.setDefineClass(cl.qualifiedName);  method.setKey(cl.qualifiedName + "." + mt.getName() + mt.getDescriptor());  method.setFullName(cl.qualifiedName.replaceAll("/", ".") + "." + mt.getName());  boolean hideMethod = false;  int start_index_method = buffer.length();  MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);  DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper);  try {    boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);    boolean isAnnotation = cl.hasModifier(CodeConstants.ACC_ANNOTATION);    boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);    boolean isDeprecated = mt.getAttributes().containsKey("Deprecated");    boolean clinit = false, init = false, dinit = false;    MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());    method.setRetType(md.ret.value);    if (md.params != null && md.params.length > 0) {        List<String> parsKey = new ArrayList<>();        for (VarType parType:md.params) {            parsKey.add(parType.value);        }    }    int flags = mt.getAccessFlags();    method.setStatic(mt.hasModifier(CodeConstants.ACC_STATIC));    if ((flags & CodeConstants.ACC_NATIVE) != 0) {      flags &= ~CodeConstants.ACC_STRICT; // compiler bug: a strictfp class sets all methods to strictfp      method.setStatic(true);    }    if (CodeConstants.CLINIT_NAME.equals(mt.getName())) {      flags &= CodeConstants.ACC_STATIC; // ignore all modifiers except 'static' in a static initializer      method.setStatic(true);    }    if (isDeprecated) {      appendDeprecation(buffer, indent);    }    if (interceptor != null) {      String oldName = interceptor.getOldName(cl.qualifiedName + " " + mt.getName() + " " + mt.getDescriptor());      appendRenameComment(buffer, oldName, MType.METHOD, indent);    }    boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic");    boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0;    if (isSynthetic) {      appendComment(buffer, "synthetic method", indent);    }    if (isBridge) {      appendComment(buffer, "bridge method", indent);    }    //写注解    appendAnnotations(buffer, indent, mt, TypeAnnotation.METHOD_RETURN_TYPE);    buffer.appendIndent(indent);    appendModifiers(buffer, flags, METHOD_ALLOWED, isInterface, METHOD_EXCLUDED);    method.setAbstract(mt.hasModifier(CodeConstants.ACC_ABSTRACT));    method.setPublic(mt.hasModifier(CodeConstants.ACC_PUBLIC));    method.setModifiers(flags);    if (isInterface) {        method.setAbstract(true);    }    if (isInterface && mt.containsCode()) {      // 'default' modifier (Java 8)      buffer.append("default ");      method.setAbstract(false);    }    String name = mt.getName();    if (CodeConstants.INIT_NAME.equals(name)) {      if (node.type == ClassNode.CLASS_ANONYMOUS) {        name = "";        dinit = true;      }      else {        name = node.simpleName;        init = true;      }    }    else if (CodeConstants.CLINIT_NAME.equals(name)) {      name = "";      clinit = true;    }    //方法名,方法描述    GenericMethodDescriptor descriptor = null;    if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {      StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)mt.getAttributes().getWithKey("Signature");      if (attr != null) {        descriptor = GenericMain.parseMethodSignature(attr.getSignature());        if (descriptor != null) {          long actualParams = md.params.length;          List<VarVersionPair> sigFields = methodWrapper.signatureFields;          if (sigFields != null) {            actualParams = sigFields.stream().filter(Objects::isNull).count();          }          else if (isEnum && init) actualParams -= 2;          if (actualParams != descriptor.params.size()) {            String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor() + " in " + cl.qualifiedName;            DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);            descriptor = null;          }        }      }    }    boolean throwsExceptions = false;    int paramCount = 0;    if (!clinit && !dinit) {      boolean thisVar = !mt.hasModifier(CodeConstants.ACC_STATIC);      // 方法返回值      if (descriptor != null && !descriptor.fparameters.isEmpty()) {        appendTypeParameters(buffer, descriptor.fparameters, descriptor.fbounds);        buffer.append(' ');      }      if (!init) {        if (descriptor != null) {          buffer.append(GenericMain.getGenericCastTypeName(descriptor.ret));        }        else {          buffer.append(ExprProcessor.getCastTypeName(md.ret));        }        buffer.append(' ');      }      //append 方法名      method.getPosition().start = buffer.length();      buffer.append(toValidJavaIdentifier(name));      method.getPosition().end = buffer.length();      method.getPosition().line = tracer.getLinesInJavaSource();      buffer.append('(');      // parameters 方法参数      List<VarVersionPair> signFields = methodWrapper.signatureFields;      int lastVisibleParameterIndex = -1;      for (int i = 0; i < md.params.length; i++) {        if (signFields == null || signFields.get(i) == null) {          lastVisibleParameterIndex = i;        }      }      boolean firstParameter = true;      int index = isEnum && init ? 3 : thisVar ? 1 : 0;      boolean hasDescriptor = descriptor != null;      int start = isEnum && init && !hasDescriptor ? 2 : 0;      int params = hasDescriptor ? descriptor.params.size() : md.params.length;      for (int i = start; i < params; i++) {        if (hasDescriptor || (signFields == null || signFields.get(i) == null)) {          if (!firstParameter) {            buffer.append(", ");          }          // 参数上的注解          appendParameterAnnotations(buffer, mt, paramCount);          if (methodWrapper.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarTypeProcessor.VAR_EXPLICIT_FINAL) {            buffer.append("final ");          }          if (descriptor != null) {            GenericType parameterType = descriptor.params.get(i);            boolean isVarArg = (i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.arrayDim > 0);            if (isVarArg) {              parameterType = parameterType.decreaseArrayDim();            }            String typeName = GenericMain.getGenericCastTypeName(parameterType);            if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) &&                DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {              typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);            }            buffer.append(typeName);            if (isVarArg) {              buffer.append("...");            }          }          else {            VarType parameterType = md.params[i];            boolean isVarArg = (i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.arrayDim > 0);            if (isVarArg) {              parameterType = parameterType.decreaseArrayDim();            }            String typeName = ExprProcessor.getCastTypeName(parameterType);            if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) &&                DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {              typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);            }            buffer.append(typeName);            if (isVarArg) {              buffer.append("...");            }          }          buffer.append(' ');          String parameterName = methodWrapper.varproc.getVarName(new VarVersionPair(index, 0));          // 写参数名字          buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors          firstParameter = false;          paramCount++;        }        index += md.params[i].stackSize;      }      buffer.append(')');      // 异常列表      StructExceptionsAttribute attr = (StructExceptionsAttribute)mt.getAttributes().getWithKey("Exceptions");      if ((descriptor != null && !descriptor.exceptions.isEmpty()) || attr != null) {        throwsExceptions = true;        buffer.append(" throws ");        List<String> exceptions = new ArrayList<>();        for (int i = 0; i < attr.getThrowsExceptions().size(); i++) {          if (i > 0) {            buffer.append(", ");          }          if (descriptor != null && !descriptor.exceptions.isEmpty()) {            GenericType type = descriptor.exceptions.get(i);            buffer.append(GenericMain.getGenericCastTypeName(type));            exceptions.add(descriptor.exceptions.get(i).value);          }          else {            VarType type = new VarType(attr.getExcClassname(i, cl.getPool()), true);            buffer.append(ExprProcessor.getCastTypeName(type));          }        }        method.setExceptions(exceptions);      }    }    tracer.incrementCurrentSourceLine(buffer.countLines(start_index_method));    if ((flags & (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_NATIVE)) != 0) { // native or abstract method (explicit or interface)      if (isAnnotation) {        StructAnnDefaultAttribute attr = (StructAnnDefaultAttribute)mt.getAttributes().getWithKey("AnnotationDefault");        if (attr != null) {          buffer.append(" default ");          buffer.append(attr.getDefaultValue().toJava(0, BytecodeMappingTracer.DUMMY));        }      }      buffer.append(';');      buffer.appendLineSeparator();      tracer.incrementCurrentSourceLine();    }    else {      if (!clinit && !dinit) {        buffer.append(' ');      }      // We do not have line information for method start, lets have it here for now      buffer.append('{').appendLineSeparator();      tracer.incrementCurrentSourceLine();      // 写方法内部众多的表达式      RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;      if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence        try {          TextBuffer code = root.toJava(indent + 1, tracer);          hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0;          buffer.append(code);        }        catch (Throwable ex) {          DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.", ex);          methodWrapper.decompiledWithErrors = true;        }      }      if (methodWrapper.decompiledWithErrors) {        buffer.appendIndent(indent + 1);        buffer.append("// $FF: Couldn't be decompiled");        buffer.appendLineSeparator();        tracer.incrementCurrentSourceLine();      }      if (root != null) {        tracer.addMapping(root.getDummyExit().bytecode);      }      buffer.appendIndent(indent).append('}').appendLineSeparator();      tracer.incrementCurrentSourceLine();    }  }  finally {    DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper);  }  if (visitor != null) {      visitor.methodDefine(method);  }  // save total lines  // TODO: optimize  //tracer.setCurrentSourceLine(buffer.countLines(start_index_method));  return !hideMethod;}

表达式树以及流程控制

前面相当于 java code 的骨架,表达式相当于 java code 的内容了,表达式一般存在于 变量定义的 = 右边初始化字段,以及 Method 内部大量的表达式。一组有关的表达式(一般是一行)是树形结构,上面说过将表达式树转换为 java code 即是树的遍历。遍历的同时调用 toJava 组装 TextBuffer
public TextBuffer toJava(int indent, BytecodeMappingTracer tracer) {  throw new RuntimeException("not implemented");}

可见是交给具体的表达式实现。
至于 Statement 流程控制语句或者说是分支语句则差不多。

0 0
原创粉丝点击