1

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?

Victor Grazi
  • 15,563
  • 14
  • 61
  • 94

1 Answers1

1

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.

Victor Grazi
  • 15,563
  • 14
  • 61
  • 94
Luca Basso Ricci
  • 17,829
  • 2
  • 47
  • 69
  • Sounds promising, but can you elaborate, I am not seeing documentation for getting from the ClassPrepareRequest to the breakpoint. – Victor Grazi Feb 16 '16 at 16:19
  • Where does event come from? – Victor Grazi Feb 19 '16 at 03:35
  • From an EventRequestManager. A request for class preparation has the same creation pattern of any other request (like breakpoint as in your example). When class in prepared (loaded from Classloader as example) a ClassPrepareEvent is fired; intercept and create the breakpoint request – Luca Basso Ricci Feb 19 '16 at 07:39
  • 1
    Don't I need a running VM to get an EventRequestManager? – Victor Grazi Feb 21 '16 at 00:57
  • Is there any documentation explaining this stuff? I simply don't see how to fill in your missing steps? I can use my approach in the solution I offered below, and that is many fewer steps than yours, but requires a running VM (although I believe yours does too.) Would it be possible for you to fill in all of your missing steps to get me from the class name and line to setting the breakpoint, without a running VM? Sorry but the only spec or docs I am seeing is this http://docs.oracle.com/javase/7/docs/jdk/api/jpda/jdi/index.html and that is really sparse – Victor Grazi Feb 21 '16 at 01:36
  • Start from http://docs.oracle.com/javase/7/docs/jdk/api/jpda/jdi/com/sun/jdi/VirtualMachineManager.html: connect to target VM and you'll get your running VM! Using a LaunchingConnector (http://docs.oracle.com/javase/7/docs/jdk/api/jpda/jdi/com/sun/jdi/connect/LaunchingConnector.html#launch(java.util.Map) is the easy way – Luca Basso Ricci Feb 21 '16 at 15:10
  • Thanks, that got me a long way. I have filled in the event handler, just to save the next guy some of the research. Not sure if I did it the best way, it seems rather convoluted – Victor Grazi Feb 21 '16 at 22:32