Skip to content

Commit d21110e

Browse files
committed
Add suspend mode for source breakpoints
Signed-off-by: Thomas Mäder <[email protected]>
1 parent ab5d534 commit d21110e

File tree

13 files changed

+301
-52
lines changed

13 files changed

+301
-52
lines changed

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class Breakpoint implements IBreakpoint {
4141
private int hitCount = 0;
4242
private String condition = null;
4343
private String logMessage = null;
44+
private int suspendPolicy = BreakpointRequest.SUSPEND_EVENT_THREAD;
4445
private HashMap<Object, Object> propertyMap = new HashMap<>();
4546

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

413414
newLocations.forEach(location -> {
414415
BreakpointRequest request = vm.eventRequestManager().createBreakpointRequest(location);
415-
request.setSuspendPolicy(BreakpointRequest.SUSPEND_EVENT_THREAD);
416+
request.setSuspendPolicy(suspendPolicy);
416417
if (hitCount > 0) {
417418
request.addCountFilter(hitCount);
418419
}
@@ -468,4 +469,14 @@ public void putProperty(Object key, Object value) {
468469
public Object getProperty(Object key) {
469470
return propertyMap.get(key);
470471
}
472+
473+
@Override
474+
public int getSuspendPolicy() {
475+
return this.suspendPolicy;
476+
}
477+
478+
@Override
479+
public void setSuspendPolicy(int suspendPolicy) {
480+
this.suspendPolicy = suspendPolicy;
481+
}
471482
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugSession.java

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,17 @@ public void terminate() {
127127
}
128128

129129
@Override
130-
public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) {
131-
return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage);
130+
public IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage, int suspendPolicy) {
131+
EvaluatableBreakpoint breakpoint = new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage);
132+
breakpoint.setSuspendPolicy(suspendPolicy);
133+
return breakpoint;
132134
}
133135

134136
@Override
135-
public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage) {
136-
return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage);
137+
public IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage, int suspendPolicy) {
138+
EvaluatableBreakpoint breakpoint = new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage);
139+
breakpoint.setSuspendPolicy(suspendPolicy);
140+
return breakpoint;
137141
}
138142

139143
@Override
@@ -142,17 +146,17 @@ public IWatchpoint createWatchPoint(String className, String fieldName, String a
142146
}
143147

144148
@Override
145-
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught) {
146-
setExceptionBreakpoints(notifyCaught, notifyUncaught, null, null);
149+
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught) {
150+
setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, null, null);
147151
}
148152

149153
@Override
150-
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters) {
151-
setExceptionBreakpoints(notifyCaught, notifyUncaught, null, classFilters, classExclusionFilters);
154+
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] classFilters, String[] classExclusionFilters) {
155+
setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, null, classFilters, classExclusionFilters);
152156
}
153157

154158
@Override
155-
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes,
159+
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] exceptionTypes,
156160
String[] classFilters, String[] classExclusionFilters) {
157161
EventRequestManager manager = vm.eventRequestManager();
158162

@@ -184,19 +188,7 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught
184188
// See org.eclipse.debug.jdi.tests.AbstractJDITest for the example.
185189

186190
if (exceptionTypes == null || exceptionTypes.length == 0) {
187-
ExceptionRequest request = manager.createExceptionRequest(null, notifyCaught, notifyUncaught);
188-
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
189-
if (classFilters != null) {
190-
for (String classFilter : classFilters) {
191-
request.addClassFilter(classFilter);
192-
}
193-
}
194-
if (classExclusionFilters != null) {
195-
for (String exclusionFilter : classExclusionFilters) {
196-
request.addClassExclusionFilter(exclusionFilter);
197-
}
198-
}
199-
request.enable();
191+
createExceptionBreakpoint(null, notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, classFilters, classExclusionFilters);
200192
return;
201193
}
202194

@@ -216,27 +208,27 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught
216208
&& eventRequests.contains(debugEvent.event.request()))
217209
.subscribe(debugEvent -> {
218210
ClassPrepareEvent event = (ClassPrepareEvent) debugEvent.event;
219-
createExceptionBreakpoint(event.referenceType(), notifyCaught, notifyUncaught, classFilters, classExclusionFilters);
211+
createExceptionBreakpoint(event.referenceType(), notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, classFilters, classExclusionFilters);
220212
});
221213
subscriptions.add(subscription);
222214

223215
// register exception breakpoint in the loaded classes.
224216
for (ReferenceType refType : vm.classesByName(exceptionType)) {
225-
createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, classFilters, classExclusionFilters);
217+
createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, classFilters, classExclusionFilters);
226218
}
227219
}
228220
}
229221
}
230222

231223
@Override
232-
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes,
224+
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] exceptionTypes,
233225
String[] classFilters, String[] classExclusionFilters, boolean async) {
234226
if (async) {
235227
AsyncJdwpUtils.runAsync(() -> {
236-
setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters);
228+
setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, exceptionTypes, classFilters, classExclusionFilters);
237229
});
238230
} else {
239-
setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters);
231+
setExceptionBreakpoints(notifyCaught, notifyUncaught, suspendModeOnCaught, suspendModeOnUncaught, exceptionTypes, classFilters, classExclusionFilters);
240232
}
241233
}
242234

