Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inject a function into a Java .class file using Haskell

I have written a Java bytecode parser using Haskell, and it works just fine. However the next step has me completely stumped.

My Haskell program needs to modify the .class file so that, when executed, the Java program prints:

"Entering [method name here]" before executing a method, and

"Exiting [method name here]" after executing a method.

All I know is that we will need to append the constant pool and method table with calls to System.out.println, but I feel I'm still missing something.

  • What is the best way to approach this problem?
  • How do you know how to call System.out.println in bytecode?
  • How do you store the string with the name of the method, to later be called as an argument of System.out.println?
like image 966
SamTheSammich Avatar asked Apr 20 '12 20:04

SamTheSammich


2 Answers

Well, this is what the various byte code engineering libraries give you. ASM, BCEL, etc. The specifics of your homework is an aspect, and AspectJ does precisely that.

Sounds like the homework is to write a Haskell byte code engineering exercise, so you will need to mod the class file yourself. Suggestion above by @biziclop is correct. Do a before and after on a class file, note the delta, and do the same yourself from Haskell.

[ps: of course, the above "short-cut" :P is if you don't feel like reading the JVM Spec (as noted in comment to your q) and figuring out how to do it as if you would if writing a Java compiler. You basically call a method by using one of the various byte codes for invoke -- here an interface method call --before which you need to have the receiver e.g. static field out of class System and the method name on the stack. Details in the spec.]

like image 108
alphazero Avatar answered Sep 23 '22 03:09

alphazero


Probably the easiest approach is to write a Java class that has a single method with a System.out.println() code in it, compile it with javac and observe the results.

Once you are familiar with it, proceed step by step.

  1. Add a System.out.println() call somewhere in the java file that you want to instrument. This takes care of the constant pool. Write the Haskell code that finds the relevant constants and injects the bytecode.
  2. Remove the "crutch" call from the java file and implement the constant pool manipulation in Haskell.
like image 36
biziclop Avatar answered Sep 23 '22 03:09

biziclop