private static void Disasm(Attributes.Code codeAttr, ConstantPool pool, CountingStreamWriter writer, string[] sourceFile) { byte[] code = codeAttr.CodeBytes; int i = 0; bool lastWide = false; Attributes.LineNumberTable lnt = codeAttr.Attributes.Where(A => A is Attributes.LineNumberTable).FirstOrDefault() as Attributes.LineNumberTable; Attributes.LineNumberTable newLnt = new Attributes.LineNumberTable(); int lastLine = 0; while (i < code.Length) { if ((lnt != null) && (sourceFile != null)) { try { var lns = lnt.Table.Where(ln => ln.StartPC <= i); if (lns.Count() > 0) { int currLine = lns.Aggregate((i1, i2) => i1.StartPC > i2.StartPC ? i1 : i2).LineNumberInFile; if (lastLine != currLine) { writer.WriteLine(" ## {0}", sourceFile[currLine]); } lastLine = currLine; } } catch (Exception) { } } newLnt.Table.Add(new Attributes.LineNumberTable.LineNumber((ushort)i, (ushort)writer.CurrLine)); OpCodes op = (OpCodes)code[i]; if (!lastWide) { writer.Write(" {0,4:X} : ", i); } if (op == OpCodes.wide) { writer.Write("wide "); i++; lastWide = true; continue; } string opStr = op.ToString(); string operandStr = ""; if (opStr[0] == '_') { opStr = opStr.Substring(1); } writer.Write(opStr); ByteCode.JavaInstructionDescption descr = ByteCode.JavaInstructions[op]; int operandSize = descr.Size - 1; if (lastWide) { operandSize *= 2; lastWide = false; } switch (descr.OpType) { case ByteCode.JavaOperandType.ConstPool: ushort index = (ushort)BitConverterBE.ReadAsInt32(code, i + 1, operandSize); operandStr = pool[index].ToString(); break; case ByteCode.JavaOperandType.ConstValue: case ByteCode.JavaOperandType.LocalVar: operandStr = BitConverterBE.ReadAsInt32(code, i + 1, operandSize).ToString(); break; case ByteCode.JavaOperandType.Offset: short offset = (short)BitConverterBE.ReadAsInt32(code, i + 1, operandSize); operandStr = String.Format("{0,4:X}", (i + offset)); break; case ByteCode.JavaOperandType.Special: switch (op) { case OpCodes.iinc: int op1 = BitConverterBE.ReadAsInt32(code, i + 1, operandSize / 2); int op2 = BitConverterBE.ReadAsInt32(code, i + 1 + operandSize / 2, operandSize / 2); operandStr = String.Format("{0}, {1}", op1, op2); break; case OpCodes.lookupswitch: int paddingLength = (4 - ((i + 1) % 4)) % 4; int _default = BitConverterBE.ReadAsInt32(code, i + paddingLength + 1, 4); int npairs = BitConverterBE.ReadAsInt32(code, i + paddingLength + 5, 4); int pairsStart = i + paddingLength + 9; operandSize = npairs * 8 + 8 + paddingLength; writer.WriteLine(" default: {0,4:X}, npairs: {1}", _default, npairs); for (int pair = 0; pair < npairs; pair++) { int pairValue = BitConverterBE.ReadAsInt32(code, pairsStart + (pair * 8), 4); int pairOffset = BitConverterBE.ReadAsInt32(code, pairsStart + (pair * 8) + 4, 4); writer.WriteLine(" {0,4:X} : {1}", pairOffset, pairValue); } break; case OpCodes.tableswitch: paddingLength = (4 - ((i + 1) % 4)) % 4; _default = BitConverterBE.ReadAsInt32(code, i + paddingLength + 1, 4); int low = BitConverterBE.ReadAsInt32(code, i + paddingLength + 5, 4); int hight = BitConverterBE.ReadAsInt32(code, i + paddingLength + 9, 4); writer.WriteLine(" default: {0,4:X}, low: {1}, hight: {2}", _default, low, hight); int jmpCount = hight - low + 1; int jmpStart = i + paddingLength + 13; operandSize = jmpCount * 4 + 13 + paddingLength; for (int jmp = 0; jmp < jmpCount; jmp++) { writer.WriteLine(" {0,4:X} : {1}", BitConverterBE.ReadAsInt32(code, jmpStart + jmp * 4, 4), low + jmp); } break; case OpCodes.invokeinterface: case OpCodes.invokedynamic: index = (ushort)BitConverterBE.ReadAsInt32(code, i + 1, 2); operandStr = pool[index].ToString(); break; case OpCodes.newarray: operandStr = ArrayTypes[code[i + 1]]; break; case OpCodes.multianewarray: index = (ushort)BitConverterBE.ReadAsInt32(code, i + 1, 2); byte dismensions = code[i + 3]; operandStr = String.Format("{0}, {1}", dismensions, pool[index].ToString()); break; } ; break; } writer.WriteLine(" {0}", operandStr); i += 1 + operandSize; } if (Program.DebugBytecode) { if (lnt != null) { codeAttr.Attributes.Remove(lnt); } codeAttr.Attributes.Add(newLnt); } }
public static void Dump(Java.Class value, Stream output) { string[] sourceFile = null; CountingStreamWriter writer = new CountingStreamWriter(output); writer.WriteLine("Class file version: {0}.{1}", value.MajorVersion, value.MinorVersion); writer.WriteLine("class {0} extends {1}", value.ThisClass, value.SuperClass); writer.WriteLine("Access Flags: {0}", value.AccessFlag.ToString()); writer.WriteLine("Interfaces (count: {0}):", value.Interfaces.Count); foreach (string iface in value.Interfaces) { writer.WriteLine(" " + iface); } writer.WriteLine("Attributes (count: {0}):", value.Attributes.Count); for (int i = 0; i < value.Attributes.Count; i++) { writer.WriteLine("{0,6:G}: {1}", i, value.Attributes[i].Name); value.Attributes[i].Dump(writer, " "); if ((value.Attributes[i] is Attributes.SourceFile) && (Program.FullPathInSourceFileName)) { using (StreamReader r = new StreamReader(((Attributes.SourceFile)value.Attributes[i]).Value)) sourceFile = r.ReadAllLines(); } } writer.WriteLine("Fields (count: {0}):", value.Fields.Count); for (int i = 0; i < value.Fields.Count; i++) { writer.WriteLine("{0,6:G}: Name: {1}", i, value.Fields[i].Name); writer.WriteLine(" Descriptor: {0}", value.Fields[i].Descriptor); writer.WriteLine(" Access Flags: {0}", value.Fields[i].AccessFlags.ToString()); writer.WriteLine(" Attributes (count: {0}):", value.Fields[i].Attributes.Count); for (int j = 0; j < value.Fields[i].Attributes.Count; j++) { writer.WriteLine(" {0,6:G}: {1}", j, value.Fields[i].Attributes[j].Name); value.Fields[i].Attributes[j].Dump(writer, " "); } writer.WriteLine(); } writer.WriteLine("Methods (count: {0}):", value.Methods.Count); for (int i = 0; i < value.Methods.Count; i++) { writer.WriteLine("{0,6:G}: Name: {1}", i, value.Methods[i].Name); writer.WriteLine(" Descriptor: {0}", value.Methods[i].Descriptor); writer.WriteLine(" Access Flags: {0}", value.Methods[i].AccessFlags.ToString()); Attributes.Code code = null; writer.WriteLine(" Attributes (count: {0}):", value.Attributes.Count); for (int j = 0; j < value.Methods[i].Attributes.Count; j++) { writer.WriteLine(" {0,6:G}: {1}", j, value.Methods[i].Attributes[j].Name); value.Methods[i].Attributes[j].Dump(writer, " "); if (value.Methods[i].Attributes[j] is Attributes.Code) { code = (Attributes.Code)value.Methods[i].Attributes[j]; } } if (code != null) { writer.WriteLine(); Disasm(code, value.ConstantPool, writer, sourceFile); } ; writer.WriteLine(); } writer.Close(); }