Skip to content

Commit c7a2ba9

Browse files
authored
Support debug protocol. (microsoft#160)
1 parent 72d056c commit c7a2ba9

File tree

6 files changed

+122
-1
lines changed

6 files changed

+122
-1
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.microsoft.java.debug.core.adapter.handler.HotCodeReplaceHandler;
2828
import com.microsoft.java.debug.core.adapter.handler.InitializeRequestHandler;
2929
import com.microsoft.java.debug.core.adapter.handler.LaunchRequestHandler;
30+
import com.microsoft.java.debug.core.adapter.handler.RestartFrameHandler;
3031
import com.microsoft.java.debug.core.adapter.handler.ScopesRequestHandler;
3132
import com.microsoft.java.debug.core.adapter.handler.SetBreakpointsRequestHandler;
3233
import com.microsoft.java.debug.core.adapter.handler.SetExceptionBreakpointsRequestHandler;
@@ -106,6 +107,7 @@ private void initialize() {
106107
registerHandler(new SetVariableRequestHandler());
107108
registerHandler(new EvaluateRequestHandler());
108109
registerHandler(new HotCodeReplaceHandler());
110+
registerHandler(new RestartFrameHandler());
109111
}
110112

111113
private void registerHandler(IDebugRequestHandler handler) {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ public enum ErrorCode {
2929
INVALID_ENCODING(1012),
3030
VM_TERMINATED(1013),
3131
LAUNCH_IN_TERMINAL_FAILURE(1014),
32-
STEP_FAILURE(1015);
32+
STEP_FAILURE(1015),
33+
RESTARTFRAME_FAILURE(1016);
3334

3435
private int id;
3536

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public CompletableFuture<Messages.Response> handle(Requests.Command command, Req
5050
caps.supportsConditionalBreakpoints = true;
5151
caps.supportsSetVariable = true;
5252
caps.supportTerminateDebuggee = true;
53+
caps.supportsRestartFrame = true;
5354
Types.ExceptionBreakpointFilter[] exceptionFilters = {
5455
Types.ExceptionBreakpointFilter.UNCAUGHT_EXCEPTION_FILTER,
5556
Types.ExceptionBreakpointFilter.CAUGHT_EXCEPTION_FILTER,
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2017 Microsoft Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License v1.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-v10.html
7+
*
8+
* Contributors:
9+
* Microsoft Corporation - initial API and implementation
10+
*******************************************************************************/
11+
12+
package com.microsoft.java.debug.core.adapter.handler;
13+
14+
import java.util.Arrays;
15+
import java.util.List;
16+
import java.util.concurrent.CompletableFuture;
17+
18+
import com.microsoft.java.debug.core.DebugException;
19+
import com.microsoft.java.debug.core.DebugUtility;
20+
import com.microsoft.java.debug.core.StackFrameUtility;
21+
import com.microsoft.java.debug.core.adapter.AdapterUtils;
22+
import com.microsoft.java.debug.core.adapter.ErrorCode;
23+
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
24+
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
25+
import com.microsoft.java.debug.core.adapter.variables.StackFrameReference;
26+
import com.microsoft.java.debug.core.protocol.Events;
27+
import com.microsoft.java.debug.core.protocol.Events.UserNotificationEvent.NotificationType;
28+
import com.microsoft.java.debug.core.protocol.Messages.Response;
29+
import com.microsoft.java.debug.core.protocol.Requests;
30+
import com.microsoft.java.debug.core.protocol.Requests.Arguments;
31+
import com.microsoft.java.debug.core.protocol.Requests.Command;
32+
import com.microsoft.java.debug.core.protocol.Requests.RestartFrameArguments;
33+
import com.sun.jdi.StackFrame;
34+
import com.sun.jdi.ThreadReference;
35+
import com.sun.jdi.request.StepRequest;
36+
37+
/**
38+
* Support Eclipse's `Drop To Frame` action, which is restartFrame in VSCode's
39+
* debug.
40+
*/
41+
public class RestartFrameHandler implements IDebugRequestHandler {
42+
43+
@Override
44+
public List<Command> getTargetCommands() {
45+
return Arrays.asList(Requests.Command.RESTARTFRAME);
46+
}
47+
48+
@Override
49+
public CompletableFuture<Response> handle(Command command, Arguments arguments, Response response, IDebugAdapterContext context) {
50+
RestartFrameArguments restartFrameArgs = (RestartFrameArguments) arguments;
51+
StackFrameReference stackFrameReference = (StackFrameReference) context.getRecyclableIdPool().getObjectById(restartFrameArgs.frameId);
52+
53+
if (stackFrameReference == null) {
54+
return AdapterUtils.createAsyncErrorResponse(response, ErrorCode.RESTARTFRAME_FAILURE,
55+
String.format("RestartFrame: cannot find the stack frame with frameID %s", restartFrameArgs.frameId));
56+
}
57+
58+
if (canRestartFrame(context, stackFrameReference)) {
59+
try {
60+
ThreadReference reference = stackFrameReference.getThread();
61+
popStackFrames(context, reference, stackFrameReference.getDepth());
62+
stepInto(context, reference);
63+
} catch (DebugException de) {
64+
context.getProtocolServer().sendEvent(new Events.UserNotificationEvent(NotificationType.ERROR, de.getMessage()));
65+
}
66+
return CompletableFuture.completedFuture(response);
67+
} else {
68+
context.getProtocolServer().sendEvent(new Events.UserNotificationEvent(NotificationType.ERROR, "Current stack frame doesn't support restart."));
69+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("restartframe", stackFrameReference.getThread().uniqueID()));
70+
return AdapterUtils.createAsyncErrorResponse(response, ErrorCode.RESTARTFRAME_FAILURE, "Failed to restart the selected stack frame.");
71+
}
72+
}
73+
74+
private boolean canRestartFrame(IDebugAdapterContext context, StackFrameReference frameReference) {
75+
if (!context.getDebugSession().getVM().canPopFrames()) {
76+
return false;
77+
}
78+
ThreadReference reference = frameReference.getThread();
79+
StackFrame[] frames = context.getStackFrameManager().reloadStackFrames(reference);
80+
81+
// The frame cannot be the bottom one of the call stack:
82+
if (frames.length <= frameReference.getDepth() + 1) {
83+
return false;
84+
}
85+
86+
// Cannot restart frame involved with native call stacks:
87+
for (int i = 0; i <= frameReference.getDepth() + 1; i++) {
88+
if (StackFrameUtility.isNative(frames[i])) {
89+
return false;
90+
}
91+
}
92+
return true;
93+
}
94+
95+
private void popStackFrames(IDebugAdapterContext context, ThreadReference thread, int depth) throws DebugException {
96+
StackFrame[] frames = context.getStackFrameManager().reloadStackFrames(thread);
97+
StackFrameUtility.pop(frames[depth]);
98+
}
99+
100+
private void stepInto(IDebugAdapterContext context, ThreadReference thread) {
101+
StepRequest request = DebugUtility.createStepIntoRequest(thread, context.getStepFilters().classNameFilters);
102+
context.getDebugSession().getEventHub().stepEvents().filter(debugEvent -> request.equals(debugEvent.event.request())).take(1).subscribe(debugEvent -> {
103+
debugEvent.shouldResume = false;
104+
// Have to send two events to keep the UI sync with the step in operations:
105+
context.getProtocolServer().sendEvent(new Events.StoppedEvent("step", thread.uniqueID()));
106+
context.getProtocolServer().sendEvent(new Events.ContinuedEvent(thread.uniqueID()));
107+
});
108+
request.enable();
109+
thread.resume();
110+
}
111+
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Requests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,10 @@ public static class RedefineClassesArguments extends Arguments {
259259

260260
}
261261

262+
public static class RestartFrameArguments extends Arguments {
263+
public int frameId;
264+
}
265+
262266
public static enum Command {
263267
INITIALIZE("initialize", InitializeArguments.class),
264268
LAUNCH("launch", LaunchArguments.class),
@@ -271,6 +275,7 @@ public static enum Command {
271275
STEPOUT("stepOut", StepOutArguments.class),
272276
PAUSE("pause", PauseArguments.class),
273277
STACKTRACE("stackTrace", StackTraceArguments.class),
278+
RESTARTFRAME("restartFrame", RestartFrameArguments.class),
274279
SCOPES("scopes", ScopesArguments.class),
275280
VARIABLES("variables", VariablesArguments.class),
276281
SETVARIABLE("setVariable", SetVariableArguments.class),

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/protocol/Types.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ public static class Capabilities {
215215
public boolean supportsHitConditionalBreakpoints;
216216
public boolean supportsConditionalBreakpoints;
217217
public boolean supportsEvaluateForHovers;
218+
public boolean supportsRestartFrame;
218219
public boolean supportsSetVariable;
219220
public boolean supportsRestartRequest;
220221
public boolean supportTerminateDebuggee;

0 commit comments

Comments
 (0)