Skip to content

Commit

Permalink
Support debug protocol.
Browse files Browse the repository at this point in the history
  • Loading branch information
yaohaizh committed Mar 26, 2018
1 parent 72d056c commit 2d5556c
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.microsoft.java.debug.core.adapter.handler.HotCodeReplaceHandler;
import com.microsoft.java.debug.core.adapter.handler.InitializeRequestHandler;
import com.microsoft.java.debug.core.adapter.handler.LaunchRequestHandler;
import com.microsoft.java.debug.core.adapter.handler.RestartFrameHandler;
import com.microsoft.java.debug.core.adapter.handler.ScopesRequestHandler;
import com.microsoft.java.debug.core.adapter.handler.SetBreakpointsRequestHandler;
import com.microsoft.java.debug.core.adapter.handler.SetExceptionBreakpointsRequestHandler;
Expand Down Expand Up @@ -106,6 +107,7 @@ private void initialize() {
registerHandler(new SetVariableRequestHandler());
registerHandler(new EvaluateRequestHandler());
registerHandler(new HotCodeReplaceHandler());
registerHandler(new RestartFrameHandler());
}

private void registerHandler(IDebugRequestHandler handler) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public enum ErrorCode {
INVALID_ENCODING(1012),
VM_TERMINATED(1013),
LAUNCH_IN_TERMINAL_FAILURE(1014),
STEP_FAILURE(1015);
STEP_FAILURE(1015),
RESTARTFRAME_FAILURE(1016);

private int id;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public CompletableFuture<Messages.Response> handle(Requests.Command command, Req
caps.supportsConditionalBreakpoints = true;
caps.supportsSetVariable = true;
caps.supportTerminateDebuggee = true;
caps.supportsRestartFrame = true;
Types.ExceptionBreakpointFilter[] exceptionFilters = {
Types.ExceptionBreakpointFilter.UNCAUGHT_EXCEPTION_FILTER,
Types.ExceptionBreakpointFilter.CAUGHT_EXCEPTION_FILTER,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*******************************************************************************
* Copyright (c) 2017 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/

package com.microsoft.java.debug.core.adapter.handler;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import com.microsoft.java.debug.core.DebugException;
import com.microsoft.java.debug.core.DebugUtility;
import com.microsoft.java.debug.core.StackFrameUtility;
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.adapter.variables.StackFrameReference;
import com.microsoft.java.debug.core.protocol.Events;
import com.microsoft.java.debug.core.protocol.Events.UserNotificationEvent.NotificationType;
import com.microsoft.java.debug.core.protocol.Messages.Response;
import com.microsoft.java.debug.core.protocol.Requests;
import com.microsoft.java.debug.core.protocol.Requests.Arguments;
import com.microsoft.java.debug.core.protocol.Requests.Command;
import com.microsoft.java.debug.core.protocol.Requests.RestartFrameArguments;
import com.sun.jdi.StackFrame;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.request.StepRequest;

/**
* Support Eclipse's `Drop To Frame` action, which is restartFrame in VSCode's
* debug.
*/
public class RestartFrameHandler implements IDebugRequestHandler {

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

@Override
public CompletableFuture<Response> handle(Command command, Arguments arguments, Response response, IDebugAdapterContext context) {
RestartFrameArguments restartFrameArgs = (RestartFrameArguments) arguments;
StackFrameReference stackFrameReference = (StackFrameReference) context.getRecyclableIdPool().getObjectById(restartFrameArgs.frameId);

if (stackFrameReference == null) {
return AdapterUtils.createAsyncErrorResponse(response, ErrorCode.RESTARTFRAME_FAILURE,
String.format("RestartFrame: cannot find the stack frame with frameID %s", restartFrameArgs.frameId));
}

if (canRestartFrame(context, stackFrameReference)) {
try {
ThreadReference reference = stackFrameReference.getThread();
popStackFrames(context, reference, stackFrameReference.getDepth());
stepInto(context, reference);
} catch (DebugException de) {
context.getProtocolServer().sendEvent(new Events.UserNotificationEvent(NotificationType.ERROR, de.getMessage()));
}
return CompletableFuture.completedFuture(response);
} else {
context.getProtocolServer().sendEvent(new Events.UserNotificationEvent(NotificationType.ERROR, "Current stack frame doesn't support restart."));
context.getProtocolServer().sendEvent(new Events.StoppedEvent("restartframe", stackFrameReference.getThread().uniqueID()));
return AdapterUtils.createAsyncErrorResponse(response, ErrorCode.RESTARTFRAME_FAILURE, "Failed to restart the selected stack frame.");
}
}

private boolean canRestartFrame(IDebugAdapterContext context, StackFrameReference frameReference) {
if (!context.getDebugSession().getVM().canPopFrames()) {
return false;
}
ThreadReference reference = frameReference.getThread();
StackFrame[] frames = context.getStackFrameManager().reloadStackFrames(reference);
// The frame cannot be the first one of the stack:
if (frames.length <= frameReference.getDepth() + 1) {
return false;
}

// Cannot restart frame involved with native call stacks:
for (int i = 0; i <= frameReference.getDepth() + 1; i++) {
if (StackFrameUtility.isNative(frames[i])) {
return false;
}
}
return true;
}

private void popStackFrames(IDebugAdapterContext context, ThreadReference thread, int depth) throws DebugException {
StackFrame[] frames = context.getStackFrameManager().reloadStackFrames(thread);
StackFrameUtility.pop(frames[depth]);
}

private void stepInto(IDebugAdapterContext context, ThreadReference thread) {
StepRequest request = DebugUtility.createStepIntoRequest(thread, context.getStepFilters().classNameFilters);
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:
context.getProtocolServer().sendEvent(new Events.StoppedEvent("step", thread.uniqueID()));
context.getProtocolServer().sendEvent(new Events.ContinuedEvent(thread.uniqueID()));
});
request.enable();
thread.resume();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ public static class RedefineClassesArguments extends Arguments {

}

public static class RestartFrameArguments extends Arguments {
public int frameId;
}

public static enum Command {
INITIALIZE("initialize", InitializeArguments.class),
LAUNCH("launch", LaunchArguments.class),
Expand All @@ -271,6 +275,7 @@ public static enum Command {
STEPOUT("stepOut", StepOutArguments.class),
PAUSE("pause", PauseArguments.class),
STACKTRACE("stackTrace", StackTraceArguments.class),
RESTARTFRAME("restartFrame", RestartFrameArguments.class),
SCOPES("scopes", ScopesArguments.class),
VARIABLES("variables", VariablesArguments.class),
SETVARIABLE("setVariable", SetVariableArguments.class),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ public static class Capabilities {
public boolean supportsHitConditionalBreakpoints;
public boolean supportsConditionalBreakpoints;
public boolean supportsEvaluateForHovers;
public boolean supportsRestartFrame;
public boolean supportsSetVariable;
public boolean supportsRestartRequest;
public boolean supportTerminateDebuggee;
Expand Down

0 comments on commit 2d5556c

Please sign in to comment.