Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
fix: not allow change policy during a live debug session
  • Loading branch information
chagong committed Jan 27, 2026
commit 6f31817d3f668b28a4178611c8fb88bae0fa3154
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,26 @@ public class Breakpoint implements IBreakpoint {
private String condition = null;
private String logMessage = null;
private HashMap<Object, Object> propertyMap = new HashMap<>();
private final boolean suspendAllThreads;

private boolean async = false;

Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber) {
this(vm, eventHub, className, lineNumber, 0, null);
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, boolean suspendAllThreads) {
this(vm, eventHub, className, lineNumber, 0, null, suspendAllThreads);
}

Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount) {
this(vm, eventHub, className, lineNumber, hitCount, null);
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, boolean suspendAllThreads) {
this(vm, eventHub, className, lineNumber, hitCount, null, suspendAllThreads);
}

Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition) {
this(vm, eventHub, className, lineNumber, hitCount, condition, null);
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, boolean suspendAllThreads) {
this(vm, eventHub, className, lineNumber, hitCount, condition, null, suspendAllThreads);
}

Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, String logMessage) {
Breakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, String condition, String logMessage, boolean suspendAllThreads) {
this.vm = vm;
this.eventHub = eventHub;
this.suspendAllThreads = suspendAllThreads;
String contextClass = className;
String methodName = null;
String methodSignature = null;
Expand All @@ -79,13 +81,14 @@ public class Breakpoint implements IBreakpoint {
this.logMessage = logMessage;
}

Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage) {
Breakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount, String condition, String logMessage, boolean suspendAllThreads) {
this.vm = vm;
this.eventHub = eventHub;
this.sourceLocation = sourceLocation;
this.hitCount = hitCount;
this.condition = condition;
this.logMessage = logMessage;
this.suspendAllThreads = suspendAllThreads;
}

// IDebugResource
Expand Down Expand Up @@ -209,7 +212,11 @@ public void setSuspendPolicy(String policy) {

@Override
public String getSuspendPolicy() {
return DebugSettings.getCurrent().suspendAllThreads ? "SUSPEND_ALL" : "SUSPEND_EVENT_THREAD";
return suspendAllThreads ? "SUSPEND_ALL" : "SUSPEND_EVENT_THREAD";
}

protected boolean suspendAllThreads() {
return suspendAllThreads;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ public class DebugSession implements IDebugSession {
private EventHub eventHub = new EventHub();
private List<EventRequest> eventRequests = new ArrayList<>();
private List<Disposable> subscriptions = new ArrayList<>();
private final boolean suspendAllThreads;

public DebugSession(VirtualMachine virtualMachine) {
vm = virtualMachine;
// Capture suspend policy at session start - this persists for the session lifetime
this.suspendAllThreads = DebugSettings.getCurrent().suspendAllThreads;
}

@Override
Expand Down Expand Up @@ -128,17 +131,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);
return new EvaluatableBreakpoint(vm, this.getEventHub(), sourceLocation, hitCount, condition, logMessage, suspendAllThreads);
}

@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);
return new EvaluatableBreakpoint(vm, this.getEventHub(), className, lineNumber, hitCount, condition, logMessage, suspendAllThreads);
}

@Override
public IWatchpoint createWatchPoint(String className, String fieldName, String accessType, String condition, int hitCount) {
return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount);
return new Watchpoint(vm, this.getEventHub(), className, fieldName, accessType, condition, hitCount, suspendAllThreads);
}

@Override
Expand Down Expand Up @@ -260,10 +263,15 @@ public VirtualMachine getVM() {
return vm;
}

@Override
public boolean suspendAllThreads() {
Comment thread
chagong marked this conversation as resolved.
Outdated
return suspendAllThreads;
}

@Override
public IMethodBreakpoint createFunctionBreakpoint(String className, String functionName, String condition,
int hitCount) {
return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount);
return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount, suspendAllThreads);
}

private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,8 @@ private static StepRequest createStepRequest(ThreadReference thread, int stepSiz
request.addClassExclusionFilter(exclusionFilter);
}
}
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
// Note: suspend policy will be set by the caller (StepRequestHandler) based on session settings
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
request.addCountFilter(1);

return request;
Expand All @@ -416,8 +416,7 @@ public static CompletableFuture<Long> stopOnEntry(IDebugSession debugSession, St
EventRequestManager manager = debugSession.getVM().eventRequestManager();
MethodEntryRequest request = manager.createMethodEntryRequest();
request.addClassFilter(mainClass);
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
request.setSuspendPolicy(debugSession.suspendAllThreads() ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);

debugSession.getEventHub().events().filter(debugEvent -> {
return debugEvent.event instanceof MethodEntryEvent && request.equals(debugEvent.event.request());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,28 @@ public class EvaluatableBreakpoint extends Breakpoint implements IEvaluatableBre
private Object compiledLogpointExpression = null;
private Map<Long, Object> compiledExpressions = new ConcurrentHashMap<>();

EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber) {
this(vm, eventHub, className, lineNumber, 0, null);
EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, boolean suspendAllThreads) {
this(vm, eventHub, className, lineNumber, 0, null, suspendAllThreads);
}

EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount) {
this(vm, eventHub, className, lineNumber, hitCount, null);
EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount, boolean suspendAllThreads) {
this(vm, eventHub, className, lineNumber, hitCount, null, suspendAllThreads);
}

EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount,
String condition) {
this(vm, eventHub, className, lineNumber, hitCount, condition, null);
String condition, boolean suspendAllThreads) {
this(vm, eventHub, className, lineNumber, hitCount, condition, null, suspendAllThreads);
}

EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, int lineNumber, int hitCount,
String condition, String logMessage) {
super(vm, eventHub, className, lineNumber, hitCount, condition, logMessage);
String condition, String logMessage, boolean suspendAllThreads) {
super(vm, eventHub, className, lineNumber, hitCount, condition, logMessage, suspendAllThreads);
this.eventHub = eventHub;
}

EvaluatableBreakpoint(VirtualMachine vm, IEventHub eventHub, JavaBreakpointLocation sourceLocation, int hitCount,
String condition, String logMessage) {
super(vm, eventHub, sourceLocation, hitCount, condition, logMessage);
String condition, String logMessage, boolean suspendAllThreads) {
super(vm, eventHub, sourceLocation, hitCount, condition, logMessage, suspendAllThreads);
this.eventHub = eventHub;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,10 @@ void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, Strin
IEventHub getEventHub();

VirtualMachine getVM();

/**
* Returns whether breakpoints should suspend all threads or just the event thread.
* This value is captured at session start and persists for the session lifetime.
*/
boolean suspendAllThreads();
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class MethodBreakpoint implements IMethodBreakpoint, IEvaluatableBreakpoi
private String condition;
private int hitCount;
private boolean async = false;
private final boolean suspendAllThreads;

private HashMap<Object, Object> propertyMap = new HashMap<>();
private Object compiledConditionalExpression = null;
Expand All @@ -54,7 +55,7 @@ public class MethodBreakpoint implements IMethodBreakpoint, IEvaluatableBreakpoi
private List<Disposable> subscriptions = new ArrayList<>();

public MethodBreakpoint(VirtualMachine vm, IEventHub eventHub, String className, String functionName,
String condition, int hitCount) {
String condition, int hitCount, boolean suspendAllThreads) {
Objects.requireNonNull(vm);
Objects.requireNonNull(eventHub);
Objects.requireNonNull(className);
Expand All @@ -65,6 +66,7 @@ public MethodBreakpoint(VirtualMachine vm, IEventHub eventHub, String className,
this.functionName = functionName;
this.condition = condition;
this.hitCount = hitCount;
this.suspendAllThreads = suspendAllThreads;
}

@Override
Expand Down Expand Up @@ -263,8 +265,7 @@ private Optional<MethodEntryRequest> createMethodEntryRequest0(ReferenceType typ
MethodEntryRequest request = vm.eventRequestManager().createMethodEntryRequest();

request.addClassFilter(type);
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
if (hitCount > 0) {
request.addCountFilter(hitCount);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,21 @@ public class Watchpoint implements IWatchpoint, IEvaluatableBreakpoint {
private HashMap<Object, Object> propertyMap = new HashMap<>();
private Object compiledConditionalExpression = null;
private Map<Long, Object> compiledExpressions = new ConcurrentHashMap<>();
private final boolean suspendAllThreads;

// IDebugResource
private List<EventRequest> requests = new ArrayList<>();
private List<Disposable> subscriptions = new ArrayList<>();

Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName) {
this(vm, eventHub, className, fieldName, "write");
Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, boolean suspendAllThreads) {
this(vm, eventHub, className, fieldName, "write", suspendAllThreads);
}

Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType) {
this(vm, eventHub, className, fieldName, accessType, null, 0);
Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, boolean suspendAllThreads) {
this(vm, eventHub, className, fieldName, accessType, null, 0, suspendAllThreads);
}

Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, String condition, int hitCount) {
Watchpoint(VirtualMachine vm, IEventHub eventHub, String className, String fieldName, String accessType, String condition, int hitCount, boolean suspendAllThreads) {
Objects.requireNonNull(vm);
Objects.requireNonNull(eventHub);
Objects.requireNonNull(className);
Expand All @@ -72,6 +73,7 @@ public class Watchpoint implements IWatchpoint, IEvaluatableBreakpoint {
this.accessType = accessType;
this.condition = condition;
this.hitCount = hitCount;
this.suspendAllThreads = suspendAllThreads;
}

@Override
Expand Down Expand Up @@ -213,8 +215,7 @@ private List<WatchpointRequest> createWatchpointRequests(ReferenceType type) {
}

watchpointRequests.forEach(request -> {
boolean suspendAll = DebugSettings.getCurrent().suspendAllThreads;
request.setSuspendPolicy(suspendAll ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
request.setSuspendPolicy(suspendAllThreads ? EventRequest.SUSPEND_ALL : EventRequest.SUSPEND_EVENT_THREAD);
if (hitCount > 0) {
request.addCountFilter(hitCount);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,11 @@
import java.util.logging.Logger;

import com.microsoft.java.debug.core.Configuration;
import com.microsoft.java.debug.core.DebugSettings;
import com.microsoft.java.debug.core.DebugSettings.IDebugSettingChangeListener;
import com.microsoft.java.debug.core.IBreakpoint;
import com.microsoft.java.debug.core.IDebugResource;
import com.microsoft.java.debug.core.IMethodBreakpoint;
import com.microsoft.java.debug.core.IWatchpoint;
import com.sun.jdi.VMDisconnectedException;

public class BreakpointManager implements IBreakpointManager, IDebugSettingChangeListener {
public class BreakpointManager implements IBreakpointManager {
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
/**
* A collection of breakpoints registered with this manager.
Expand All @@ -51,7 +47,6 @@ public BreakpointManager() {
this.sourceToBreakpoints = new HashMap<>();
this.watchpoints = new HashMap<>();
this.methodBreakpoints = new HashMap<>();
DebugSettings.addDebugSettingChangeListener(this);
}

@Override
Expand Down Expand Up @@ -273,50 +268,4 @@ public IMethodBreakpoint[] setMethodBreakpoints(IMethodBreakpoint[] breakpoints)
private String getMethodBreakpointKey(IMethodBreakpoint breakpoint) {
return breakpoint.className() + "#" + breakpoint.methodName();
}

@Override
public void update(DebugSettings oldSettings, DebugSettings newSettings) {
// If suspend policy changed, recreate all breakpoints with new policy
if (oldSettings.suspendAllThreads != newSettings.suspendAllThreads) {
// Recreate all line breakpoints
synchronized (breakpoints) {
for (IBreakpoint bp : breakpoints) {
reinstallBreakpoint(bp);
}
}

// Recreate all watchpoints
for (IWatchpoint wp : watchpoints.values()) {
if (wp != null) {
reinstallBreakpoint(wp);
}
}

// Recreate all method breakpoints
for (IMethodBreakpoint mbp : methodBreakpoints.values()) {
if (mbp != null) {
reinstallBreakpoint(mbp);
}
}
}
}

private void reinstallBreakpoint(IDebugResource resource) {
try {
// Close (delete) existing event requests
resource.close();
// Reinstall with new suspend policy (which will be read from DebugSettings)
if (resource instanceof IBreakpoint) {
((IBreakpoint) resource).install();
} else if (resource instanceof IWatchpoint) {
((IWatchpoint) resource).install();
} else if (resource instanceof IMethodBreakpoint) {
((IMethodBreakpoint) resource).install();
}
} catch (VMDisconnectedException ex) {
// Ignore since reinstalling breakpoints is meaningless when JVM is disconnected.
} catch (Exception e) {
logger.log(Level.WARNING, String.format("Failed to reinstall breakpoint: %s", e.toString()), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

import com.microsoft.java.debug.core.AsyncJdwpUtils;
import com.microsoft.java.debug.core.DebugEvent;
import com.microsoft.java.debug.core.DebugSettings;
import com.microsoft.java.debug.core.DebugUtility;
import com.microsoft.java.debug.core.IDebugSession;
import com.microsoft.java.debug.core.JdiExceptionReference;
Expand Down Expand Up @@ -114,12 +113,12 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
threadState.pendingStepRequest = DebugUtility.createStepOverRequest(thread, null);
}

if (DebugSettings.getCurrent().suspendAllThreads) {
if (context.getDebugSession().suspendAllThreads()) {
threadState.pendingStepRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
}

threadState.pendingMethodExitRequest = thread.virtualMachine().eventRequestManager().createMethodExitRequest();
if (DebugSettings.getCurrent().suspendAllThreads) {
if (context.getDebugSession().suspendAllThreads()) {
threadState.pendingMethodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
} else {
threadState.pendingMethodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
Expand Down Expand Up @@ -199,7 +198,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
}

context.getThreadCache().removeEventThread(thread.uniqueID());
if (DebugSettings.getCurrent().suspendAllThreads) {
if (context.getDebugSession().suspendAllThreads()) {
try {
context.getDebugSession().resume();
} catch (VMDisconnectedException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.apache.commons.lang3.StringUtils;

import com.microsoft.java.debug.core.AsyncJdwpUtils;
import com.microsoft.java.debug.core.DebugSettings;
import com.microsoft.java.debug.core.DebugUtility;
import com.microsoft.java.debug.core.adapter.AdapterUtils;
import com.microsoft.java.debug.core.adapter.ErrorCode;
Expand Down Expand Up @@ -151,7 +150,7 @@ private CompletableFuture<Response> resume(Requests.ContinueArguments arguments,
thread = DebugUtility.getThread(context.getDebugSession(), arguments.threadId);
}

if (DebugSettings.getCurrent().suspendAllThreads) {
if (context.getDebugSession().suspendAllThreads()) {
thread = null;
}

Expand Down
Loading