Question

I am trying to analyse byte code with javassist using simple class MyData:

class MyData {
    private Collection<String> strings = new ArrayList<String>();

        // .....................    
    public void add(String str) {
        strings.add(str); // line number 35
    }
        // .....................    
}

Here is the code I am running against this class:

ClassFile cf = new ClassFile(new DataInputStream(TryJavassist.class.getResourceAsStream("MyData.class")));
MethodInfo minfo = cf.getMethod("add");  
CodeAttribute ca = minfo.getCodeAttribute();
for (CodeIterator ci = ca.iterator(); ci.hasNext();) {
    int index = ci.next();
    int op = ci.byteAt(index);

    System.out.println(op + "=" + Mnemonic.OPCODE[op] + ": " + minfo.getLineNumber(index));
}

It works and prints:

42=aload_0: 35
180=getfield: 35
43=aload_1: 35
185=invokeinterface: 35
87=pop: 35
177=return: 36

Line 35 invokes method add() of collection named strings. The code snippet I posted retrieves only invokeinterface and line 35. OK, I can know that it was class field (getfield).

I would like to know how to get the rest of information:

  • the field name is strings
  • the interface method being called is add()

Neither googling nor reading API doc have not given any positive result so far.

Was it helpful?

Solution

It is hard work, needing an understanding of the JVM class format and instruction set. Any answer can only give partial data. Especially with Javassist. In the instruction typically one parameter is an index in the constant pool, where there is an object with an index to a name, and an index to a type. So be aware of what you are getting into.

If the class is compiled with debugging info, the private field names are accessible (ClassFile.getFields).

There is a nice Dump tool packed with javassist.

private void dumpMyDataClass() throws IOException, BadBytecode, Exception {
    ClassFile cf = new ClassFile(new DataInputStream(getClass().getResourceAsStream("MyData.class")));

    // Dump fields:
    for (Object fieldInfoObj : cf.getFields()) {
        FieldInfo fieldInfo = (FieldInfo) fieldInfoObj;
        System.out.printf("Field %s; %s%n", fieldInfo.getName(), fieldInfo.getDescriptor());
    }

    MethodInfo minfo = cf.getMethod("add");
    CodeAttribute ca = minfo.getCodeAttribute();
    for (CodeIterator ci = ca.iterator(); ci.hasNext();) {
        int address = ci.next();
        int op = ci.byteAt(address);

        String params = "";
        switch (op) {
            case Opcode.INVOKEINTERFACE:
                int a1 = ci.s16bitAt(address + 1);
                params += " " + cf.getConstPool().getInterfaceMethodrefName(a1);
                System.out.println("a1 = " + a1);
                break;
        }

        System.out.printf("Line %4d. Address %7d: %s%s%n", minfo.getLineNumber(address), address, Mnemonic.OPCODE[op], params);
    }

    // Command line tool of javassist:
    String pathToClass = System.getProperty("user.dir") + "/target/classes/jeggen/test2/MyData.class";
    Dump.main(new String[] { pathToClass });
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top