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 @@ -88,6 +88,11 @@ public IWatchpoint createWatchPoint(String className, String fieldName, String a

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

@Override
public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught, String[] classFilters, String[] classExclusionFilters) {
EventRequestManager manager = vm.eventRequestManager();
ArrayList<ExceptionRequest> legacy = new ArrayList<>(manager.exceptionRequests());
manager.deleteEventRequests(legacy);
Expand All @@ -108,6 +113,16 @@ public void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught
// 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 (classExclusionFilters != null) {
for (String exclusionFilter : classExclusionFilters) {
request.addClassExclusionFilter(exclusionFilter);
}
}
request.enable();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,21 @@

package com.microsoft.java.debug.core;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

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.StepFilters;

public final class DebugSettings {
private static final Logger logger = Logger.getLogger(Configuration.LOGGER_NAME);
private static Set<IDebugSettingChangeListener> listeners =
Collections.newSetFromMap(new ConcurrentHashMap<IDebugSettingChangeListener, Boolean>());
private static DebugSettings current = new DebugSettings();

public int maxStringLength = 0;
Expand All @@ -31,6 +38,9 @@ public final class DebugSettings {
public String logLevel;
public String javaHome;
public HotCodeReplace hotCodeReplace = HotCodeReplace.MANUAL;
public StepFilters stepFilters = new StepFilters();
public ClassFilters exceptionFilters = new ClassFilters();
public boolean exceptionFiltersUpdated = false;

public static DebugSettings getCurrent() {
return current;
Expand All @@ -44,7 +54,11 @@ public static DebugSettings getCurrent() {
*/
public void updateSettings(String jsonSettings) {
try {
DebugSettings oldSettings = current;
current = JsonUtils.fromJson(jsonSettings, DebugSettings.class);
for (IDebugSettingChangeListener listener : listeners) {
listener.update(oldSettings, current);
}
} catch (JsonSyntaxException ex) {
logger.severe(String.format("Invalid json for debugSettings: %s, %s", jsonSettings, ex.getMessage()));
}
Expand All @@ -54,6 +68,14 @@ private DebugSettings() {

}

public static boolean addDebugSettingChangeListener(IDebugSettingChangeListener listener) {
return listeners.add(listener);
}

public static boolean removeDebugSettingChangeListener(IDebugSettingChangeListener listener) {
return listeners.remove(listener);
}

public static enum HotCodeReplace {
@SerializedName("manual")
MANUAL,
Expand All @@ -62,4 +84,8 @@ public static enum HotCodeReplace {
@SerializedName("never")
NEVER
}

public static interface IDebugSettingChangeListener {
public void update(DebugSettings oldSettings, DebugSettings newSettings);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,21 @@ public static IDebugSession attach(VirtualMachineManager vmManager, String hostN
* @return the new step request.
*/
public static StepRequest createStepOverRequest(ThreadReference thread, String[] stepFilters) {
return createStepRequest(thread, StepRequest.STEP_LINE, StepRequest.STEP_OVER, stepFilters);
return createStepOverRequest(thread, null, stepFilters);
}

/**
* Create a step over request on the specified thread.
* @param thread
* the target thread.
* @param classFilters
* restricts the step event to those matching the given class patterns when stepping.
* @param classExclusionFilters
* restricts the step event to those not matching the given class patterns when stepping.
* @return the new step request.
*/
public static StepRequest createStepOverRequest(ThreadReference thread, String[] classFilters, String[] classExclusionFilters) {
return createStepRequest(thread, StepRequest.STEP_LINE, StepRequest.STEP_OVER, classFilters, classExclusionFilters);
}

/**
Expand All @@ -325,7 +339,21 @@ public static StepRequest createStepOverRequest(ThreadReference thread, String[]
* @return the new step request.
*/
public static StepRequest createStepIntoRequest(ThreadReference thread, String[] stepFilters) {
return createStepRequest(thread, StepRequest.STEP_LINE, StepRequest.STEP_INTO, stepFilters);
return createStepIntoRequest(thread, null, stepFilters);
}

/**
* Create a step into request on the specified thread.
* @param thread
* the target thread.
* @param classFilters
* restricts the step event to those matching the given class patterns when stepping.
* @param classExclusionFilters
* restricts the step event to those not matching the given class patterns when stepping.
* @return the new step request.
*/
public static StepRequest createStepIntoRequest(ThreadReference thread, String[] classFilters, String[] classExclusionFilters) {
return createStepRequest(thread, StepRequest.STEP_LINE, StepRequest.STEP_INTO, classFilters, classExclusionFilters);
}

/**
Expand All @@ -337,14 +365,33 @@ public static StepRequest createStepIntoRequest(ThreadReference thread, String[]
* @return the new step request.
*/
public static StepRequest createStepOutRequest(ThreadReference thread, String[] stepFilters) {
return createStepRequest(thread, StepRequest.STEP_LINE, StepRequest.STEP_OUT, stepFilters);
return createStepOutRequest(thread, null, stepFilters);
}

private static StepRequest createStepRequest(ThreadReference thread, int stepSize, int stepDepth, String[] stepFilters) {
/**
* Create a step out request on the specified thread.
* @param thread
* the target thread.
* @param classFilters
* restricts the step event to those matching the given class patterns when stepping.
* @param classExclusionFilters
* restricts the step event to those not matching the given class patterns when stepping.
* @return the new step request.
*/
public static StepRequest createStepOutRequest(ThreadReference thread, String[] classFilters, String[] classExclusionFilters) {
return createStepRequest(thread, StepRequest.STEP_LINE, StepRequest.STEP_OUT, classFilters, classExclusionFilters);
}

private static StepRequest createStepRequest(ThreadReference thread, int stepSize, int stepDepth, String[] classFilters, String[] classExclusionFilters) {
StepRequest request = thread.virtualMachine().eventRequestManager().createStepRequest(thread, stepSize, stepDepth);
if (stepFilters != null) {
for (String stepFilter : stepFilters) {
request.addClassExclusionFilter(stepFilter);
if (classFilters != null) {
for (String classFilter : classFilters) {
request.addClassFilter(classFilter);
}
}
if (classExclusionFilters != null) {
for (String exclusionFilter : classExclusionFilters) {
request.addClassExclusionFilter(exclusionFilter);
}
}
request.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public interface IDebugSession {

void setExceptionBreakpoints(boolean notifyCaught, boolean notifyUncaught);

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

// TODO: createFunctionBreakpoint

Process process();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,24 @@

import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import com.microsoft.java.debug.core.DebugSettings;
import com.microsoft.java.debug.core.IDebugSession;
import com.microsoft.java.debug.core.adapter.variables.IVariableFormatter;
import com.microsoft.java.debug.core.adapter.variables.VariableFormatterFactory;
import com.microsoft.java.debug.core.protocol.IProtocolServer;
import com.microsoft.java.debug.core.protocol.Requests.StepFilters;

import org.apache.commons.lang3.ArrayUtils;

public class DebugAdapterContext implements IDebugAdapterContext {
private static final int MAX_CACHE_ITEMS = 10000;
private final StepFilters defaultFilters = new StepFilters();
private Map<String, String> sourceMappingCache = Collections.synchronizedMap(new LRUCache<>(MAX_CACHE_ITEMS));
private IProviderContext providerContext;
private IProtocolServer server;
Expand Down Expand Up @@ -235,12 +242,28 @@ public String getMainClass() {

@Override
public void setStepFilters(StepFilters stepFilters) {
// For backward compatibility, merge the classNameFilters to skipClasses.
if (stepFilters != null && ArrayUtils.isNotEmpty(stepFilters.classNameFilters)) {
Set<String> patterns = new LinkedHashSet<>();
if (ArrayUtils.isNotEmpty(stepFilters.skipClasses)) {
patterns.addAll(Arrays.asList(stepFilters.skipClasses));
}

patterns.addAll(Arrays.asList(stepFilters.classNameFilters));
stepFilters.skipClasses = patterns.toArray(new String[0]);
}
this.stepFilters = stepFilters;
}

@Override
public StepFilters getStepFilters() {
return stepFilters;
if (stepFilters != null) {
return stepFilters;
} else if (DebugSettings.getCurrent().stepFilters != null) {
return DebugSettings.getCurrent().stepFilters;
}

return defaultFilters;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private void popStackFrames(IDebugAdapterContext context, ThreadReference thread
}

private void stepInto(IDebugAdapterContext context, ThreadReference thread) {
StepRequest request = DebugUtility.createStepIntoRequest(thread, context.getStepFilters().classNameFilters);
StepRequest request = DebugUtility.createStepIntoRequest(thread, context.getStepFilters().allowClasses, context.getStepFilters().skipClasses);
context.getDebugSession().getEventHub().stepEvents().filter(debugEvent -> request.equals(debugEvent.event.request())).take(1).subscribe(debugEvent -> {
debugEvent.shouldResume = false;
// Have to send two events to keep the UI sync with the step in operations:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,56 @@

import org.apache.commons.lang3.ArrayUtils;

import com.microsoft.java.debug.core.DebugSettings;
import com.microsoft.java.debug.core.IDebugSession;
import com.microsoft.java.debug.core.DebugSettings.IDebugSettingChangeListener;
import com.microsoft.java.debug.core.adapter.AdapterUtils;
import com.microsoft.java.debug.core.adapter.ErrorCode;
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
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.SetExceptionBreakpointsArguments;
import com.microsoft.java.debug.core.protocol.Types;
import com.sun.jdi.event.VMDeathEvent;
import com.sun.jdi.event.VMDisconnectEvent;

public class SetExceptionBreakpointsRequestHandler implements IDebugRequestHandler {
public class SetExceptionBreakpointsRequestHandler implements IDebugRequestHandler, IDebugSettingChangeListener {
private IDebugSession debugSession = null;
private boolean isInitialized = false;
private boolean notifyCaught = false;
private boolean notifyUncaught = false;

@Override
public List<Command> getTargetCommands() {
return Arrays.asList(Command.SETEXCEPTIONBREAKPOINTS);
}

@Override
public CompletableFuture<Response> handle(Command command, Arguments arguments, Response response, IDebugAdapterContext context) {
public synchronized CompletableFuture<Response> handle(Command command, Arguments arguments, Response response, IDebugAdapterContext context) {
if (context.getDebugSession() == null) {
return AdapterUtils.createAsyncErrorResponse(response, ErrorCode.EMPTY_DEBUG_SESSION, "Empty debug session.");
}

if (!isInitialized) {
isInitialized = true;
debugSession = context.getDebugSession();
DebugSettings.addDebugSettingChangeListener(this);
debugSession.getEventHub().events().subscribe(debugEvent -> {
if (debugEvent.event instanceof VMDeathEvent
|| debugEvent.event instanceof VMDisconnectEvent) {
DebugSettings.removeDebugSettingChangeListener(this);
}
});
}

String[] filters = ((SetExceptionBreakpointsArguments) arguments).filters;
try {
boolean notifyCaught = ArrayUtils.contains(filters, Types.ExceptionBreakpointFilter.CAUGHT_EXCEPTION_FILTER_NAME);
boolean notifyUncaught = ArrayUtils.contains(filters, Types.ExceptionBreakpointFilter.UNCAUGHT_EXCEPTION_FILTER_NAME);

context.getDebugSession().setExceptionBreakpoints(notifyCaught, notifyUncaught);
this.notifyCaught = ArrayUtils.contains(filters, Types.ExceptionBreakpointFilter.CAUGHT_EXCEPTION_FILTER_NAME);
this.notifyUncaught = ArrayUtils.contains(filters, Types.ExceptionBreakpointFilter.UNCAUGHT_EXCEPTION_FILTER_NAME);
setExceptionBreakpoints(context.getDebugSession(), this.notifyCaught, this.notifyUncaught);
return CompletableFuture.completedFuture(response);
} catch (Exception ex) {
throw AdapterUtils.createCompletionException(
Expand All @@ -55,4 +76,21 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
}
}

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

@Override
public synchronized void update(DebugSettings oldSettings, DebugSettings newSettings) {
try {
if (newSettings != null && newSettings.exceptionFiltersUpdated) {
setExceptionBreakpoints(debugSession, notifyCaught, notifyUncaught);
}
} catch (Exception ex) {
DebugSettings.removeDebugSettingChangeListener(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,14 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,

if (command == Command.STEPIN) {
threadState.pendingStepRequest = DebugUtility.createStepIntoRequest(thread,
context.getStepFilters().classNameFilters);
context.getStepFilters().allowClasses,
context.getStepFilters().skipClasses);
} else if (command == Command.STEPOUT) {
threadState.pendingStepRequest = DebugUtility.createStepOutRequest(thread,
context.getStepFilters().classNameFilters);
context.getStepFilters().allowClasses,
context.getStepFilters().skipClasses);
} else {
threadState.pendingStepRequest = DebugUtility.createStepOverRequest(thread,
context.getStepFilters().classNameFilters);
threadState.pendingStepRequest = DebugUtility.createStepOverRequest(thread, null);
}
threadState.pendingStepRequest.enable();
DebugUtility.resumeThread(thread);
Expand Down Expand Up @@ -133,21 +134,14 @@ private void handleDebugEvent(DebugEvent debugEvent, IDebugSession debugSession,
if (threadState.pendingStepType == Command.STEPIN) {
int currentStackDepth = thread.frameCount();
Location currentStepLocation = getTopFrame(thread).location();
// Check if the step into operation stepped through the filtered code and stopped at an un-filtered location.
if (threadState.stackDepth + 1 < thread.frameCount()) {
// Create another stepOut request to return back where we started the step into.
threadState.pendingStepRequest = DebugUtility.createStepOutRequest(thread,
context.getStepFilters().classNameFilters);
threadState.pendingStepRequest.enable();
debugEvent.shouldResume = true;
return;
}

// If the ending step location is filtered, or same as the original location where the step into operation is originated,
// do another step of the same kind.
if (shouldFilterLocation(threadState.stepLocation, currentStepLocation, context)
|| shouldDoExtraStepInto(threadState.stackDepth, threadState.stepLocation, currentStackDepth, currentStepLocation)) {
threadState.pendingStepRequest = DebugUtility.createStepIntoRequest(thread,
context.getStepFilters().classNameFilters);
context.getStepFilters().allowClasses,
context.getStepFilters().skipClasses);
threadState.pendingStepRequest.enable();
debugEvent.shouldResume = true;
return;
Expand All @@ -169,7 +163,8 @@ private boolean isStepFiltersConfigured(StepFilters filters) {
if (filters == null) {
return false;
}
return ArrayUtils.isNotEmpty(filters.classNameFilters) || filters.skipConstructors
return ArrayUtils.isNotEmpty(filters.allowClasses) || ArrayUtils.isNotEmpty(filters.skipClasses)
|| ArrayUtils.isNotEmpty(filters.classNameFilters) || filters.skipConstructors
|| filters.skipStaticInitializers || filters.skipSynthetics;
}

Expand Down
Loading