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
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @testforstephen @jdneo @Eskibear @CsCherrYY
* @testforstephen @jdneo
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,26 @@
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import com.sun.jdi.ObjectCollectedException;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.VMDisconnectedException;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.request.ClassPrepareRequest;
import com.sun.jdi.request.EventRequest;
import com.sun.jdi.request.EventRequestManager;
import com.sun.jdi.request.ExceptionRequest;

import io.reactivex.disposables.Disposable;

public class DebugSession implements IDebugSession {
private VirtualMachine vm;
private EventHub eventHub = new EventHub();
private List<EventRequest> eventRequests = new ArrayList<>();
private List<Disposable> subscriptions = new ArrayList<>();

public DebugSession(VirtualMachine virtualMachine) {
vm = virtualMachine;
Expand Down Expand Up @@ -136,9 +146,27 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught

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

@Override
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] exceptionTypes,
String[] classFilters, String[] classExclusionFilters) {
EventRequestManager manager = vm.eventRequestManager();
ArrayList<ExceptionRequest> legacy = new ArrayList<>(manager.exceptionRequests());
manager.deleteEventRequests(legacy);

try {
ArrayList<ExceptionRequest> legacy = new ArrayList<>(manager.exceptionRequests());
manager.deleteEventRequests(legacy);
manager.deleteEventRequests(eventRequests);
} catch (VMDisconnectedException ex) {
// ignore since removing breakpoints is meaningless when JVM is terminated.
}
subscriptions.forEach(subscription -> {
subscription.dispose();
});
subscriptions.clear();
eventRequests.clear();

// 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
Expand All @@ -153,20 +181,48 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught
// a thread to be available, and queries it by calling allThreads().
// See org.eclipse.debug.jdi.tests.AbstractJDITest for the example.

// get only the uncaught exceptions
ExceptionRequest request = manager.createExceptionRequest(null, notifyCaught, notifyUncaught);
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
if (classFilters != null) {
for (String classFilter : classFilters) {
request.addClassFilter(classFilter);
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();
return;
}
if (classExclusionFilters != null) {
for (String exclusionFilter : classExclusionFilters) {
request.addClassExclusionFilter(exclusionFilter);

for (String exceptionType : exceptionTypes) {
if (StringUtils.isBlank(exceptionType)) {
continue;
}

// register exception breakpoint in the future loaded classes.
ClassPrepareRequest classPrepareRequest = manager.createClassPrepareRequest();
classPrepareRequest.addClassFilter(exceptionType);
classPrepareRequest.enable();
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);
});
subscriptions.add(subscription);

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

Expand Down Expand Up @@ -195,4 +251,22 @@ public IMethodBreakpoint createFunctionBreakpoint(String className, String funct
int hitCount) {
return new MethodBreakpoint(vm, this.getEventHub(), className, functionName, condition, hitCount);
}

private void createExceptionBreakpoint(ReferenceType refType, boolean notifyCaught, boolean notifyUncaught,
String[] classFilters, String[] classExclusionFilters) {
EventRequestManager manager = vm.eventRequestManager();
ExceptionRequest request = manager.createExceptionRequest(refType, 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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import com.google.gson.JsonSyntaxException;
import com.google.gson.annotations.SerializedName;
import com.microsoft.java.debug.core.protocol.JsonUtils;
import com.microsoft.java.debug.core.protocol.Requests.ClassFilters;
import com.microsoft.java.debug.core.protocol.Requests.ExceptionFilters;
import com.microsoft.java.debug.core.protocol.Requests.StepFilters;

public final class DebugSettings {
Expand All @@ -39,7 +39,7 @@ public final class DebugSettings {
public String javaHome;
public HotCodeReplace hotCodeReplace = HotCodeReplace.MANUAL;
public StepFilters stepFilters = new StepFilters();
public ClassFilters exceptionFilters = new ClassFilters();
public ExceptionFilters exceptionFilters = new ExceptionFilters();
public boolean exceptionFiltersUpdated = false;
public int limitOfVariablesPerJdwpRequest = 100;
public int jdwpRequestTimeout = 3000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public interface IDebugSession {

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

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

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

Process process();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
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.ClassFilters;
import com.microsoft.java.debug.core.protocol.Requests.Command;
import com.microsoft.java.debug.core.protocol.Requests.ExceptionFilters;
import com.microsoft.java.debug.core.protocol.Requests.SetExceptionBreakpointsArguments;
import com.microsoft.java.debug.core.protocol.Types;
import com.sun.jdi.event.VMDeathEvent;
Expand Down Expand Up @@ -77,10 +77,11 @@ public synchronized CompletableFuture<Response> handle(Command command, Argument
}

private void setExceptionBreakpoints(IDebugSession debugSession, boolean notifyCaught, boolean notifyUncaught) {
ClassFilters exceptionFilters = DebugSettings.getCurrent().exceptionFilters;
ExceptionFilters exceptionFilters = DebugSettings.getCurrent().exceptionFilters;
String[] exceptionTypes = (exceptionFilters == null ? null : exceptionFilters.exceptionTypes);
String[] classFilters = (exceptionFilters == null ? null : exceptionFilters.allowClasses);
String[] classExclusionFilters = (exceptionFilters == null ? null : exceptionFilters.skipClasses);
debugSession.setExceptionBreakpoints(notifyCaught, notifyUncaught, classFilters, classExclusionFilters);
debugSession.setExceptionBreakpoints(notifyCaught, notifyUncaught, exceptionTypes, classFilters, classExclusionFilters);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ public static class ClassFilters {
public String[] skipClasses = new String[0];
}

public static class ExceptionFilters extends ClassFilters {
/**
* Specifies that exceptions which are instances of refType will be reported.
* Note: this will include instances of sub-types. If null, all instances
* will be reported.
*/
public String[] exceptionTypes = new String[0];
}

public static class StepFilters extends ClassFilters {
/**
* Deprecated - please use {@link ClassFilters#skipClasses } instead.
Expand Down