Skip to content

Commit

Permalink
dap: Add stopped event, continue request, and clean server code a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
dd86k committed Oct 14, 2024
1 parent a732103 commit 78fc679
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 63 deletions.
6 changes: 5 additions & 1 deletion source/adapter/base.d
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,17 @@ abstract class Adapter
return transport.name();
}

// Send data to client.
// Send a message to client.
void send(ubyte[] data)
{
// TODO: Consider mutex over transport *if* data starts getting mangled
// Under Phobos, standard streams have locking implemented, but
// when adapters starts with other transport medias, it may be
// interesting to use a mutex.
logTrace("Sending %u bytes", data.length);
transport.send(data);
}
// Send a message to client.
void send(const(char)[] data)
{
send(cast(ubyte[])data);
Expand Down
94 changes: 71 additions & 23 deletions source/adapter/dap.d
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,31 @@ import ddlogger;
// Then, server can call something like "addSession" once it supports
// multi-sessions.

private
string eventStoppedReasonString(AdapterEventStoppedReason reason)
{
final switch (reason) with (AdapterEventStoppedReason) {
case step:
return "step";
case breakpoint:
return "breakpoint";
case exception:
return "exception";
case pause:
return "pause";
case entry:
return "entry";
case goto_:
return "goto";
case functionBreakpoint:
return "function breakpoint";
case dataBreakpoint:
return "data breakpoint";
case instructionBreakpoint:
return "instruction breakpoint";
}
}

private
struct Capability
{
Expand Down Expand Up @@ -165,39 +190,43 @@ class DAPAdapter : Adapter
send(jconfigdone);
goto Lread;
case "launch":
processCreation = request.type = AdapterRequestType.launch;
request.type = AdapterRequestType.launch;
JSONValue jargs;
required(j, "arguments", jargs);
required(jargs, "path", request.launchOptions.path);
break;
case "attach":
processCreation = request.type = AdapterRequestType.attach;
request.type = AdapterRequestType.attach;
JSONValue jargs;
required(j, "arguments", jargs);
required(jargs, "pid", request.attachOptions.pid);
break;
case "continue":
request.type = AdapterRequestType.continue_;
JSONValue jargs;
required(j, "arguments", jargs);
required(jargs, "threadId", request.continueOptions.tid);
break;
case "disconnect":
// If launched, close debuggee.
// If attached, detach. Unless terminateDebuggee:true specified.
// "the debug adapter must terminate the debuggee if it was started
// with the launch request. If an attach request was used to connect
// to the debuggee, then the debug adapter must not terminate the debuggee."
request.type = AdapterRequestType.close;
switch (processCreation) {
case AdapterRequestType.attach:
if (const(JSONValue) *pjdisconnect = "arguments" in j)
{
bool kill; // Defaults to false
optional(pjdisconnect, "terminateDebuggee", kill);
with (CloseAction) request.closeOptions.action = kill ? terminate : detach;
}
else
{
request.closeOptions.action = CloseAction.detach;
}
break;
case AdapterRequestType.launch:
request.closeOptions.action = CloseAction.terminate;
break;
default:
request.closeOptions.action = CloseAction.nothing;
if (const(JSONValue) *pjdisconnect = "arguments" in j)
{
// "Indicates whether the debuggee should be terminated when the
// debugger is disconnected.
// If unspecified, the debug adapter is free to do whatever it
// thinks is best. The attribute is only honored by a debug
// adapter if the corresponding capability `supportTerminateDebuggee` is true."
optional(pjdisconnect, "terminateDebuggee", request.closeOptions.terminate);
// "Indicates whether the debuggee should stay suspended when the
// debugger is disconnected.
// If unspecified, the debuggee should resume execution. The
// attribute is only honored by a debug adapter if the corresponding
// capability `supportSuspendDebuggee` is true."
// TODO: bool suspendDebuggee (optional)
// TODO: bool restart (optional)
}
break;
default:
Expand Down Expand Up @@ -284,6 +313,26 @@ class DAPAdapter : Adapter
"": ""
];
break;
case stopped:
string reason = void;
final switch (event.stopped.reason) with (AdapterEventStoppedReason) {
case step: reason = "step"; break;
case breakpoint: reason = "breakpoint"; break;
case exception: reason = "exception"; break;
case pause: reason = "pause"; break;
case entry: reason = "entry"; break;
case goto_: reason = "goto"; break;
case functionBreakpoint: reason = "function breakpoint"; break;
case dataBreakpoint: reason = "data breakpoint"; break;
case instructionBreakpoint: reason = "instruction breakpoint"; break;
}
j["reason"] = reason;
j["description"] = event.stopped.description;
//j["threadId"] = reason;
break;
case exited:
j["exitCode"] = event.exited.code;
break;
default:
throw new Exception(text("Event unimplemented: ", event.type));
}
Expand Down Expand Up @@ -311,7 +360,6 @@ private:
// TODO: Consider updating seq atomically
/// Server sequencial ID.
int current_seq = 1;
AdapterRequestType processCreation;

struct ClientCapabilities
{
Expand Down
14 changes: 2 additions & 12 deletions source/adapter/types.d
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ enum AdapterRequestType
/// Kill process.
terminate,

/// Close debugger and closes debuggee if running.
/// Close debugger and close debuggee if still running.
close,
}

Expand All @@ -41,16 +41,6 @@ enum OptionType
reserved
}

