I am trying to code a debugger for a school project, so I can go through the code step by step and possibly skip over some methods, so far I have tried multiple approaches with the com.sun.jdi package but nothing has worked so far, as my jdi Event queue does not include a class-prepared event so I cannot set the breakpoints automatically. Is there a way around this, I have attached my code below. Different approaches or solutions to the problem are welcome.
Thank you
This is my debugger class so far.
package JPIDebugger;
import java.util.Map;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.LaunchingConnector;
import com.sun.jdi.event.*;
import com.sun.jdi.request.BreakpointRequest;
import com.sun.jdi.request.ClassPrepareRequest;
import com.sun.jdi.*;
public class JPIDebuggerClass {
public static void main(String[] args) throws Exception {
int[] breakPointLines = {6, 9};
//VirtualMachine vm = null;
try {
// Starting the VM
LaunchingConnector launchingConnector = Bootstrap.virtualMachineManager()
.defaultConnector();
Map<String, Connector.Argument> arguments = launchingConnector.defaultArguments();
arguments.get("main").setValue("JPIDebugger.Debuggee");
VirtualMachine vm = launchingConnector.launch(arguments);
// Setting up the class prepare request
ClassPrepareRequest classPrepareRequest = vm.eventRequestManager().createClassPrepareRequest();
classPrepareRequest.addClassFilter("JPIDebugger.Debuggee");
classPrepareRequest.enable();
// The classPrepareRequest should have put a ClassPreparedEvent in the event queue
while (true) {
EventQueue eventQueue = vm.eventQueue();
EventSet eventSet = eventQueue.remove();
EventIterator eventIterator = eventSet.eventIterator();
System.out.println(eventIterator.toString() + " Event Set is received.");
while (eventIterator.hasNext()) {
Event event = eventIterator.next();
System.out.println(event.toString() + " is the event");
if (event instanceof ClassPrepareEvent) {
System.out.println("Class is prepared");
ClassType classType = (ClassType) ((ClassPrepareEvent) event).referenceType();
for (int lineNumber : breakPointLines) {
Location location = classType.locationsOfLine(lineNumber).get(0);
BreakpointRequest bpReq = vm.eventRequestManager().createBreakpointRequest(location);
bpReq.enable();
}
}
if (event instanceof BreakpointEvent) {
System.out.println("Breakpoint is hit");
LocatableEvent locatableEvent = (LocatableEvent) event;
StackFrame stackFrame = locatableEvent.thread().frame(0);
if (stackFrame.location().toString().contains("JPIDebugger.Debuggee")) {
Map<LocalVariable, Value> visibleVariables = stackFrame
.getValues(stackFrame.visibleVariables());
System.out.println("Variables at " + stackFrame.location().toString() + " > ");
for (Map.Entry<LocalVariable, Value> entry : visibleVariables.entrySet()) {
System.out.println(entry.getKey().name() + " = " + entry.getValue());
}
}
}
vm.resume();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
This is the Debuggee class, that I am trying to "Debug" and set breakpoints in.
package JPIDebugger;
public class Debuggee {
public static void main(String[] args) {
String jpda = "Java Platform Debugger Architecture";
System.out.println("Hi Everyone, Welcome to " + jpda); // add a break point here
String jdi = "Java Debug Interface"; // add a break point here and also stepping in here
String text = "Today, we'll dive into " + jdi;
System.out.println(text);
}
}
The Output I am getting is:
com.sun.tools.jdi.EventSetImpl$Itr@2957fcb0 Event Set is received.
VMStartEvent in thread main is the event
com.sun.tools.jdi.EventSetImpl$Itr@3b764bce Event Set is received.
VMDeathEvent is the event
com.sun.tools.jdi.EventSetImpl$Itr@45fe3ee3 Event Set is received.
VMDisconnectEvent is the event
com.sun.jdi.VMDisconnectedException
at jdk.jdi/com.sun.tools.jdi.EventQueueImpl.removeUnfiltered(EventQueueImpl.java:200)
at jdk.jdi/com.sun.tools.jdi.EventQueueImpl.remove(EventQueueImpl.java:97)
at jdk.jdi/com.sun.tools.jdi.EventQueueImpl.remove(EventQueueImpl.java:83)
at JPIDebugger.JPIDebuggerClass.main(JPIDebuggerClass.java:31)