@@ -267,10 +259,20 @@ public IMethodBreakpoint createFunctionBreakpoint(String className, String funct
267259
}
268260

269261
private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught,
270-
String[] classFilters, String[] classExclusionFilters) {
262+
int suspendModeOnCaught, int suspendModeOnUncaught, String[] classFilters, String[] classExclusionFilters) {
263+
if (suspendModeOnCaught == suspendModeOnUncaught) {
264+
createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught, classFilters, classExclusionFilters);
265+
} else {
266+
createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnCaught, classFilters, classExclusionFilters);
267+
createExceptionBreakpoint(refType, notifyCaught, notifyUncaught, suspendModeOnUncaught, classFilters, classExclusionFilters);
268+
}
269+
}
270+
271+
private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught,
272+
int suspendMode, String[] classFilters, String[] classExclusionFilters) {
271273
EventRequestManager manager = vm.eventRequestManager();
272274
ExceptionRequest request = manager.createExceptionRequest(refType, notifyCaught, notifyUncaught);
273-
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
275+
request.setSuspendPolicy(suspendMode);
274276
if (classFilters != null) {
275277
for (String classFilter : classFilters) {
276278
request.addClassFilter(classFilter);

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IBreakpoint.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ public interface IBreakpoint extends IDebugResource {
4949

5050
void setLogMessage(String logMessage);
5151

52+
int getSuspendPolicy();
53+
54+
void setSuspendPolicy(int suspendPolicy);
55+
5256
default void setAsync(boolean async) {
5357
}
5458

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/IDebugSession.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,19 @@ public interface IDebugSession {
2828
void terminate();
2929

3030
// breakpoints
31-
IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage);
31+
IBreakpoint createBreakpoint(String className, int lineNumber, int hitCount, String condition, String logMessage, int suspendPolicy);
3232

33-
IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage);
33+
IBreakpoint createBreakpoint(JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage, int suspendPolicy);
3434

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

37-
void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught);
37+
void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught);
3838

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

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

43-
void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters,
43+
void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, int suspendModeOnCaught, int suspendModeOnUncaught, String[] exceptionTypes, String[] classFilters, String[] classExclusionFilters,
4444
boolean async);
4545

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

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/AdapterUtils.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
import com.microsoft.java.debug.core.DebugException;
3636
import com.microsoft.java.debug.core.protocol.Messages.Response;
37+
import com.sun.jdi.request.EventRequest;
3738
import com.microsoft.java.debug.core.protocol.Responses;
3839
import com.microsoft.java.debug.core.protocol.Types;
3940

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

