📄 sourcecodebuilder.java
字号:
/*
* Author jyang Created on 2006-4-5 10:30:53
*/
package com.jasml.decompiler;
import java.util.HashSet;
import com.jasml.classes.Attribute;
import com.jasml.classes.Attribute_Code;
import com.jasml.classes.Attribute_ConstantValue;
import com.jasml.classes.Attribute_Deprecated;
import com.jasml.classes.Attribute_Exceptions;
import com.jasml.classes.Attribute_InnerClasses;
import com.jasml.classes.Attribute_LineNumberTable;
import com.jasml.classes.Attribute_LocalVariableTable;
import com.jasml.classes.Attribute_SourceFile;
import com.jasml.classes.Attribute_Synthetic;
import com.jasml.classes.ConstantPool;
import com.jasml.classes.ConstantPoolItem;
import com.jasml.classes.Constant_Class;
import com.jasml.classes.Constant_Double;
import com.jasml.classes.Constant_Fieldref;
import com.jasml.classes.Constant_Float;
import com.jasml.classes.Constant_Integer;
import com.jasml.classes.Constant_InterfaceMethodref;
import com.jasml.classes.Constant_Long;
import com.jasml.classes.Constant_Methodref;
import com.jasml.classes.Constant_NameAndType;
import com.jasml.classes.Constant_String;
import com.jasml.classes.Constant_Utf8;
import com.jasml.classes.Constants;
import com.jasml.classes.Field;
import com.jasml.classes.JavaClass;
import com.jasml.classes.Method;
import com.jasml.classes.Attribute_LocalVariableTable.LocalVariable;
import com.jasml.helper.OpcodeHelper;
import com.jasml.helper.Util;
public class SourceCodeBuilder {
ConstantPool cpl;
SourceCodeBuilderConfiguration config;
public SourceCodeBuilder() {
config = new SourceCodeBuilderConfiguration();
}
public SourceCodeBuilder(SourceCodeBuilderConfiguration config) {
this.config = config;
}
private String toString(Attribute_ConstantValue var) {
return toString(cpl.getConstant(var.constant_value_index));
}
private String toString(Attribute_Deprecated var) {
return "[" + Constants.ATTRIBUTE_NAME_DEPRECATED + "]";
}
private String toString(Attribute_Synthetic var) {
return "[" + Constants.ATTRIBUTE_NAME_SYNTHETIC + "]";
}
private String toString(Attribute_SourceFile var) {
return "[" + Constants.ATTRIBUTE_NAME_SOURCE_FILE + " : " + toString(cpl.getConstant(var.sourcefile_index)) + "]";
}
private String toString(Attribute_LocalVariableTable attr, Attribute_Code.Opcode[] ops) {
if (attr.local_variable_table_length == 0)
return "";
StringBuffer buf = new StringBuffer();
buf.append("[" + Constants.ATTRIBUTE_NAME_LOCAL_VARIABLE + " :");
LocalVariable var;
for (int i = 0; i < attr.local_variable_table_length; i++) {
var = attr.local_variable_table[i];
buf.append(Constants.LINE_SEPARATER);
buf.append(Util.descriptorToString(toString(cpl.getConstant(var.descriptor_index)))); // descriptor
buf.append(" ");
buf.append(toString(cpl.getConstant(var.name_index))); // name
buf.append(" ");
buf.append("start=" + config.labelPrefix + var.start_pc); // start position
buf.append(", ");
buf.append("end=" + config.labelPrefix + (findPreviousInstruction(var.start_pc + var.length, ops)).offset); // valid scope
buf.append(", ");
buf.append("index=" + var.index); // index into runtime frame
}
buf.append("]");
return buf.toString();
}
private String toString(Attribute_LineNumberTable attr) {
if (attr.line_number_table_length == 0)
return "";
StringBuffer buf = new StringBuffer();
buf.append("[" + Constants.ATTRIBUTE_NAME_LINE_NUMBER_TABLE + " :");
for (int i = 0; i < attr.line_number_table_length; i++) {
buf.append(Constants.LINE_SEPARATER);
buf.append(config.labelPrefix + attr.lineNumberTable[i].start_pc + " -> " + attr.lineNumberTable[i].line_number);
}
buf.append("]");
return buf.toString();
}
private String toString(Attribute_InnerClasses attr) {
StringBuffer buf = new StringBuffer();
Attribute_InnerClasses.InnerClass innerClass;
buf.append("[" + Constants.ATTRIBUTE_NAME_INNER_CLASSES + " :");
for (int i = 0; i < attr.number_of_classes; i++) {
buf.append(Constants.LINE_SEPARATER);
innerClass = attr.innerClasses[i];
// access flag
buf.append("access = " + Util.accessFlagToString_Class((short) innerClass.inner_class_access_flags) + " , ");
// inner class name
buf.append("name = ");
if (innerClass.inner_name_index == 0) {
buf.append("0 , ");
} else {
buf.append(toString(cpl.getConstant(innerClass.inner_name_index)) + " , ");
}
// inner class info
buf.append("fullname = ");
buf.append(toString(cpl.getConstant(innerClass.inner_class_info_index)) + " , ");
// outer class info
buf.append("outername = ");
if (innerClass.outer_class_info_index == 0) {
buf.append("0");
} else {
buf.append(toString(cpl.getConstant(innerClass.outer_class_info_index)));
}
}
buf.append(']');
return buf.toString();
}
private String toString(Attribute_Exceptions attr) {
if (attr.number_of_exceptions == 0)
return "";
StringBuffer buf = new StringBuffer();
for (int i = 0; i < attr.number_of_exceptions; i++) {
buf.append(toString(cpl.getConstant(attr.exception_index_table[i])) + ",");
}
buf.deleteCharAt(buf.length() - 1);
return buf.toString();
}
private String getLocalVariableName(int index, int codeOffset, Attribute_LocalVariableTable.LocalVariable[] lvts) {
if (lvts == null) {
return "UnknowVariable";
}
int i;
Attribute_LocalVariableTable.LocalVariable lv;
for (i = 0; i < lvts.length; i++) {
lv = lvts[i];
if (lv.index == index && lv.start_pc <= codeOffset && (lv.start_pc + lv.length) >= codeOffset) {
return toString(cpl.getConstant(lv.name_index));
}
}
// no match found, TODO: why could this happen
// search for the one with the same index value
for (i = 0; i < lvts.length; i++) {
lv = lvts[i];
if (lv.index == index) {
return toString(cpl.getConstant(lv.name_index));
}
}
// still not found
return "unknown_local_variable";
// TODO: this is little tricky
}
private String toString(Attribute_Code code, HashSet referedLines) {
StringBuffer buf = new StringBuffer();
Attribute_Code.Opcode op;
Attribute_Code.Opcode[] ops = code.codes;
byte[][] operands;
int ti, def, low, high, jump_count, npairs;
String soffset;
Attribute_LocalVariableTable.LocalVariable[] lvts = null;
for (int i = 0; i < code.attributes_count; i++) {
if (code.attributes[i] instanceof Attribute_LocalVariableTable) {
lvts = ((Attribute_LocalVariableTable) code.attributes[i]).local_variable_table;
break;
}
}
// instructions
if (code.code_length != 0) {
for (int t = 0; t < ops.length; t++) {
op = ops[t];
operands = op.operands;
// offset
soffset = Integer.toString(op.offset);
if (referedLines.contains(soffset) == true) {
if (config.labelInSingleLine == true) {
buf.append(config.labelPrefix + soffset + " : ");
buf.append(Constants.LINE_SEPARATER);
buf.append(config.instructionPadding);
} else {
buf.append(Util.padChar(config.labelPrefix + soffset, config.labelLength, ' ') + " : ");
}
} else {
buf.append(config.instructionPadding);
}
// opcode name
buf.append(Constants.OPCODE_NAMES[0xFF & op.opcode] + " ");
switch (op.opcode) {
case Constants.TABLESWITCH:
def = Util.getNum(operands[1]) + op.offset;
low = Util.getNum(operands[2]);
high = Util.getNum(operands[3]);
jump_count = high - low + 1;
buf.append("default=" + config.labelPrefix + def + ", low=" + low + ", high=" + high + ", jump_table:");
for (int i = 0; i < jump_count; i++) {
// jump address is calculated by adding with tableswitch offset.
buf.append(config.labelPrefix + (Util.getNum(operands[i + 4]) + op.offset) + ",");
}
buf.deleteCharAt(buf.length() - 1);
break;
case Constants.LOOKUPSWITCH: {
def = Util.getNum(operands[1]) + op.offset;
npairs = Util.getNum(operands[2]);
buf.append("default=" + config.labelPrefix + def + ", npairs=" + npairs + ", jump_table:");
if (npairs != 0) {
for (int i = 0; i < npairs; i++) {
buf.append(Util.getNum(operands[i * 2 + 3]));
buf.append("->");
buf.append(config.labelPrefix + (Util.getNum(operands[i * 2 + 4]) + op.offset) + ",");
}
buf.deleteCharAt(buf.length() - 1);
}
}
break;
/*
* Two address bytes + offset from start of byte stream form the
* jump target
*/
case Constants.GOTO:
case Constants.IFEQ:
case Constants.IFGE:
case Constants.IFGT:
case Constants.IFLE:
case Constants.IFLT:
case Constants.JSR:
case Constants.IFNE:
case Constants.IFNONNULL:
case Constants.IFNULL:
case Constants.IF_ACMPEQ:
case Constants.IF_ACMPNE:
case Constants.IF_ICMPEQ:
case Constants.IF_ICMPGE:
case Constants.IF_ICMPGT:
case Constants.IF_ICMPLE:
case Constants.IF_ICMPLT:
case Constants.IF_ICMPNE:
/*
* 32-bit wide jumps
*/
case Constants.GOTO_W:
case Constants.JSR_W:
buf.append(config.labelPrefix + (Util.getSignedNum(operands[0]) + op.offset));
break;
/*
* Index byte references local variable
*/
case Constants.ALOAD:
case Constants.ASTORE:
case Constants.DLOAD:
case Constants.DSTORE:
case Constants.FLOAD:
case Constants.FSTORE:
case Constants.ILOAD:
case Constants.ISTORE:
case Constants.LLOAD:
case Constants.LSTORE:
case Constants.RET:
ti = Util.getNum(operands[0]); // the index into local variable
// table
buf.append(getLocalVariableName(ti, op.offset, lvts) + "(" + ti + ")");
break;
/*
* Remember wide byte which is used to form a 16-bit address in the
* following instruction. Relies on that the method is called again
* with the following opcode.
*/
case Constants.WIDE:
// TODO: testing
break;
/*
* Array of basic type.
*/
case Constants.NEWARRAY:
buf.append(Constants.TYPE_NAMES[Util.getNum(operands[0])]);
break;
/*
* Access object/class fields.
*/
case Constants.GETFIELD:
case Constants.GETSTATIC:
case Constants.PUTFIELD:
case Constants.PUTSTATIC:
/*
* Operands are references to classes in constant pool
*/
case Constants.NEW:
case Constants.CHECKCAST:
case Constants.INSTANCEOF:
/*
* Operands are references to methods in constant pool
*/
case Constants.INVOKESPECIAL:
case Constants.INVOKESTATIC:
case Constants.INVOKEVIRTUAL:
buf.append(toString(cpl.getConstant(Util.getNum(operands[0]))));
break;
case Constants.INVOKEINTERFACE:
buf.append(toString(cpl.getConstant(Util.getNum(operands[0]))));
buf.append(" ");
buf.append(Util.getNum(operands[1]));
break;
/*
* Operands are references to items in constant pool
*/
case Constants.LDC_W:
case Constants.LDC2_W:
case Constants.LDC:
buf.append(toString(cpl.getConstant(Util.getNum(operands[0]))));
break;
/*
* Array of references.
*/
case Constants.ANEWARRAY:
buf.append(toString(cpl.getConstant(Util.getNum(operands[0]))));
break;
/*
* Multidimensional array of references.
*/
case Constants.MULTIANEWARRAY:
buf.append(toString(cpl.getConstant(Util.getNum(operands[0]))));
buf.append(' ');
buf.append(Util.getNum(operands[1]));
break;
/*
* Increment local variable.
*/
case Constants.IINC:
ti = Util.getNum(operands[0]);
buf.append(getLocalVariableName(ti, op.offset, lvts) + "(" + ti + ") " + Util.getSignedNum(operands[1]));
break;
default:
if (operands != null) {
for (int i = 0; i < operands.length; i++) {
buf.append(Util.getNum(operands[i]) + " ");
}
}
}
if (config.showInfo == true) {
buf.append(" //");
buf.append(OpcodeHelper.getOpcodeInfo(op.opcode).operation);
}
buf.append(Constants.LINE_SEPARATER);
}
}
// Local variable table
for (int i = 0; i < code.attributes_count; i++) {
if (code.attributes[i] instanceof Attribute_LocalVariableTable
&& ((Attribute_LocalVariableTable) code.attributes[i]).local_variable_table_length != 0) {
buf.append(Constants.LINE_SEPARATER);
buf.append(toString((Attribute_LocalVariableTable) code.attributes[i], ops));
break;
}
}
// Exception table
if (code.exception_table_length != 0) {
buf.append(Constants.LINE_SEPARATER);
buf.append(Constants.LINE_SEPARATER);
buf.append("[" + Constants.ATTRIBUTE_NAME_EXCEPTION_TABLE + ":");
for (int i = 0; i < code.exception_table_length; i++) {
buf.append(Constants.LINE_SEPARATER);
buf.append("start=" + config.labelPrefix + code.exception_table[i].start_pc);
buf.append(" , ");
buf.append("end=" + config.labelPrefix + code.exception_table[i].end_pc);
buf.append(" , ");
buf.append("handler=" + config.labelPrefix + code.exception_table[i].handler_pc);
buf.append(" , ");
if (code.exception_table[i].catch_type != 0) {
buf.append("catch_type=" + toString(cpl.getConstant(code.exception_table[i].catch_type)));
} else {
buf.append("catch_type=0");
}
}
buf.append("]");
}
// Line number table
if (config.showLineNumber == true) {
for (int i = 0; i < code.attributes_count; i++) {
if (code.attributes[i] instanceof Attribute_LineNumberTable
&& ((Attribute_LineNumberTable) code.attributes[i]).line_number_table_length != 0) {
buf.append(Constants.LINE_SEPARATER);
buf.append(Constants.LINE_SEPARATER);
buf.append(toString((Attribute_LineNumberTable) code.attributes[i]));
break;
}
}
}
// max_stack
buf.append(Constants.LINE_SEPARATER);
buf.append(Constants.LINE_SEPARATER);
buf.append("[" + Constants.ATTRIBUTE_NAME_MAX_STACK + " : " + code.max_stack + "]");
// max_local
buf.append(Constants.LINE_SEPARATER);
buf.append("[" + Constants.ATTRIBUTE_NAME_MAX_LOCAL + " : " + code.max_locals + "]");
return buf.toString();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -