package org.zoodb.internal.util; import java.nio.ByteBuffer; import java.util.Arrays; public class ClassDebugger { private static final byte[] BA = { -54, -2, -70, -66, // 0-3: magic number 0, 0, //4-5: minor version 0, 50, //6-7: major version 0, 16, //8-9: constant pools size+1 7, 0, 2, 1, 0, 11, 98, 99, 101, 47, 77, 121, 67, 108, 97, 115, 115, 7, 0, 4, 1, 0, 25, 98, 99, 101, 47, 80, 101, 114, 115, 105, 115, 116, 101, 110, 116, 67, 97, 112, 97, 98, 108, 101, 73, 109, 112, 108, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 10, 0, 3, 0, 9, 12, 0, 5, 0, 6, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 18, 76, 111, 99, 97, 108, 86, 97, 114, 105, 97, 98, 108, 101, 84, 97, 98, 108, 101, 1, 0, 4, 116, 104, 105, 115, 1, 0, 13, 76, 98, 99, 101, 47, 77, 121, 67, 108, 97, 115, 115, 59, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 12, 77, 121, 67, 108, 97, 115, 115, 46, 106, 97, 118, 97, 0, 33, 0, 1, 0, 3, 0, 0, 0, 0, 0, 1, 0, 1, 0, 5, 0, 6, 0, 1, 0, 7, 0, 0, 0, 47, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 8, -79, 0, 0, 0, 2, 0, 10, 0, 0, 0, 6, 0, 1, 0, 0, 0, 3, 0, 11, 0, 0, 0, 12, 0, 1, 0, 0, 0, 5, 0, 12, 0, 13, 0, 0, 0, 1, 0, 14, 0, 0, 0, 2, 0, 15 }; public enum CP { CONSTANT_0, CONSTANT_Utf8, // 1 Laenge des unterminierten Strings in Anzahl Byte (2 bytes) //String in Utf8-Darstellung (variable Laenge) CONSTANT_Unicode, // 2 Laenge nachfolgenden Zeichenkette in Anzahl Byte (2 bytes) //Unicode-Zeichenkette (variable Laenge) CONSTANT_Integer, // 3 Vorzeichenbehafteter Integer-Wert, big-endian (4 bytes) CONSTANT_Float, // 4 Float-Wert nach IEEE 754 (4 bytes) CONSTANT_Long, // 5 Vorzeichenbehafteter Integer-Wert, big-endian (8 bytes) CONSTANT_Double, // 6 Double-Wert nach IEEE 754 (8 bytes) CONSTANT_Class, // 7 Index zu einem weiteren Konstantpool-Eintrag vom Typ CONSTANT_Utf8, der //den Klassennamen beinhaltet (2 bytes) CONSTANT_String, // 8 Index zu einem weiteren Konstantpool-Eintrag vom Typ CONSTANT_Utf8, der //den String beinhaltet (2 bytes) CONSTANT_Fieldref, // 9 Index zu einem CONSTANT_Class Eintrag, der die Klasse bezeichnet, die das //Feld enthaelt (2 bytes) plus ein Index zu einem CONSTANT_NameAndType Eintrag, //der die Signatur des Feldes angibt (2 bytes) CONSTANT_Methodref, // A Index zu einem CONSTANT_Class Eintrag, der die Klasse bezeichnet, welche die //Methode enthaelt (2 bytes) plus ein Index zu einem CONSTANT_NameAndType //Eintrag, der die Signatur der Methode angibt (2 bytes) CONSTANT_InterfaceMethodref, // B Index zu einem CONSTANT_Class Eintrag, der das Interface bezeichnet, welches //die jeweilige Methode deklariert (2 bytes) plus ein Index zu einem //CONSTANT_NameAndType Eintrag, der die Signatur des Interfaces angibt (2 //bytes) CONSTANT_NameAndType, // C Index zu einem CONSTANT_Utf8 Eintrag, der den Namen des Feldes oder der //Methode enthaelt (2 bytes) plus ein weiteren Index zu einem CONSTANT_Utf8 //Eintrag, der die Signatur des Feldes oder der Methode angibt (2 bytes) } private static final int ACC_PUBLIC = 0x0001;// Kann ausserhalb des Package verwendet werden. private static final int ACC_PRIVATE = 0x0002; // Kann nur von innerhalb der Klasse zugegriffen werden. private static final int ACC_PROTECTED = 0x0004; // Kann von innerhalb der Klasse und von abgeleiteten Klassen // zugegriffen werden. private static final int ACC_STATIC = 0x0008; // Als static deklariert (Klassenvariable). private static final int ACC_FINAL = 0x0010; // Kann nicht abgeleitet werden. private static final int ACC_SUPER = 0x0020; // Behandelt Methodenaufrufe der Superklasse speziell. Dieses // Flag dient zur Rueckwaertskompatibilitaet und wird von neueren // Compilern immer gesetzt. private static final int ACC_VOLATILE = 0x0040; // Kann nicht ge-cached werden. private static final int ACC_TRANSIENT = 0x0080; // Feld als transient deklariert. private static final int ACC_NATIVE = 0x0100; // In einer anderen Sprache (als Java) implementiert. private static final int ACC_INTERFACE = 0x0200; // Dieses Flag ist gesetzt, wenn es sich um ein Interface und // nicht um eine Klasse handelt. private static final int ACC_ABSTRACT = 0x0400; // Kann nicht instanziert werden. private static final int ACC_STRICT = 0x0800; // Als strictfp deklariert. private static FormattedStringBuilder sb = new FormattedStringBuilder(); public static boolean VERBOSE = true; public static void main(String[] args) { run(BA); byte[] ba2 = ClassBuilderSimple.build("MySubClass", "MySuperClass"); run(ba2); } private static void run(byte[] ba) { ByteBuffer bb = ByteBuffer.wrap(ba); logHex("Magic:", bb.get(), bb.get(), bb.get(), bb.get()); log("Version:", bb.getShort(), bb.getShort()); int poolSize = bb.getShort(); log("Pool size:", poolSize); for (int i = 1; i < poolSize; i++) { int tag = bb.get(); CP cp = CP.values()[tag]; log("entry=" + i + ":", Integer.toString(tag), cp.name()); switch(cp) { case CONSTANT_Utf8: { int len = bb.getShort(); sb.fill(20); for (int c = 0; c < len; c++) { sb.append((char)bb.get()); } sb.appendln(); break; } case CONSTANT_Class: { int id = bb.getShort(); log(" ID=", id); break; } case CONSTANT_Methodref: { int idClass = bb.getShort(); int idType = bb.getShort(); log(" classID=", idClass + " typeNameID=" + idType); break; } case CONSTANT_NameAndType: { int idName = bb.getShort(); int idType = bb.getShort(); log(" nameID=", idName + " typeID=" + idType); break; } default: throw new UnsupportedOperationException(cp.name()); } } sb.appendln("p=" + bb.position()); sb.appendln(); sb.appendln("Class descriptor"); sb.appendln("================"); int classMods = bb.getShort(); sb.append("Modifiers:").fill(20); getModifiers(classMods, true); sb.appendln(); sb.append("Name:").fill(20); int thisID = bb.getShort(); sb.appendln("ID=" + thisID); int superID = bb.getShort(); sb.append("Super-class").fill(20); sb.appendln("ID=" + superID); int nInter = bb.getShort(); sb.append("Interfaces").fill(20); sb.appendln("n=" + nInter); sb.appendln(); sb.appendln("Fields"); sb.appendln("================"); int nFields = bb.getShort(); sb.append("Fields").fill(20); sb.appendln("n=" + nFields); sb.appendln(); sb.appendln("Methods"); sb.appendln("================"); int nMethods = bb.getShort(); sb.append("Methods").fill(20); sb.appendln("n=" + nMethods); for (int c = 0; c < nMethods; c++) { int mods = bb.getShort(); sb.append("Method").fill(20); getModifiers(mods, false); int nameID = bb.getShort(); sb.append("nameID=" + nameID); int signID = bb.getShort(); sb.append(" signatureID=" + signID); sb.appendln(); sb.fill(20); int nAttr = bb.getShort(); sb.append("attributes=" + nAttr); sb.appendln(); for (int a = 0; a < nAttr; a++) { int attrID = bb.getShort(); int attrLen = bb.getInt(); byte[] mba = new byte[attrLen]; bb.get(mba); sb.fill(20); sb.append("ID=" + attrID); sb.append(" len=" + attrLen); sb.append(" code=" + Arrays.toString(mba)); sb.appendln(); } } sb.appendln(); sb.appendln("Class attributes"); sb.appendln("================"); int nClassAttr = bb.getShort(); sb.append("Attributes").fill(20); sb.appendln("n=" + nClassAttr); for (int a = 0; a < nClassAttr; a++) { int attrID = bb.getShort(); int attrLen = bb.getInt(); byte[] mba = new byte[attrLen]; bb.get(mba); sb.fill(20); sb.append("ID=" + attrID); sb.append(" len=" + attrLen); sb.append(" code=" + Arrays.toString(mba)); sb.appendln(); } // int classMods = bb.getShort(); // sb.append("Modifiers:").fill(20); // if ((classMods & ACC_PUBLIC) != 0) sb.append("public "); // if ((classMods & ACC_FINAL) != 0) sb.append("final "); // if ((classMods & ACC_SUPER) != 0) sb.append("super "); // if ((classMods & ACC_ABSTRACT) != 0) sb.append("abstract "); // if ((classMods & ACC_INTERFACE) != 0) sb.append("interface "); // else sb.append("class "); // sb.appendln(); // sb.append("Name:").fill(20); // int thisID = bb.getShort(); // sb.appendln("ID=" + thisID); // int superID = bb.getShort(); // sb.append("Super-class").fill(20); // sb.appendln("ID=" + superID); // int nInter = bb.getShort(); // sb.append("Interfaces").fill(20); // sb.appendln("n=" + nInter); sb.appendln("p=" + bb.position() + "/" + ba.length); if (VERBOSE) { System.out.println(sb); } } private static void getModifiers(int mods, boolean isClass) { if ((mods & ACC_PUBLIC) != 0) sb.append("public "); if ((mods & ACC_PRIVATE) != 0) sb.append("private "); if ((mods & ACC_PROTECTED) != 0) sb.append("protected "); if ((mods & ACC_STATIC) != 0) sb.append("static "); if ((mods & ACC_FINAL) != 0) sb.append("final "); if (isClass) { if ((mods & ACC_SUPER) != 0) sb.append("super "); } else { if ((mods & ACC_SUPER) != 0) sb.append("synchronized "); } if ((mods & ACC_ABSTRACT) != 0) sb.append("abstract "); if (isClass) { if ((mods & ACC_INTERFACE) != 0) sb.append("interface "); else sb.append("class "); } } private static void logHex(String string, byte ... bytes) { sb.append(string).fill(20); for (byte b: bytes) { sb.append(toHex(b)); sb.append(" "); } sb.appendln(); } private static void log(String string, int ... values) { sb.append(string).fill(20); for (int v: values) { sb.append(v); sb.append(" "); } sb.appendln(); } private static void log(String string, String ... values) { sb.append(string).fill(20); for (String v: values) { sb.append(v); sb.append(" "); } sb.appendln(); } private static String toHex(byte b) { String s = Integer.toHexString(b); return s.substring(6); } }