jdi

How do you set a breakpoint before executing


I would like to set a breakpoint in an application before it starts to run, so that I can make sure the application does not pass the breakpoint on startup.

In order to set a breakpoint you need to do something like:

EventRequestManager reqMan = vm.eventRequestManager();
BreakpointRequest bpReq = reqMan.createBreakpointRequest(locationForBreakpoint);
bpReq.enable();

In order to get the Location for the breakpoint, you can do something like:

Method method = location.method();
List<Location> locations = method.locationsOfLine(55);
Location locationForBreakpoint = locations.get(0);

In order to get a Method you can do something like:

classType.concreteMethodByName(methodNname, String signature)

However in order to get that classType you seem to require an ObjectReference which seems to require a running JVM.

Is there any way to set the breakpoint before the application JVM runs, to be sure the breakpoint is not passed during application startup?


Solution

  • First of all start you target program using a LaunchingConnector to get back the target virtual machine.

    VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
    LaunchingConnector lc = vmm.launchingConnectors().get(0);
    // Equivalently, can call:
    // LaunchingConnector lc = vmm.defaultConnector();
    
    Map<String, Connector.Argument> env = lc.defaultArguments();
    env.get("main").setValue("p.DebugDummy");
    env.get("suspend").setValue("true");
    env.get("home").setValue("C:/Program Files/Java/jdk1.7.0_51");
    VirtualMachine vm = lc.launch(env);
    

    (change environment values according to your needs,but remember to start target VM with suspended=true).
    With this VM in you hand intercept a ClassPrepareEvent using a ClassPrepareRequest.

    ClassPrepareRequest r = reqMan.createClassPrepareRequest();
    r.addClassFilter("myclasses.SampleClass");
    r.enable();
    

    Create a ClassPrepareEvent handler

     executor.execute(()->    {
        try {
          while(true)
          {
              EventQueue eventQueue = vm.eventQueue();
              EventSet eventSet = eventQueue.remove();
              EventIterator eventIterator = eventSet.eventIterator();
              if (eventIterator.hasNext()) {
                Event event = eventIterator.next();
                if(event instanceof ClassPrepareEvent) {
                  ClassPrepareEvent evt = (ClassPrepareEvent) event;
                  ClassType classType = (ClassType) evt.referenceType();
                  List<Location> locations = referenceType.locationsOfLine(55);
                  Location locationForBreakpoint = locations.get(0);
    
                  vm.resume();
                }
              }
            }
        } catch (InterruptedException | AbsentInformationException | IncompatibleThreadStateException e) {
          e.printStackTrace();
        }
      }
    

    then resume target VM with a call to vm.resume() to run program. I hope this solve your problem.