Skip to content

Commit

Permalink
Make adapters retain last request to make replying to its id easier
Browse files Browse the repository at this point in the history
  • Loading branch information
dd86k committed Aug 30, 2024
1 parent 38ec3c7 commit 6bf13c7
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 43 deletions.
21 changes: 20 additions & 1 deletion source/adapters/base.d
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ enum CloseAction
struct AdapterRequest
{
RequestType type;
/// Request ID. Must be non-zero.
int id;

union
{
Expand Down Expand Up @@ -98,7 +100,7 @@ struct AdapterRequest
/// by the server.
struct AdapterReply
{
RequestType type; // Initial request

}

/// Used to reply an error back to the client, that the request
Expand Down Expand Up @@ -150,6 +152,23 @@ enum EventType
thread,
}

// DAP has these output message types:
// - console : Client UI debug console, informative only
// - important: Important message from debugger
// - stdout : Debuggee stdout message
// - stderr : Debuggee stderr message
// - telemetry: Sent to a telemetry server instead of client
//
// MI has these output message types:
// - ~ : Stdout output
// - & : Command echo
enum EventMessageType
{
stdout,
stderr,

}

struct AdapterEvent
{
EventType type;
Expand Down
53 changes: 24 additions & 29 deletions source/adapters/dap.d
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ class DAPAdapter : Adapter

// Parse JSON into a message
JSONValue j = parseJSON(cast(immutable(char)[])buffer);
request_seq = cast(int)j["seq"].integer; // Must be 32-bit int
AdapterRequest request;
request.id = cast(int)j["seq"].integer; // Must be 32-bit int
string mtype = j["type"].str;
if (mtype != "request")
{
Expand All @@ -98,7 +99,6 @@ class DAPAdapter : Adapter
scope mcommand = pcommand.str(); // Validated before Request.init

logTrace("command: '%s'", mcommand);
AdapterRequest request;
switch (mcommand) {
// Initialize DAP session, server services not required
case "initialize":
Expand Down Expand Up @@ -153,15 +153,25 @@ class DAPAdapter : Adapter
clientcap = " none";
logInfo("Client capabilities:%s", clientcap);

AdapterReply res;
res.type = RequestType.initializaton;
reply(res);
j["command"] = "initialize";

JSONValue jcapabilities;
foreach (ref Capability capability; server.capabilities)
{
if (capability.supported)
jcapabilities[capability.name] = true;
}

if (jcapabilities.isNull() == false)
j["body"] = jcapabilities;

send(j);
goto Lread;
// Client configuration done, server services not required
case "configurationDone":
JSONValue jconfigdone;
jconfigdone["seq"] = current_seq++;
jconfigdone["request_seq"] = request_seq;
jconfigdone["request_seq"] = request.id;
jconfigdone["type"] = "response";
jconfigdone["success"] = true;
jconfigdone["command"] = "configurationDone";
Expand Down Expand Up @@ -213,38 +223,25 @@ class DAPAdapter : Adapter
override
void reply(AdapterReply response)
{
logTrace("Response=%s", response.type);
logTrace("Response=%s", request.type);

JSONValue j;
j["seq"] = current_seq++;
j["request_seq"] = request_seq;
j["request_seq"] = request.id;
j["type"] = "response";
j["success"] = true;

switch (response.type) {
switch (request.type) {
case RequestType.unknown:
break;
case RequestType.initializaton:
j["command"] = "initialize";

JSONValue jcapabilities;
foreach (ref Capability capability; server.capabilities)
{
if (capability.supported)
jcapabilities[capability.name] = true;
}

if (jcapabilities.isNull() == false)
j["body"] = jcapabilities;
break;
case RequestType.launch: // Empty reply bodies
j["command"] = "launch";
break;
case RequestType.attach: // Empty reply bodies
j["command"] = "attach";
break;
default:
throw new Exception(text("Not implemented: ", response.type));
throw new Exception(text("Not implemented: ", request.type));
}

send(j);
Expand All @@ -256,14 +253,11 @@ class DAPAdapter : Adapter
logTrace("Error=%s", error.message);

JSONValue j;

j["seq"] = current_seq++;
j["request_seq"] = request_seq; // todo: match seq
j["request_seq"] = request.id;
j["type"] = "response";
j["success"] = false;
j["body"] = [
"error": error.message
];
j["body"] = [ "error": error.message ];

send(j);
}
Expand Down Expand Up @@ -310,8 +304,9 @@ class DAPAdapter : Adapter
}

private:
AdapterRequest request;
/// Server sequencial ID.
int current_seq = 1;
int request_seq;
RequestType processCreation;

struct ClientCapabilities
Expand Down
41 changes: 28 additions & 13 deletions source/adapters/mi.d
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,6 @@ class MIAdapter : Adapter
goto Lread;
}

// Recognized requests
string requestCommand = args[0];

// TODO: Implement these commands
// - -exec-finish: functionOut
// - -exec-next: nextLine
Expand All @@ -158,9 +155,20 @@ class MIAdapter : Adapter
// - file-exec-and-symbols: set exec and symbols
// - goto: break-insert -t TARGET or exec-jump TARGET

// Command list: gdb/mi/mi-cmds.c
// Filter by recognized requests
AdapterRequest request;
// Commands can come in two flavors: Numbered and unnumbered
//
// Unnumbered is just "-file-exec-and-symbols", this is mostly expected
// for simple workloads, where we are expecting one process.
//
// Numbered has an request ID attached like "1-file-exec-and-symbols",
// this allows (assumingly) the control of multiple processes.
//
// So, a check is performed.
string requestCommand = args[0];

// TODO: (required for Native Debug) numbered requests

// Filtered by recognized requests (Command list: gdb/mi/mi-cmds.c)
switch (requestCommand) {
// -exec-run [ --all | --thread-group N ] [ --start ]
// Start execution of target process.
Expand All @@ -180,15 +188,16 @@ class MIAdapter : Adapter

reply(AdapterError("No executable to run."));
goto Lread;
// Resume process execution.
case "-exec-continue":
request.type = RequestType.go;
return request;
// Terminal process.
case "-exec-abort":
request.type = RequestType.terminate;
return request;
case "-gdb-detach", "detach":
request.type = RequestType.detach;
return request;
// attach PID
// Attach debugger to process via its ID.
case "attach":
if (args.length < 2)
{
Expand All @@ -205,6 +214,10 @@ class MIAdapter : Adapter

request.type = RequestType.attach;
return request;
// Detach from process.
case "-gdb-detach", "detach":
request.type = RequestType.detach;
return request;
case "target":
if (args.length < 2)
{
Expand All @@ -230,7 +243,7 @@ class MIAdapter : Adapter
goto Lread;
// (gdb, lldb) Set target path and symbols as the same
// file-exec-and-symbols PATH
case "file-exec-and-symbols":
case "-file-exec-and-symbols":
if (args.length < 2)
{
reply(AdapterError("Need target executable path"));
Expand All @@ -244,7 +257,7 @@ class MIAdapter : Adapter
// Set target arguments.
case "-exec-arguments":
// If arguments given, set, otherwise, clear.
targetExecArgs(args.length >= 1 ? args[1..$].dup : null);
targetExecArgs(args.length > 1 ? args[1..$].dup : null);
reply(AdapterReply());
goto Lread;
// -environment-cd PATH
Expand Down Expand Up @@ -308,7 +321,7 @@ class MIAdapter : Adapter
override
void reply(AdapterReply msg)
{
switch (msg.type) {
switch (request.type) {
case RequestType.launch:
send("^running");
break;
Expand Down Expand Up @@ -365,14 +378,16 @@ class MIAdapter : Adapter

private:
int miversion;
/// Current request
AdapterRequest request;
}

// Check MI version out of adapter type
int miVersion(AdapterType adp)
{
if (adp < AdapterType.mi || adp > AdapterType.mi4)
return 0;
return adp - AdapterType.mi;
return (adp - AdapterType.mi) + 1;
}
unittest
{
Expand Down
2 changes: 2 additions & 0 deletions source/utils/shell.d
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ unittest
// empty inputs
assert(shellArgs(null) == null);
assert(shellArgs("") == null);
assert(shellArgs(" ") == null);
assert(shellArgs("\t\n") == null);
// spacing
assert(shellArgs("hello") == [ "hello" ]);
assert(shellArgs(" hello") == [ "hello" ]);
Expand Down

0 comments on commit 6bf13c7

Please sign in to comment.