Pergunta

My goal is to instrument a small amount of code at the beginning of every basic block of some Java bytecode. The purpose is to record the execution path through basic blocks. Currently, I am using Javassist to instrument some code at the beginning and at the end of methods, but I've run into a wall with the Javassist API in instrumenting finer bytecode locations.

Javassist provides me with a Block[] that represents all of the basic blocks within a method. The basic blocks can report their bytecode locations, so I know where my instrumentation needs to go. Javassist's instrumentation that I wanted to use was CtMethod.insertAt(int sourceCodeLineNumber,String newSourceCode), however this uses the source code line number rather than the bytecode line number, which causes the problems illustrated in this question (I'm fairly certain there's no fix to that problem by this point).

The Question: How can I assign values to variables within a method using instrumentation when the variables themselves are from Javassist instrumentation. I'd preferably not have to use other tools, but I'm taking any help that I can get by this point.

Variables are declared like this using Javassist:

//m is a CtMethod           
try { m.addLocalVariable("someVar", ClassPool.getDefault().get("SomePackage.SomeClass")); } 
catch (NotFoundException e) { e.printStackTrace(); }

My worst case scenario is somehow extrapolate the stack variable that javassist instruments and insert the bytecode with an iterator that goes through the entire method/class, but that'd be really nasty. My method only has an integer input (the block ID) and void output, so the Java bytecode would look like this at the beginning of every basic block:

ALOAD 6 //6 is my new Javassist variable ID, however I don't think I can get Javassist to actually tell it to me
ICONST_1 //My parameters, which is an int.  I'd have to switch statement between ICONST, SIPUSH, and ALOAD depending on basic block's index size
INVOKEVIRTUAL SomePackage/SomeClass.SomeMethod(I)V
Foi útil?

Solução

The best way that I found to get the variable ID from the ConstPool table is testing the max size after inserting your variable

    try { m.addLocalVariable(mse, ClassPool.getDefault().get("org.javadynamicanalyzer.MethodStackEntry")); } 
    catch (NotFoundException e) { e.printStackTrace(); }

    int mseCSindex=m.getMethodInfo().getCodeAttribute().getMaxLocals()-1;

Next, I needed the invokevirtual index from the table. This was slightly suckier to find. The code below searches the ConstPool table for the function that I'm looking for. The function I'm searching for is in org.javadyanmicanalyzer.MethodStackEntry.setBlockID(int).

        int virtFunIndex=-1;
        boolean found=false;
        while(found==false){
            ++virtFunIndex;
            try{ 
                int id=cp.isMember("org.javadynamicanalyzer.MethodStackEntry", "setBlockIndex", virtFunIndex);
                if(id!=0){
                    found=true;
                }
            }
            catch(NullPointerException | ClassCastException e){}
        }

Finally, I needed to instrument the beginning of each Block:

        int len=new ControlFlow(m).basicBlocks().length;
        for(int i=0; i<len; ++i){
            Block thisbb=new ControlFlow(m).basicBlocks()[i]; //we have to re-evaluate the control flow every time we add new code
            CodeIterator itr=m.getMethodInfo().getCodeAttribute().iterator();

            int pos=thisbb.position();
            byte[] newCode=new byte[]{Bytecode.ALOAD, //loads the mse class
                                      mseCSindex, //my mse local variable
                                      Bytecode.ICONST_0, //the input to the virtual function
                                      Bytecode.INVOKEVIRTUAL, //execute the virtual function
                                      (byte) virtFunIndex>>8, //virtual function's address
                                      (byte) virtFunIndex && 0xFF};

            int n = itr.insertAt(pos, newCode);
        }

It's messy and has the potential to completely destroy itself, but it worked!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top