Skip to content
Open
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 @@ -41,6 +41,7 @@ public class Breakpoint implements IBreakpoint {
private int hitCount = 0;
private String condition = null;
private String logMessage = null;
private int suspendPolicy = BreakpointRequest.SUSPEND_EVENT_THREAD;
private HashMap<Object, Object> propertyMap = new HashMap<>();

private boolean async = false;
Expand Down Expand Up @@ -412,7 +413,7 @@ private CompletableFuture<List<BreakpointRequest>> createBreakpointRequests(List

newLocations.forEach(location -> {
BreakpointRequest request = vm.eventRequestManager().createBreakpointRequest(location);
request.setSuspendPolicy(BreakpointRequest.SUSPEND_EVENT_THREAD);
request.setSuspendPolicy(suspendPolicy);
if (hitCount > 0) {
request.addCountFilter(hitCount);
}
Expand Down Expand Up @@ -468,4 +469,14 @@ public void putProperty(Object key, Object value) {
public Object getProperty(Object key) {
return propertyMap.get(key);
}

@Override
public int getSuspendPolicy() {
return this.suspendPolicy;
}

@Override
public void setSuspendPolicy(int suspendPolicy) {
this.suspendPolicy = suspendPolicy;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,17 @@ public void terminate() {
}

@Override
public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) {
return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage);
public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage, int suspendPolicy) {
EvaluatableBreakpoint breakpoint = new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage);
breakpoint.setSuspendPolicy(suspendPolicy);
return breakpoint;
}

@Override
public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage) {
return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage);
public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage, int suspendPolicy) {
EvaluatableBreakpoint breakpoint = new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage);
breakpoint.setSuspendPolicy(suspendPolicy);
return breakpoint;
}

@Override
Expand All @@ -142,18 +146,21 @@ public IWatchpoint createWatchPoint(String className, String fieldName, String a
}

@Override
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught) {
setExceptionBreakpoints(notifyCaught, notifyUncaught, null, null);
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught) {
setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, null, null);
}

@Override
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters) {
setExceptionBreakpoints(notifyCaught, notifyUncaught, null, classFilters, classExclusionFilters);
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught,
int suspendModeOnUncaught, String[] classFilters, String[] classExclusionFilters) {
setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, null,
classFilters, classExclusionFilters);
}

@Override
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes,
String[] classFilters, String[] classExclusionFilters) {
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught,
int suspendModeOnUncaught, String[] exceptionTypes,
String[] classFilters, String[] classExclusionFilters) {
EventRequestManager manager = vm.eventRequestManager();

try {
Expand All @@ -169,7 +176,8 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught
subscriptions.clear();
eventRequests.clear();

// When no exception breakpoints are requested, no need to create an empty exception request.
// When no exception breakpoints are requested, no need to create an empty
// exception request.
if (notifyCaught || notifyUncaught) {
// from: https://www.javatips.net/api/REPLmode-master/src/jm/mode/replmode/REPLRunner.java
// Calling this seems to set something internally to make the
Expand All @@ -184,19 +192,8 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught
// See org.eclipse.debug.jdi.tests.AbstractJDITest for the example.

if (exceptionTypes == null || exceptionTypes.length == 0) {
ExceptionRequest request = manager.createExceptionRequest(null, notifyCaught, notifyUncaught);
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
if (classFilters != null) {
for (String classFilter : classFilters) {
request.addClassFilter(classFilter);
}
}
if (classExclusionFilters != null) {
for (String exclusionFilter : classExclusionFilters) {
request.addClassExclusionFilter(exclusionFilter);
}
}
request.enable();
createExceptionBreakpoint(null, notifyCaught, notifyUncaught, suspendModeOnCaught,
suspendModeOnUncaught, classFilters, classExclusionFilters);
return;
}

Expand All @@ -212,31 +209,36 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught
eventRequests.add(classPrepareRequest);

Disposable subscription = eventHub.events()
.filter(debugEvent -> debugEvent.event instanceof ClassPrepareEvent
&& eventRequests.contains(debugEvent.event.request()))
.subscribe(debugEvent -> {
ClassPrepareEvent event = (ClassPrepareEvent) debugEvent.event;
createExceptionBreakpoint(event.referenceType(), notifyCaught, notifyUncaught, classFilters, classExclusionFilters);
});
.filter(debugEvent -> debugEvent.event instanceof ClassPrepareEvent
&& eventRequests.contains(debugEvent.event.request()))
.subscribe(debugEvent -> {
ClassPrepareEvent event = (ClassPrepareEvent) debugEvent.event;
createExceptionBreakpoint(event.referenceType(), notifyCaught, notifyUncaught,
suspendModeOnCaught, suspendModeOnUncaught, classFilters, classExclusionFilters);
});
subscriptions.add(subscription);

// register exception breakpoint in the loaded classes.
for (ReferenceType refType : vm.classesByName(exceptionType)) {
createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, classFilters, classExclusionFilters);
createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught,
suspendModeOnUncaught, classFilters, classExclusionFilters);
}
}
}
}

@Override
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes,
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught,
int suspendModeOnUncaught, String[] exceptionTypes,
String[] classFilters, String[] classExclusionFilters, boolean async) {
if (async) {
AsyncJdwpUtils.runAsync(() -> {
setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters);
setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught,
exceptionTypes, classFilters, classExclusionFilters);
});
} else {
setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters);
setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught,
exceptionTypes, classFilters, classExclusionFilters);
}
}

