Skip to content

Commit 0ffb658

Browse files
committed
[lldb-dap] Creating an API for sending custom dap events from lldb-dap.
Custom DAP events can be detected using https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent. This API allows an lldb python script to send custom events to the DAP client to allow extensions to handle these custom events.
1 parent 14b4356 commit 0ffb658

File tree

8 files changed

+112
-21
lines changed

8 files changed

+112
-21
lines changed

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1230,7 +1230,7 @@ def run_vscode(dbg, args, options):
12301230
def main():
12311231
parser = optparse.OptionParser(
12321232
description=(
1233-
"A testing framework for the Visual Studio Code Debug " "Adaptor protocol"
1233+
"A testing framework for the Visual Studio Code Debug Adaptor protocol"
12341234
)
12351235
)
12361236

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
C_SOURCES := main.c
2+
3+
include Makefile.rules
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""
2+
Test lldb-dap custom-event integration.
3+
"""
4+
5+
import json
6+
7+
from lldbsuite.test.decorators import *
8+
from lldbsuite.test.lldbtest import *
9+
import lldbdap_testcase
10+
11+
12+
class TestDAP_customEvent(lldbdap_testcase.DAPTestCaseBase):
13+
def test_custom_event(self):
14+
"""
15+
Test sending a custom event.
16+
"""
17+
program = self.getBuildArtifact("a.out")
18+
source = "main.c"
19+
custom_event_body = {
20+
"key": 321,
21+
"arr": [True],
22+
}
23+
self.build_and_launch(
24+
program,
25+
stopCommands=[
26+
"lldb-dap custom-event my-custom-event-no-body",
27+
"lldb-dap custom-event my-custom-event '{}'".format(
28+
json.dumps(custom_event_body)
29+
),
30+
],
31+
)
32+
33+
breakpoint_line = line_number(source, "// breakpoint")
34+
35+
self.set_source_breakpoints(source, [breakpoint_line])
36+
self.continue_to_next_stop()
37+
38+
custom_event = self.dap_server.wait_for_event(
39+
filter=["my-custom-event-no-body"]
40+
)
41+
self.assertEquals(custom_event["event"], "my-custom-event-no-body")
42+
self.assertIsNone(custom_event.get("body", None))
43+
44+
custom_event = self.dap_server.wait_for_event(filter=["my-custom-event"])
45+
self.assertEquals(custom_event["event"], "my-custom-event")
46+
self.assertEquals(custom_event["body"], custom_event_body)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <stdio.h>
2+
3+
int main(int argc, char const *argv[]) {
4+
printf("example\n"); // breakpoint 1
5+
return 0;
6+
}

lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
"""
2-
Test lldb-dap startDebugging reverse request
2+
Test lldb-dap start-debugging reverse requests.
33
"""
44

55

6-
import dap_server
76
from lldbsuite.test.decorators import *
87
from lldbsuite.test.lldbtest import *
9-
from lldbsuite.test import lldbutil
108
import lldbdap_testcase
119

1210

@@ -25,7 +23,7 @@ def test_startDebugging(self):
2523
self.set_source_breakpoints(source, [breakpoint_line])
2624
self.continue_to_next_stop()
2725
self.dap_server.request_evaluate(
28-
"`lldb-dap startDebugging attach '{\"pid\":321}'", context="repl"
26+
"`lldb-dap start-debugging attach '{\"pid\":321}'", context="repl"
2927
)
3028

3129
self.continue_to_exit()

lldb/tools/lldb-dap/DAP.cpp

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -863,42 +863,35 @@ int64_t Variables::InsertExpandableVariable(lldb::SBValue variable,
863863
bool StartDebuggingRequestHandler::DoExecute(
864864
lldb::SBDebugger debugger, char **command,
865865
lldb::SBCommandReturnObject &result) {
866-
// Command format like: `startDebugging <launch|attach> <configuration>`
866+
// Command format like: `start-debugging <launch|attach> <configuration>`
867867
if (!command) {
868-
result.SetError("Invalid use of startDebugging");
869-
result.SetStatus(lldb::eReturnStatusFailed);
868+
result.SetError("Invalid use of start-debugging, expected format "
869+
"`start-debugging <launch|attach> <configuration>`.");
870870
return false;
871871
}
872872

873873
if (!command[0] || llvm::StringRef(command[0]).empty()) {
874-
result.SetError("startDebugging request type missing.");
875-
result.SetStatus(lldb::eReturnStatusFailed);
874+
result.SetError("start-debugging request type missing.");
876875
return false;
877876
}
878877

879878
if (!command[1] || llvm::StringRef(command[1]).empty()) {
880-
result.SetError("configuration missing.");
881-
result.SetStatus(lldb::eReturnStatusFailed);
879+
result.SetError("start-debugging debug configuration missing.");
882880
return false;
883881
}
884882

885883
llvm::StringRef request{command[0]};
886884
std::string raw_configuration{command[1]};
887885

888-
int i = 2;
889-
while (command[i]) {
890-
raw_configuration.append(" ").append(command[i]);
891-
}
892-
893886
llvm::Expected<llvm::json::Value> configuration =
894887
llvm::json::parse(raw_configuration);
895888

896889
if (!configuration) {
897890
llvm::Error err = configuration.takeError();
898-
std::string msg =
899-
"Failed to parse json configuration: " + llvm::toString(std::move(err));
891+
std::string msg = "Failed to parse json configuration: " +
892+
llvm::toString(std::move(err)) + "\n\n" +
893+
raw_configuration;
900894
result.SetError(msg.c_str());
901-
result.SetStatus(lldb::eReturnStatusFailed);
902895
return false;
903896
}
904897

@@ -966,6 +959,44 @@ bool ReplModeRequestHandler::DoExecute(lldb::SBDebugger debugger,
966959
return true;
967960
}
968961

962+
// Sends a custom DAP event with an optional body.
963+
//
964+
// See
965+
// https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent
966+
bool CustomDAPEventRequestHandler::DoExecute(
967+
lldb::SBDebugger debugger, char **command,
968+
lldb::SBCommandReturnObject &result) {
969+
// Command format like: `custom-event <name> <body>?`
970+
if (!command || !command[0] || llvm::StringRef(command[0]).empty()) {
971+
result.SetError("Invalid use of custom-event, expected format "
972+
"`custom-event <name> <body>?`.");
973+
return false;
974+
}
975+
976+
llvm::StringRef name{command[0]};
977+
llvm::json::Object event(CreateEventObject(name));
978+
979+
if (command[1] && !llvm::StringRef(command[1]).empty()) {
980+
llvm::StringRef raw_body{command[1]};
981+
982+
llvm::Expected<llvm::json::Value> body = llvm::json::parse(raw_body);
983+
984+
if (!body) {
985+
llvm::Error err = body.takeError();
986+
std::string msg = "Failed to parse custom event body: " +
987+
llvm::toString(std::move(err));
988+
result.SetError(msg.c_str());
989+
return false;
990+
}
991+
992+
event.try_emplace("body", std::move(*body));
993+
}
994+
995+
g_dap.SendJSON(llvm::json::Value(std::move(event)));
996+
result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
997+
return true;
998+
}
999+
9691000
void DAP::SetFrameFormat(llvm::StringRef format) {
9701001
if (format.empty())
9711002
return;

lldb/tools/lldb-dap/DAP.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface {
150150
lldb::SBCommandReturnObject &result) override;
151151
};
152152

153+
struct CustomDAPEventRequestHandler : public lldb::SBCommandPluginInterface {
154+
bool DoExecute(lldb::SBDebugger debugger, char **command,
155+
lldb::SBCommandReturnObject &result) override;
156+
};
157+
153158
struct DAP {
154159
std::string debug_adaptor_path;
155160
InputStream input;

lldb/tools/lldb-dap/lldb-dap.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1629,13 +1629,15 @@ void request_initialize(const llvm::json::Object &request) {
16291629
"lldb-dap", "Commands for managing lldb-dap.");
16301630
if (GetBoolean(arguments, "supportsStartDebuggingRequest", false)) {
16311631
cmd.AddCommand(
1632-
"startDebugging", new StartDebuggingRequestHandler(),
1632+
"start-debugging", new StartDebuggingRequestHandler(),
16331633
"Sends a startDebugging request from the debug adapter to the client "
16341634
"to start a child debug session of the same type as the caller.");
16351635
}
16361636
cmd.AddCommand(
16371637
"repl-mode", new ReplModeRequestHandler(),
16381638
"Get or set the repl behavior of lldb-dap evaluation requests.");
1639+
cmd.AddCommand("custom-event", new CustomDAPEventRequestHandler(),
1640+
"Fires a custom lldb-dap event.");
16391641

16401642
g_dap.progress_event_thread = std::thread(ProgressEventThreadFunction);
16411643

0 commit comments

Comments
 (0)