Search code examples
javadebuggingbtrace

JVM process - print every method argument


We use InstallAnywhere to create installers. Recently an installer created using it started failing with StackOverFlow error (in silent installation).. Error stack has thousands of lines like below.

java.lang.StackOverflowError
at com.zerog.ia.installer.util.VariableManager.substitute(Unknown Source)
at com.zerog.ia.installer.util.VariableFacade.substitute(Unknown Source)
at com.zerog.ia.installer.util.VariableFacade.substitute(Unknown Source)
at com.zerog.ia.installer.util.magicfolders.MagicFolder.getPath(Unknown Source)
at com.zerog.ia.installer.util.magicfolders.MagicFolder.toString(Unknown Source)
at com.zerog.ia.installer.util.VariableManager.getValueOfVariable(Unknown Source)
at com.zerog.ia.installer.util.IAVariableStringResolver.getValueOfVariable(Unknown Source)
at com.zerog.ia.installer.util.VariableManager.substitute(Unknown Source)

VariableManager.substitute is very common API, it takes a string argument and return substituted(evaluted) value. How can I see the argument passed to it in the real JVM process?


Solution

  • The solution was to use a btrace script.

    The installer process is Java process that can be queried by JVM tools like (jps, jstack)

    1. Install JDK (JVisualVM comes with it)
    2. Start VisualVM and Install btrace plugin

    enter image description here

    1. Right click on process (LAX) Start 'btrace'

    enter image description here

    Copy following btrace script to btrace console

    package com.sun.btrace.samples;
    
    import com.sun.btrace.BTraceUtils;
    import com.sun.btrace.Profiler;
    import com.sun.btrace.annotations.*;
    import com.sun.btrace.*;
    
    @BTrace class Profiling {
    @Property
    Profiler swingProfiler = BTraceUtils.Profiling.newProfiler();
    
    @OnMethod(
        clazz="com.zerog.ia.installer.util.VariableFacade", 
        method="/.*substitute.*/")
        void entry( String probeMethod) {
            BTraceUtils.print("Entry" );
            BTraceUtils.println(BTraceUtils.timestamp() );
            BTraceUtils.println(probeMethod);
        }
    
    @OnMethod(
        clazz="com.zerog.ia.installer.*", 
        method="/.*/")
        void entry2( @ProbeMethodName(fqn=true) String probeMethod ) {
            BTraceUtils.print("Entry" );
            BTraceUtils.println(BTraceUtils.timestamp() );
            BTraceUtils.println(probeMethod);
        }
    
    @OnMethod(clazz = "com.zerog.ia.installer.*", method = "/.*/", location = @Location(Kind.RETURN))
         void onPrepareReturn(AnyType arg) {
            if (arg != null) {
                 BTraceUtils.println(arg);
            }
        }
    
    }
    

    Start btrace by clicking "start" icon. enter image description here

    Watch output for logs.

    Btrace is extremely powerful tool to quickly check inside the JVM. Checkout more at Btrace Kenai project

    Edit-comment from @J.B Btrace is now at github