Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.commons.lang3.StringUtils;

import com.sun.jdi.Location;
import com.sun.jdi.Method;
import com.sun.jdi.ObjectCollectedException;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.VMDisconnectedException;
Expand All @@ -35,8 +36,11 @@
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.jdi.connect.LaunchingConnector;
import com.sun.jdi.connect.VMStartException;
import com.sun.jdi.event.MethodEntryEvent;
import com.sun.jdi.event.StepEvent;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;
import com.sun.jdi.request.MethodEntryRequest;
import com.sun.jdi.request.StepRequest;

public class DebugUtility {
Expand Down Expand Up @@ -240,7 +244,7 @@ private static CompletableFuture<Location> step(ThreadReference thread, IEventHu
.subscribe(debugEvent -> {
StepEvent event = (StepEvent) debugEvent.event;
future.complete(event.location());
thread.virtualMachine().eventRequestManager().deleteEventRequest(request);
deleteEventRequestSafely(thread.virtualMachine().eventRequestManager(), request);
});
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
request.addCountFilter(1);
Expand All @@ -251,6 +255,40 @@ private static CompletableFuture<Location> step(ThreadReference thread, IEventHu
return future;
}

/**
* Suspend the main thread when the program enters the main method of the specified main class.
* @param debugSession
* the debug session.
* @param mainClass
* the fully qualified name of the main class.
* @return
* a {@link CompletableFuture} that contains the suspended main thread id.
*/
public static CompletableFuture<Long> stopOnEntry(IDebugSession debugSession, String mainClass) {
CompletableFuture<Long> future = new CompletableFuture<>();

EventRequestManager manager = debugSession.getVM().eventRequestManager();
MethodEntryRequest request = manager.createMethodEntryRequest();
request.addClassFilter(mainClass);
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);

debugSession.getEventHub().events().filter(debugEvent -> {
return debugEvent.event instanceof MethodEntryEvent && request.equals(debugEvent.event.request());
}).subscribe(debugEvent -> {
Method method = ((MethodEntryEvent) debugEvent.event).method();
if (method.isPublic() && method.isStatic() && method.name().equals("main")
&& method.signature().equals("([Ljava/lang/String;)V")) {
deleteEventRequestSafely(debugSession.getVM().eventRequestManager(), request);
debugEvent.shouldResume = false;
ThreadReference bpThread = ((MethodEntryEvent) debugEvent.event).thread();
future.complete(bpThread.uniqueID());
}
});
request.enable();

return future;
}

/**
* Get the ThreadReference instance by the thread id.
* @param debugSession
Expand Down Expand Up @@ -312,6 +350,36 @@ public static void resumeThread(ThreadReference thread) {
}
}

/**
* Remove the event request from the vm. If the vm has terminated, do nothing.
* @param eventManager
* The event request manager.
* @param request
* The target event request.
*/
public static void deleteEventRequestSafely(EventRequestManager eventManager, EventRequest request) {
try {
eventManager.deleteEventRequest(request);
} catch (VMDisconnectedException ex) {
// ignore.
}
}

/**
* Remove the event request list from the vm. If the vm has terminated, do nothing.
* @param eventManager
* The event request manager.
* @param requests
* The target event request list.
*/
public static void deleteEventRequestSafely(EventRequestManager eventManager, List<EventRequest> requests) {
try {
eventManager.deleteEventRequests(requests);
} catch (VMDisconnectedException ex) {
// ignore.
}
}

/**
* Encode an string array to a string as the follows.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.concurrent.CompletableFuture;

import com.microsoft.java.debug.core.DebugEvent;
import com.microsoft.java.debug.core.DebugUtility;
import com.microsoft.java.debug.core.IDebugSession;
import com.microsoft.java.debug.core.UsageDataSession;
import com.microsoft.java.debug.core.adapter.AdapterUtils;
Expand All @@ -26,21 +27,16 @@
import com.microsoft.java.debug.core.protocol.Messages.Response;
import com.microsoft.java.debug.core.protocol.Requests.Arguments;
import com.microsoft.java.debug.core.protocol.Requests.Command;
import com.sun.jdi.Method;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.ExceptionEvent;
import com.sun.jdi.event.MethodEntryEvent;
import com.sun.jdi.event.StepEvent;
import com.sun.jdi.event.ThreadDeathEvent;
import com.sun.jdi.event.ThreadStartEvent;
import com.sun.jdi.event.VMDeathEvent;
import com.sun.jdi.event.VMDisconnectEvent;
import com.sun.jdi.event.VMStartEvent;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;
import com.sun.jdi.request.MethodEntryRequest;

public class ConfigurationDoneRequestHandler implements IDebugRequestHandler {

Expand Down Expand Up @@ -69,24 +65,11 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession, IDebugAdapterContext context) {
Event event = debugEvent.event;
boolean isImportantEvent = true;
MethodEntryRequest request = null;
if (event instanceof VMStartEvent) {
if (context.isVmStopOnEntry()) {
EventRequestManager manager = debugSession.getVM().eventRequestManager();
request = manager.createMethodEntryRequest();
request.addClassFilter(context.getMainClass());
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
request.enable();
}
} else if (event instanceof MethodEntryEvent) {
Method method = ((MethodEntryEvent) event).method();
if (method.name().equals("main") && method.isStatic() && method.isPublic() && method.signature().equals("([Ljava/lang/String;)V")) {
ThreadReference bpThread = ((MethodEntryEvent) event).thread();
context.sendEvent(new Events.StoppedEvent("entry", bpThread.uniqueID()));
debugEvent.shouldResume = false;
if (request != null) {
request.disable();
}
DebugUtility.stopOnEntry(debugSession, context.getMainClass()).thenAccept(threadId -> {
context.sendEvent(new Events.StoppedEvent("entry", threadId));
});
}
} else if (event instanceof VMDeathEvent) {
context.setVmTerminated();
Expand Down