2

I am currently trying to track method calls for learning purposes.

The javagent I have implemented is a modified version of the implementation in this article. The programm adds to any method call logging instructions into the bytecode. Unfortunately bootstrap classloader refuses to load any manipulated content from rt.jar. I can understand that this isn't a good idea for a production enviroment, but for a student it would be really amazing.

Do you got any ideas how to make this happen?

Siguza
  • 15,723
  • 6
  • 44
  • 66

2 Answers2

0

The only chance you have is to change the contents of rt.jar. The bootstrap class loader is special in many ways, many, but not all, of the classes are loaded before the agent even starts up.

Some classes can be explicitly redefined using the redefine method. This is however not possible for all bootstrap classes.

Rafael Winterhalter
  • 38,221
  • 13
  • 94
  • 174
  • Thanks for you answer! Would it be possible to define a custom Classloader below the system and bootstrap classloader, that will load a modified version and delegates only when he doesn't find the class? Would be again really dirty... -> Agent.transform(): checks whether call comes from Boostrtrap -> CustomClassloader calls Transformer loads modified ByteCode – hotzenplotz Jun 19 '15 at 13:58
  • No, the JVM makes sure that you never define custom classes in the `java.*` namespace. Such classes must be loaded by the bootstrap class loader. – Rafael Winterhalter Jun 19 '15 at 14:04
  • I'm don't think that this is correct. You can redefine java.* classes. See http://stackoverflow.com/questions/29059553/javac-classpath-order-contradicts-oracle-documentation/29060452#29060452 and others. – Marco13 Jun 20 '15 at 01:15
  • You cannot redefine all classes, some are possible. – Rafael Winterhalter Jun 20 '15 at 08:03
0

I could successfully manipulate classes from the rt.jar.

For example I manipulated the bytecode of the BigDecimal class. Which class are you training to manipulate? And what kind of manipulation are you doing? Just adding logs to every method of the class like in the article that you mentioned?

In additional of following the instructions of article, I had to do some other things in order to be able manipulate the classes of rt.jar.

  1. In the LoggerAgent class I added an array of classes that I explicitly want to manipulate.

    String[] includeArr = new String[] { "java/math/BigDecimal" };
    ArrayList<String> include = new ArrayList(Arrays.asList(includeArr));
    
  2. In the transform method of the LoggerAgent class I modified the loop to include the classes I explicitly want to manipulate.

    for (int i = 0; i < ignore.length; i++) {
        if (className.startsWith(ignore[i]) && !include.contains(className)) {        
            return bytes;
        }
    }
    
  3. Fixed the method methodReturnsValue of JavassistHelper to correctly distinguish between methods and constructors.

    private static boolean methodReturnsValue(CtBehavior method)throws NotFoundException {
    
        if (method instanceof CtMethod){
            CtClass returnType = ((CtMethod) method).getReturnType();
            String returnTypeName = returnType.getName();
            if(returnTypeName.equals("void")){
                return false;
            }else{
                return true;
            }    
        } else{
            return false;
        }
    }
    
  4. Last, in the HelloWorld class I created a BigDecimal just to check the manipulation behavior.

The output looks like as follow:

19/06/2015 16:00:26 java.math.BigDecimal signum
INFO: << signum() returns: 1
19/06/2015 16:00:26 java.math.BigDecimal layoutChars
INFO: << layoutChars(1=true) returns: 11.1099999999999994315658113919198513031005859375
19/06/2015 16:00:26 java.math.BigDecimal toString
INFO: << toString() returns: 11.1099999999999994315658113919198513031005859375
19/06/2015 16:00:26 com.runjva.demo.HelloWorld main
INFO: << main(args=[])
BigDecimal=11.1099999999999994315658113919198513031005859375
Stop at Fri Jun 19 16:00:26 PDT 2015

I hope it helps. If not, please add more details of what you are trying to do.

Rodrigo V
  • 81
  • 1
  • 6
  • Thanks for your answer! I fixed the constructor thing in LoggerAgent.doMethod(). I tried to enable logging everything, that is maybe the wrong approach ;) I will try it with your way now :) I am interested in the Collection Framework and everything related to Streams & Lambdas. Do you know how classes with native code getting translated or execeuted by the JVM? Trying to instrument hashmap for example produced some strange errors by the JVM. (some .cpp exception classes were mentioned) – hotzenplotz Jun 20 '15 at 17:27