[Lldb-commits] [lldb] [lldb-dap] Creating an API for sending custom dap events from lldb-dap. (PR #112384)

John Harrison via lldb-commits lldb-commits at lists.llvm.org
Tue Oct 15 08:50:12 PDT 2024


https://github.com/ashgti created https://github.com/llvm/llvm-project/pull/112384

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.

>From 0ffb658030e1ec70545115bd32e6e53c9a486969 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Mon, 14 Oct 2024 14:52:51 -0700
Subject: [PATCH] [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.
---
 .../test/tools/lldb-dap/dap_server.py         |  2 +-
 .../API/tools/lldb-dap/custom-event/Makefile  |  3 +
 .../custom-event/TestDAP_customEvent.py       | 46 ++++++++++++++
 .../API/tools/lldb-dap/custom-event/main.c    |  6 ++
 .../startDebugging/TestDAP_startDebugging.py  |  6 +-
 lldb/tools/lldb-dap/DAP.cpp                   | 61 ++++++++++++++-----
 lldb/tools/lldb-dap/DAP.h                     |  5 ++
 lldb/tools/lldb-dap/lldb-dap.cpp              |  4 +-
 8 files changed, 112 insertions(+), 21 deletions(-)
 create mode 100644 lldb/test/API/tools/lldb-dap/custom-event/Makefile
 create mode 100644 lldb/test/API/tools/lldb-dap/custom-event/TestDAP_customEvent.py
 create mode 100644 lldb/test/API/tools/lldb-dap/custom-event/main.c

diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
index b095171d8fd1a4..a43dd1aa7b9496 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
@@ -1230,7 +1230,7 @@ def run_vscode(dbg, args, options):
 def main():
     parser = optparse.OptionParser(
         description=(
-            "A testing framework for the Visual Studio Code Debug " "Adaptor protocol"
+            "A testing framework for the Visual Studio Code Debug Adaptor protocol"
         )
     )
 
diff --git a/lldb/test/API/tools/lldb-dap/custom-event/Makefile b/lldb/test/API/tools/lldb-dap/custom-event/Makefile
new file mode 100644
index 00000000000000..10495940055b63
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/custom-event/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/tools/lldb-dap/custom-event/TestDAP_customEvent.py b/lldb/test/API/tools/lldb-dap/custom-event/TestDAP_customEvent.py
new file mode 100644
index 00000000000000..2ae02b09c9f0fc
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/custom-event/TestDAP_customEvent.py
@@ -0,0 +1,46 @@
+"""
+Test lldb-dap custom-event integration.
+"""
+
+import json
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+import lldbdap_testcase
+
+
+class TestDAP_customEvent(lldbdap_testcase.DAPTestCaseBase):
+    def test_custom_event(self):
+        """
+        Test sending a custom event.
+        """
+        program = self.getBuildArtifact("a.out")
+        source = "main.c"
+        custom_event_body = {
+            "key": 321,
+            "arr": [True],
+        }
+        self.build_and_launch(
+            program,
+            stopCommands=[
+                "lldb-dap custom-event my-custom-event-no-body",
+                "lldb-dap custom-event my-custom-event '{}'".format(
+                    json.dumps(custom_event_body)
+                ),
+            ],
+        )
+
+        breakpoint_line = line_number(source, "// breakpoint")
+
+        self.set_source_breakpoints(source, [breakpoint_line])
+        self.continue_to_next_stop()
+
+        custom_event = self.dap_server.wait_for_event(
+            filter=["my-custom-event-no-body"]
+        )
+        self.assertEquals(custom_event["event"], "my-custom-event-no-body")
+        self.assertIsNone(custom_event.get("body", None))
+
+        custom_event = self.dap_server.wait_for_event(filter=["my-custom-event"])
+        self.assertEquals(custom_event["event"], "my-custom-event")
+        self.assertEquals(custom_event["body"], custom_event_body)
diff --git a/lldb/test/API/tools/lldb-dap/custom-event/main.c b/lldb/test/API/tools/lldb-dap/custom-event/main.c
new file mode 100644
index 00000000000000..27bc22b94794b6
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/custom-event/main.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(int argc, char const *argv[]) {
+  printf("example\n"); // breakpoint 1
+  return 0;
+}
diff --git a/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py b/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py
index fd48e69cae5e25..fd452d91e472bd 100644
--- a/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py
+++ b/lldb/test/API/tools/lldb-dap/startDebugging/TestDAP_startDebugging.py
@@ -1,12 +1,10 @@
 """
-Test lldb-dap startDebugging reverse request
+Test lldb-dap start-debugging reverse requests.
 """
 
 
-import dap_server
 from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
 import lldbdap_testcase
 
 
@@ -25,7 +23,7 @@ def test_startDebugging(self):
         self.set_source_breakpoints(source, [breakpoint_line])
         self.continue_to_next_stop()
         self.dap_server.request_evaluate(
-            "`lldb-dap startDebugging attach '{\"pid\":321}'", context="repl"
+            "`lldb-dap start-debugging attach '{\"pid\":321}'", context="repl"
         )
 
         self.continue_to_exit()
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 6012ee52110b73..b8887ac367f44f 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -863,42 +863,35 @@ int64_t Variables::InsertExpandableVariable(lldb::SBValue variable,
 bool StartDebuggingRequestHandler::DoExecute(
     lldb::SBDebugger debugger, char **command,
     lldb::SBCommandReturnObject &result) {
-  // Command format like: `startDebugging <launch|attach> <configuration>`
+  // Command format like: `start-debugging <launch|attach> <configuration>`
   if (!command) {
-    result.SetError("Invalid use of startDebugging");
-    result.SetStatus(lldb::eReturnStatusFailed);
+    result.SetError("Invalid use of start-debugging, expected format "
+                    "`start-debugging <launch|attach> <configuration>`.");
     return false;
   }
 
   if (!command[0] || llvm::StringRef(command[0]).empty()) {
-    result.SetError("startDebugging request type missing.");
-    result.SetStatus(lldb::eReturnStatusFailed);
+    result.SetError("start-debugging request type missing.");
     return false;
   }
 
   if (!command[1] || llvm::StringRef(command[1]).empty()) {
-    result.SetError("configuration missing.");
-    result.SetStatus(lldb::eReturnStatusFailed);
+    result.SetError("start-debugging debug configuration missing.");
     return false;
   }
 
   llvm::StringRef request{command[0]};
   std::string raw_configuration{command[1]};
 
-  int i = 2;
-  while (command[i]) {
-    raw_configuration.append(" ").append(command[i]);
-  }
-
   llvm::Expected<llvm::json::Value> configuration =
       llvm::json::parse(raw_configuration);
 
   if (!configuration) {
     llvm::Error err = configuration.takeError();
-    std::string msg =
-        "Failed to parse json configuration: " + llvm::toString(std::move(err));
+    std::string msg = "Failed to parse json configuration: " +
+                      llvm::toString(std::move(err)) + "\n\n" +
+                      raw_configuration;
     result.SetError(msg.c_str());
-    result.SetStatus(lldb::eReturnStatusFailed);
     return false;
   }
 
@@ -966,6 +959,44 @@ bool ReplModeRequestHandler::DoExecute(lldb::SBDebugger debugger,
   return true;
 }
 
+// Sends a custom DAP event with an optional body.
+//
+// See
+// https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent
+bool CustomDAPEventRequestHandler::DoExecute(
+    lldb::SBDebugger debugger, char **command,
+    lldb::SBCommandReturnObject &result) {
+  // Command format like: `custom-event <name> <body>?`
+  if (!command || !command[0] || llvm::StringRef(command[0]).empty()) {
+    result.SetError("Invalid use of custom-event, expected format "
+                    "`custom-event <name> <body>?`.");
+    return false;
+  }
+
+  llvm::StringRef name{command[0]};
+  llvm::json::Object event(CreateEventObject(name));
+
+  if (command[1] && !llvm::StringRef(command[1]).empty()) {
+    llvm::StringRef raw_body{command[1]};
+
+    llvm::Expected<llvm::json::Value> body = llvm::json::parse(raw_body);
+
+    if (!body) {
+      llvm::Error err = body.takeError();
+      std::string msg = "Failed to parse custom event body: " +
+                        llvm::toString(std::move(err));
+      result.SetError(msg.c_str());
+      return false;
+    }
+
+    event.try_emplace("body", std::move(*body));
+  }
+
+  g_dap.SendJSON(llvm::json::Value(std::move(event)));
+  result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
+  return true;
+}
+
 void DAP::SetFrameFormat(llvm::StringRef format) {
   if (format.empty())
     return;
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index f4fdec6e895ad1..92108f8bbe86c3 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -150,6 +150,11 @@ struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface {
                  lldb::SBCommandReturnObject &result) override;
 };
 
+struct CustomDAPEventRequestHandler : public lldb::SBCommandPluginInterface {
+  bool DoExecute(lldb::SBDebugger debugger, char **command,
+                 lldb::SBCommandReturnObject &result) override;
+};
+
 struct DAP {
   std::string debug_adaptor_path;
   InputStream input;
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index c5c4b09f15622b..d3adc8f7fbcd35 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -1629,13 +1629,15 @@ void request_initialize(const llvm::json::Object &request) {
       "lldb-dap", "Commands for managing lldb-dap.");
   if (GetBoolean(arguments, "supportsStartDebuggingRequest", false)) {
     cmd.AddCommand(
-        "startDebugging", new StartDebuggingRequestHandler(),
+        "start-debugging", new StartDebuggingRequestHandler(),
         "Sends a startDebugging request from the debug adapter to the client "
         "to start a child debug session of the same type as the caller.");
   }
   cmd.AddCommand(
       "repl-mode", new ReplModeRequestHandler(),
       "Get or set the repl behavior of lldb-dap evaluation requests.");
+  cmd.AddCommand("custom-event", new CustomDAPEventRequestHandler(),
+                 "Fires a custom lldb-dap event.");
 
   g_dap.progress_event_thread = std::thread(ProgressEventThreadFunction);
 



More information about the lldb-commits mailing list