/// What should the server do on a closing request?
///
/// Used internally.
enum CloseAction
{
nothing,
terminate,
detach,
}

struct AdapterRequest
{
/// Request type.
Expand Down Expand Up @@ -80,7 +70,7 @@ struct AdapterRequest

struct RequestCloseOptions
{
CloseAction action;
bool terminate; /// Optional: If launched, terminate process.
}
RequestCloseOptions closeOptions;
}
Expand Down
3 changes: 0 additions & 3 deletions source/debugger/base.d
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ module debugger.base;

import adapter.types : AdapterEvent;

// TODO: BridgeDebugger
// Basically just passes DAP/MI requests to debugger via transport.

struct ThreadInfo
{
int id;
Expand Down
31 changes: 7 additions & 24 deletions source/server.d
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,6 @@ Lrequest:
switch (request.type) {
// Launch process with debugger
case AdapterRequestType.launch:
if (debuggerType)
{
adapter.reply(AdapterError(messageDebuggerActive));
goto Lrequest;
}

with (request.launchOptions) try debugger.launch(path, null, null);
catch (Exception ex)
{
Expand All @@ -140,12 +134,6 @@ Lrequest:
break;
// Attach debugger to process
case AdapterRequestType.attach:
if (debuggerType)
{
adapter.reply(AdapterError(messageDebuggerActive));
goto Lrequest;
}

with (request.attachOptions) try debugger.attach(pid);
catch (Exception ex)
{
Expand All @@ -158,17 +146,18 @@ Lrequest:
break;
// Continue
case AdapterRequestType.continue_:
try debugger.continue_();
catch (Exception ex)
{
adapter.reply(AdapterError(ex.msg));
goto Lrequest;
}

adapter.reply(AdapterReply());
eventThread.start();
break;
// Detach debugger from process
case AdapterRequestType.detach:
if (debuggerType == AdapterRequestType.unknown) // Nothing to detach from
{
adapter.reply(AdapterError(messageDebuggerUnactive));
goto Lrequest;
}

try debugger.detach();
catch (Exception ex)
{
Expand All @@ -182,12 +171,6 @@ Lrequest:
break;
// Terminate process
case AdapterRequestType.terminate:
if (debuggerType == AdapterRequestType.unknown) // Nothing to terminate
{
adapter.reply(AdapterError(messageDebuggerUnactive));
goto Lrequest;
}

try debugger.terminate();
catch (Exception ex)
{
Expand Down

0 comments on commit 78fc679

Please sign in to comment.