365366
return values;
366367
}
368+
369+
public static int suspendPolicyFromBreakpointMode(String breakpointMode) {
370+
if (Constants.SUSPEND_VM.equals(breakpointMode)) {
371+
return EventRequest.SUSPEND_ALL;
372+
} else if (Constants.SUSPEND_THREAD.equals(breakpointMode)) {
373+
return EventRequest.SUSPEND_EVENT_THREAD;
374+
}
375+
return EventRequest.SUSPEND_EVENT_THREAD;
376+
}
367377
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/Constants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,8 @@ public final class Constants {
1515
public static final String PROJECT_NAME = "projectName";
1616
public static final String DEBUGGEE_ENCODING = "debuggeeEncoding";
1717
public static final String MAIN_CLASS = "mainClass";
18+
19+
// Breakpoint suspend modes
20+
public static final String SUSPEND_VM = "suspendVM";
21+
public static final String SUSPEND_THREAD = "suspendThread";
1822
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/ConfigurationDoneRequestHandler.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import com.sun.jdi.event.VMDeathEvent;
4242
import com.sun.jdi.event.VMDisconnectEvent;
4343
import com.sun.jdi.event.VMStartEvent;
44+
import com.sun.jdi.request.EventRequest;
4445

4546
public class ConfigurationDoneRequestHandler implements IDebugRequestHandler {
4647
protected static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
@@ -119,7 +120,8 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession,
119120
((ExceptionEvent) event).catchLocation() == null);
120121
context.getExceptionManager().setException(thread.uniqueID(), jdiException);
121122
context.getThreadCache().addEventThread(thread, "exception");
122-
context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID()));
123+
boolean suspendAll = event.request() != null ? event.request().suspendPolicy() == EventRequest.SUSPEND_ALL : false;
124+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("exception", thread.uniqueID(), suspendAll));
123125
debugEvent.shouldResume = false;
124126
} else {
125127
isImportantEvent = false;

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/InitializeRequestHandler.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
import java.util.List;
1616
import java.util.concurrent.CompletableFuture;
1717

18+
import com.microsoft.java.debug.core.adapter.Constants;
1819
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
1920
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
2021
import com.microsoft.java.debug.core.protocol.Messages;
2122
import com.microsoft.java.debug.core.protocol.Requests;
2223
import com.microsoft.java.debug.core.protocol.Types;
2324

2425
public class InitializeRequestHandler implements IDebugRequestHandler {
26+
2527
@Override
2628
public List<Requests.Command> getTargetCommands() {
2729
return Arrays.asList(Requests.Command.INITIALIZE);
@@ -66,6 +68,30 @@ public CompletableFuture<Messages.Response> handle(Requests.Command command, Req
6668
caps.supportsClipboardContext = true;
6769
caps.supportsBreakpointLocationsRequest = true;
6870
caps.supportsStepInTargetsRequest = true;
71+
72+
// Add breakpoint modes for suspend behavior
73+
Types.BreakpointMode[] breakpointModes = {
74+
new Types.BreakpointMode (
75+
Constants.SUSPEND_THREAD,
76+
"Suspend Thread",
77+
"Suspends only the thread that hit the breakpoint",
78+
new Types.BreakpointModeApplicability[] {
79+
Types.BreakpointModeApplicability.SOURCE
80+
// data and function breakpoints are not supported by VS Code
81+
// instruction breakpoints are not supported by this adapter
82+
}
83+
),
84+
new Types.BreakpointMode(
85+
Constants.SUSPEND_VM,
86+
"Suspend VM",
87+
"Suspends the entire virtual machine when breakpoint is hit",
88+
new Types.BreakpointModeApplicability[] {
89+
Types.BreakpointModeApplicability.SOURCE }
90+
)
91+
92+
};
93+
caps.breakpointModes = breakpointModes;
94+
6995
response.body = caps;
7096
context.setInitialized(true);
7197
return CompletableFuture.completedFuture(response);

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/SetBreakpointsRequestHandler.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,19 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
134134
added[i].setCondition(toAdds[i].getCondition());
135135
}
136136

137+
if (toAdds[i].getSuspendPolicy() != added[i].getSuspendPolicy()) {
138+
added[i].setSuspendPolicy(toAdds[i].getSuspendPolicy());
139+
try {
140+
added[i].close();
141+
added[i].install().thenAccept(bp -> {
142+
Events.BreakpointEvent bpEvent = new Events.BreakpointEvent("changed", this.convertDebuggerBreakpointToClient(bp, context));
143+
context.getProtocolServer().sendEvent(bpEvent);
144+
});
145+
} catch (Exception e) {
146+
logger.log(Level.SEVERE, String.format("Close breakpoint exception: %s", e.toString()), e);
147+
}
148+
}
149+
137150
}
138151
res.add(this.convertDebuggerBreakpointToClient(added[i], context));
139152
}
@@ -200,6 +213,7 @@ private void registerBreakpointHandler(IDebugAdapterContext context) {
200213
// find the breakpoint related to this breakpoint event
201214
IBreakpoint expressionBP = getAssociatedEvaluatableBreakpoint(context, (BreakpointEvent) event);
202215
String breakpointName = computeBreakpointName(event.request());
216+
boolean suspendAll = event.request() != null ? event.request().suspendPolicy() == EventRequest.SUSPEND_ALL : false;
203217

204218
if (expressionBP != null) {
205219
CompletableFuture.runAsync(() -> {
@@ -212,15 +226,14 @@ private void registerBreakpointHandler(IDebugAdapterContext context) {
212226
debugEvent.eventSet.resume();
213227
} else {
214228
context.getThreadCache().addEventThread(bpThread, breakpointName);
215-
context.getProtocolServer().sendEvent(new Events.StoppedEvent(
216-
breakpointName, bpThread.uniqueID()));
229+
context.getProtocolServer().sendEvent(new Events.StoppedEvent(breakpointName, bpThread.uniqueID(), suspendAll));
217230
}
218231
});
219232
});
220233
} else {
221234
context.getThreadCache().addEventThread(bpThread, breakpointName);
222235
context.getProtocolServer().sendEvent(new Events.StoppedEvent(
223-
breakpointName, bpThread.uniqueID()));
236+
breakpointName, bpThread.uniqueID(), suspendAll));
224237
}
225238
debugEvent.shouldResume = false;
226239
}
@@ -335,7 +348,7 @@ private IBreakpoint[] convertClientBreakpointsToDebugger(String sourceFile, Type
335348
}
336349
}
337350
breakpoints[i] = context.getDebugSession().createBreakpoint(locations[i], hitCount, sourceBreakpoints[i].condition,
338-
sourceBreakpoints[i].logMessage);
351+
sourceBreakpoints[i].logMessage, AdapterUtils.suspendPolicyFromBreakpointMode(sourceBreakpoints[i].mode));
339352
if (sourceProvider.supportsRealtimeBreakpointVerification() && StringUtils.isNotBlank(locations[i].className())) {
340353
breakpoints[i].putProperty("verified", true);
341354
}

0 commit comments

Comments
 (0)