Expand Down Expand Up @@ -267,10 +269,20 @@ public IMethodBreakpoint createFunctionBreakpoint(String className, String funct
}

private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught,
String[] classFilters, String[] classExclusionFilters) {
int suspendModeOnCaught, int suspendModeOnUncaught, String[] classFilters, String[] classExclusionFilters) {
if (suspendModeOnCaught == suspendModeOnUncaught) {
createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught, classFilters, classExclusionFilters);
} else {
createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught, classFilters, classExclusionFilters);
createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnUncaught, classFilters, classExclusionFilters);
}
}

private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught,
int suspendMode, String[] classFilters, String[] classExclusionFilters) {
EventRequestManager manager = vm.eventRequestManager();
ExceptionRequest request = manager.createExceptionRequest(refType, notifyCaught, notifyUncaught);
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
request.setSuspendPolicy(suspendMode);
if (classFilters != null) {
for (String classFilter : classFilters) {
request.addClassFilter(classFilter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ public interface IBreakpoint extends IDebugResource {

void setLogMessage(String logMessage);

int getSuspendPolicy();

void setSuspendPolicy(int suspendPolicy);

default void setAsync(boolean async) {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,25 @@ public interface IDebugSession {
void terminate();

// breakpoints
IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage);
IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage,
int suspendPolicy);

IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage);
IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition,
String logMessage, int suspendPolicy);

IWatchpoint createWatchPoint(String className, String fieldName, String accessType, String condition, int hitCount);

void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught);
void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught,
int suspendModeOnUncaught);

void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters);
void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught,
int suspendModeOnUncaught, String[] classFilters, String[] classExclusionFilters);

void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters);
void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught,
int suspendModeOnUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters);

void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters,
boolean async);
void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught,
int suspendModeOnUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters, boolean async);

IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition, int hitCount);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

import com.microsoft.java.debug.core.DebugException;
import com.microsoft.java.debug.core.protocol.Messages.Response;
import com.sun.jdi.request.EventRequest;
import com.microsoft.java.debug.core.protocol.Responses;
import com.microsoft.java.debug.core.protocol.Types;

Expand Down Expand Up @@ -364,4 +365,13 @@ public static int[] binarySearchMappedLines(int[] lineMappings, int targetLine)

return values;
}

public static int suspendPolicyFromBreakpointMode(String breakpointMode) {
if (Constants.SUSPEND_VM.equals(breakpointMode)) {
return EventRequest.SUSPEND_ALL;
} else if (Constants.SUSPEND_THREAD.equals(breakpointMode)) {
return EventRequest.SUSPEND_EVENT_THREAD;
}
return EventRequest.SUSPEND_EVENT_THREAD;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ public final class Constants {
public static final String PROJECT_NAME = "projectName";
public static final String DEBUGGEE_ENCODING = "debuggeeEncoding";
public static final String MAIN_CLASS = "mainClass";

// Breakpoint suspend modes
public static final String SUSPEND_VM = "suspendVM";
public static final String SUSPEND_THREAD = "suspendThread";
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import com.sun.jdi.event.VMDeathEvent;
import com.sun.jdi.event.VMDisconnectEvent;
import com.sun.jdi.event.VMStartEvent;
import com.sun.jdi.request.EventRequest;

public class ConfigurationDoneRequestHandler implements IDebugRequestHandler {
protected static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
Expand Down Expand Up @@ -119,7 +120,8 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession,
((ExceptionEvent) event).catchLocation() == null);
context.getExceptionManager().setException(thread.uniqueID(), jdiException);
context.getThreadCache().addEventThread(thread, "exception");
context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID()));
boolean suspendAll = event.request() != null ? event.request().suspendPolicy() == EventRequest.SUSPEND_ALL : false;
context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID(), suspendAll));
debugEvent.shouldResume = false;
} else {
isImportantEvent = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;

import com.microsoft.java.debug.core.adapter.Constants;
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
import com.microsoft.java.debug.core.protocol.Messages;
import com.microsoft.java.debug.core.protocol.Requests;
import com.microsoft.java.debug.core.protocol.Types;

public class InitializeRequestHandler implements IDebugRequestHandler {

@Override
public List<Requests.Command> getTargetCommands() {
return Arrays.asList(Requests.Command.INITIALIZE);
Expand Down Expand Up @@ -66,6 +68,30 @@ public CompletableFuture<Messages.Response> handle(Requests.Command command, Req
caps.supportsClipboardContext = true;
caps.supportsBreakpointLocationsRequest = true;
caps.supportsStepInTargetsRequest = true;

// Add breakpoint modes for suspend behavior
Types.BreakpointMode[] breakpointModes = {
new Types.BreakpointMode(
Constants.SUSPEND_THREAD,
"Suspend Thread",
"Suspends only the thread that hit the breakpoint",
new Types.BreakpointModeApplicability[] {
Types.BreakpointModeApplicability.SOURCE
// data and function breakpoints are not supported by VS Code
// instruction breakpoints are not supported by this adapter
}
),
new Types.BreakpointMode(
Constants.SUSPEND_VM,
"Suspend VM",
"Suspends the entire virtual machine when breakpoint is hit",
new Types.BreakpointModeApplicability[] {
Types.BreakpointModeApplicability.SOURCE
}
)
};
caps.breakpointModes = breakpointModes;

response.body = caps;
context.setInitialized(true);
return CompletableFuture.completedFuture(response);
Expand Down
Loading