HelloWorld.java
package com.my.jdi;
public class HelloWorld {
public static void main(String[] args) throws Exception {
int i = 0;
while(true) {
System.out.println(++i);
Thread.sleep(5000);
}
}
}
SimpleDebugger.java
package com.my.jdi;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sun.jdi.Bootstrap;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.Location;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.StackFrame;
import com.sun.jdi.StringReference;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.Value;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.VirtualMachineManager;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.jdi.connect.LaunchingConnector;
import com.sun.jdi.connect.VMStartException;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.EventIterator;
import com.sun.jdi.event.EventQueue;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.event.VMDeathEvent;
import com.sun.jdi.event.VMDisconnectEvent;
import com.sun.jdi.event.VMStartEvent;
import com.sun.jdi.request.BreakpointRequest;
import com.sun.jdi.request.ClassPrepareRequest;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;
/**
* For javadoc of JDI, please see:
* @see http://docs.oracle.com/javase/8/docs/jdk/api/jpda/jdi/index.html
* @see https://www.ibm.com/developerworks/cn/java/j-lo-jpda4/index.html
*/
public class SimpleDebugger {
private static final int BREAK_POINT_LINE = 6;
private static final String DEBUG_CLASS = "com.my.jdi.HelloWorld";
private static EventRequestManager eventRequestManager = null;
private static EventSet eventSet = null;
private static boolean vmExit = false;
public static void main(String[] args) throws Exception {
VirtualMachine targetVM = launchVM();
// Get process which run target VM
Process process = targetVM.process();
registerVMEvent(targetVM);
//classPrepareRequest.setEnabled(true);
// Enter event loop
eventLoop(targetVM);
process.destroy();
}
/**
* Register ClassPrepareRequest
*/
private static void registerVMEvent(VirtualMachine targetVM) {
eventRequestManager = targetVM.eventRequestManager();
ClassPrepareRequest classPrepareRequest = eventRequestManager.createClassPrepareRequest();
classPrepareRequest.addClassFilter(DEBUG_CLASS);
classPrepareRequest.addCountFilter(1);
classPrepareRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
// Event created by eventRequestManager is non-active, need to call enable method
classPrepareRequest.enable();
}
private static void eventLoop(VirtualMachine targetVM) throws Exception {
// EventQueue manages event from debugger for target VM
EventQueue eventQueue = targetVM.eventQueue();
while (!vmExit) {
// Waits until the next available event comes.
eventSet = eventQueue.remove();
EventIterator eventIterator = eventSet.eventIterator();
while (eventIterator.hasNext()) {
Event event = (Event) eventIterator.next();
execute(event);
}
}
}
private static void execute(Event event) throws Exception {
if (event instanceof VMDisconnectEvent) {
System.out.println("VM disconnect");
vmExit = true;
} else {
if (event instanceof VMStartEvent) {
System.out.println("VM started");
} else if (event instanceof VMDeathEvent) {
System.out.println("VM death");
} else if (event instanceof ClassPrepareEvent) {
ClassPrepareEvent classPrepareEvent = (ClassPrepareEvent) event;
String className = classPrepareEvent.referenceType().name();
if (DEBUG_CLASS.equals(className)) {
System.out.println("Class " + DEBUG_CLASS + " is already prepared");
}
if (true) {
// Get location
ReferenceType referenceType = classPrepareEvent.referenceType();
List<Location> locations = referenceType.locationsOfLine(BREAK_POINT_LINE);
Location location = locations.get(0);
// Create BreakpointEvent
BreakpointRequest breakpointRequest = eventRequestManager.createBreakpointRequest(location);
breakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
breakpointRequest.enable();
}
} else if (event instanceof BreakpointEvent) {
System.out.println("Reach line 10 of " + DEBUG_CLASS);
BreakpointEvent breakpointEvent = (BreakpointEvent) event;
ThreadReference threadReference = breakpointEvent.thread();
StackFrame stackFrame = threadReference.frame(0);
LocalVariable localVariable = stackFrame.visibleVariableByName("str");
Value value = stackFrame.getValue(localVariable);
String str = ((StringReference) value).value();
System.out.println("The local variable str at line 10 is " + str + " of " + value.type().name());
}
// Unless resume is being handled in another way, each EventSet should invoke EventSet.resume().
eventSet.resume();
}
}
/**
* Launch the target VM.
*/
private static VirtualMachine launchVM() {
VirtualMachineManager vmManager = Bootstrap.virtualMachineManager();
// Get all launch connectors
List<LaunchingConnector> list = vmManager.launchingConnectors();
for (LaunchingConnector conn: list) {
System.out.println("LaunchingConnector: " + conn.name());
}
// Get arguments of the default launching connector
LaunchingConnector launchingConnector = vmManager.defaultConnector();
Map<String, Connector.Argument> env = launchingConnector.defaultArguments();
env.get("main").setValue(DEBUG_CLASS);// Set class of main method
env.get("suspend").setValue("true");
Set<String> keySet = env.keySet();
for (String key: keySet) {
System.out.println("Argument: " + env.get(key));
}
// Launch target VM
try {
VirtualMachine vm = launchingConnector.launch(env);
if (vm == null) {
System.out.println("Launch failed, vm is null");
throw new Error("Launch VM failed!");
} else {
System.out.println("Launch success!");
return vm;
}
} catch (IOException exc) {
throw new Error("Unable to launch target VM: " + exc);
} catch (IllegalConnectorArgumentsException exc) {
throw new Error("Illegal connector argument to launch target VM: " + exc);
} catch (VMStartException exc) {
throw new Error("Target VM failed to initialize: " + exc.getMessage());
}
}
}