[Lldb-commits] [lldb] 132e57b - Retry of D84974

Walter Erquinigo via lldb-commits lldb-commits at lists.llvm.org
Mon Sep 14 10:45:19 PDT 2020


Author: Walter Erquinigo
Date: 2020-09-14T10:44:13-07:00
New Revision: 132e57bc597bd3f50174b7d286c43f76b47f11c1

URL: https://github.com/llvm/llvm-project/commit/132e57bc597bd3f50174b7d286c43f76b47f11c1
DIFF: https://github.com/llvm/llvm-project/commit/132e57bc597bd3f50174b7d286c43f76b47f11c1.diff

LOG: Retry of D84974

- Fix a small issue caused by a conflicting name (GetObject) on Windows.
  The fix was to rename the internal GetObject function to
  GetNextFunction.

Added: 
    lldb/test/API/tools/lldb-vscode/runInTerminal/Makefile
    lldb/test/API/tools/lldb-vscode/runInTerminal/TestVSCode_runInTerminal.py
    lldb/test/API/tools/lldb-vscode/runInTerminal/main.c

Modified: 
    lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
    lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
    lldb/tools/lldb-vscode/JSONUtils.cpp
    lldb/tools/lldb-vscode/JSONUtils.h
    lldb/tools/lldb-vscode/VSCode.cpp
    lldb/tools/lldb-vscode/VSCode.h
    lldb/tools/lldb-vscode/lldb-vscode.cpp
    lldb/tools/lldb-vscode/package.json

Removed: 
    


################################################################################
diff  --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
index fa5a9c0db1eb..5710751ec34b 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
@@ -282,7 +282,7 @@ def launch(self, program=None, args=None, cwd=None, env=None,
                trace=False, initCommands=None, preRunCommands=None,
                stopCommands=None, exitCommands=None, terminateCommands=None,
                sourcePath=None, debuggerRoot=None, launchCommands=None,
-               sourceMap=None, disconnectAutomatically=True):
+               sourceMap=None, disconnectAutomatically=True, runInTerminal=False):
         '''Sending launch request to vscode
         '''
 
@@ -316,10 +316,16 @@ def cleanup():
             sourcePath=sourcePath,
             debuggerRoot=debuggerRoot,
             launchCommands=launchCommands,
-            sourceMap=sourceMap)
+            sourceMap=sourceMap,
+            runInTerminal=runInTerminal)
         if not (response and response['success']):
             self.assertTrue(response['success'],
                             'launch failed (%s)' % (response['message']))
+        # We need to trigger a request_configurationDone after we've successfully
+        # attached a runInTerminal process to finish initialization.
+        if runInTerminal:
+            self.vscode.request_configurationDone()
+
 
     def build_and_launch(self, program, args=None, cwd=None, env=None,
                          stopOnEntry=False, disableASLR=True,
@@ -327,7 +333,7 @@ def build_and_launch(self, program, args=None, cwd=None, env=None,
                          trace=False, initCommands=None, preRunCommands=None,
                          stopCommands=None, exitCommands=None,
                          terminateCommands=None, sourcePath=None,
-                         debuggerRoot=None):
+                         debuggerRoot=None, runInTerminal=False):
         '''Build the default Makefile target, create the VSCode debug adaptor,
            and launch the process.
         '''
@@ -337,4 +343,4 @@ def build_and_launch(self, program, args=None, cwd=None, env=None,
         self.launch(program, args, cwd, env, stopOnEntry, disableASLR,
                     disableSTDIO, shellExpandArguments, trace,
                     initCommands, preRunCommands, stopCommands, exitCommands,
-                    terminateCommands, sourcePath, debuggerRoot)
+                    terminateCommands, sourcePath, debuggerRoot, runInTerminal=runInTerminal)

diff  --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
index 6b1c1c961b54..834e33ef5c3d 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
@@ -300,12 +300,29 @@ def send_recv(self, command):
         self.send_packet(command)
         done = False
         while not done:
-            response = self.recv_packet(filter_type='response')
-            if response is None:
+            response_or_request = self.recv_packet(filter_type=['response', 'request'])
+            if response_or_request is None:
                 desc = 'no response for "%s"' % (command['command'])
                 raise ValueError(desc)
-            self.validate_response(command, response)
-            return response
+            if response_or_request['type'] == 'response':
+                self.validate_response(command, response_or_request)
+                return response_or_request
+            else:
+                if response_or_request['command'] == 'runInTerminal':
+                    subprocess.Popen(response_or_request['arguments']['args'], 
+                        env=response_or_request['arguments']['env'])
+                    self.send_packet({
+                        "type": "response",
+                        "seq": -1,
+                        "request_seq": response_or_request['seq'],
+                        "success": True,
+                        "command": "runInTerminal",
+                        "body": {}
+                    }, set_sequence=False)
+                else:
+                    desc = 'unkonwn reverse request "%s"' % (response_or_request['command'])
+                    raise ValueError(desc)
+            
         return None
 
     def wait_for_event(self, filter=None, timeout=None):
@@ -599,7 +616,8 @@ def request_launch(self, program, args=None, cwd=None, env=None,
                        trace=False, initCommands=None, preRunCommands=None,
                        stopCommands=None, exitCommands=None,
                        terminateCommands=None ,sourcePath=None,
-                       debuggerRoot=None, launchCommands=None, sourceMap=None):
+                       debuggerRoot=None, launchCommands=None, sourceMap=None,
+                       runInTerminal=False):
         args_dict = {
             'program': program
         }
@@ -638,6 +656,8 @@ def request_launch(self, program, args=None, cwd=None, env=None,
             args_dict['launchCommands'] = launchCommands
         if sourceMap:
             args_dict['sourceMap'] = sourceMap
+        if runInTerminal:
+            args_dict['runInTerminal'] = runInTerminal
         command_dict = {
             'command': 'launch',
             'type': 'request',

diff  --git a/lldb/test/API/tools/lldb-vscode/runInTerminal/Makefile b/lldb/test/API/tools/lldb-vscode/runInTerminal/Makefile
new file mode 100644
index 000000000000..10495940055b
--- /dev/null
+++ b/lldb/test/API/tools/lldb-vscode/runInTerminal/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules

diff  --git a/lldb/test/API/tools/lldb-vscode/runInTerminal/TestVSCode_runInTerminal.py b/lldb/test/API/tools/lldb-vscode/runInTerminal/TestVSCode_runInTerminal.py
new file mode 100644
index 000000000000..6a463dfacc1f
--- /dev/null
+++ b/lldb/test/API/tools/lldb-vscode/runInTerminal/TestVSCode_runInTerminal.py
@@ -0,0 +1,48 @@
+"""
+Test lldb-vscode runInTerminal reverse request
+"""
+
+
+import unittest2
+import vscode
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+import lldbvscode_testcase
+import time
+import os
+
+
+class TestVSCode_runInTerminal(lldbvscode_testcase.VSCodeTestCaseBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    @skipIfRemote
+    def test_runInTerminal(self):
+        '''
+            Tests the "runInTerminal" reverse request. It makes sure that the IDE can
+            launch the inferior with the correct environment variables and arguments.
+        '''
+        program = self.getBuildArtifact("a.out")
+        source = 'main.c'
+        self.build_and_launch(program, stopOnEntry=True, runInTerminal=True, args=["foobar"], env=["FOO=bar"])
+        breakpoint_line = line_number(source, '// breakpoint')
+
+        self.set_source_breakpoints(source, [breakpoint_line])
+        self.continue_to_next_stop()
+
+        # We verify we actually stopped inside the loop
+        counter = int(self.vscode.get_local_variable_value('counter'))
+        self.assertTrue(counter > 0)
+
+        # We verify we were able to set the launch arguments
+        argc = int(self.vscode.get_local_variable_value('argc'))
+        self.assertEqual(argc, 2)
+
+        argv1 = self.vscode.request_evaluate('argv[1]')['body']['result']
+        self.assertIn('foobar', argv1)
+
+        # We verify we were able to set the environment
+        env = self.vscode.request_evaluate('foo')['body']['result']
+        self.assertIn('bar', env)

diff  --git a/lldb/test/API/tools/lldb-vscode/runInTerminal/main.c b/lldb/test/API/tools/lldb-vscode/runInTerminal/main.c
new file mode 100644
index 000000000000..676bd830e657
--- /dev/null
+++ b/lldb/test/API/tools/lldb-vscode/runInTerminal/main.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[]) {
+  const char *foo = getenv("FOO");
+  for (int counter = 1;; counter++) {
+    sleep(1); // breakpoint
+  }
+  return 0;
+}

diff  --git a/lldb/tools/lldb-vscode/JSONUtils.cpp b/lldb/tools/lldb-vscode/JSONUtils.cpp
index 36156ca2c42f..044bfd13ec46 100644
--- a/lldb/tools/lldb-vscode/JSONUtils.cpp
+++ b/lldb/tools/lldb-vscode/JSONUtils.cpp
@@ -998,4 +998,44 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit unit) {
   return llvm::json::Value(std::move(object));
 }
 
+/// See
+/// https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal
+llvm::json::Object
+CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request) {
+  llvm::json::Object reverse_request;
+  reverse_request.try_emplace("type", "request");
+  reverse_request.try_emplace("command", "runInTerminal");
+
+  llvm::json::Object run_in_terminal_args;
+  // This indicates the IDE to open an embedded terminal, instead of opening the
+  // terminal in a new window.
+  run_in_terminal_args.try_emplace("kind", "integrated");
+
+  auto launch_request_arguments = launch_request.getObject("arguments");
+  std::vector<std::string> args = GetStrings(launch_request_arguments, "args");
+  // The program path must be the first entry in the "args" field
+  args.insert(args.begin(),
+              GetString(launch_request_arguments, "program").str());
+  run_in_terminal_args.try_emplace("args", args);
+
+  const auto cwd = GetString(launch_request_arguments, "cwd");
+  if (!cwd.empty())
+    run_in_terminal_args.try_emplace("cwd", cwd);
+
+  // We need to convert the input list of environments variables into a
+  // dictionary
+  std::vector<std::string> envs = GetStrings(launch_request_arguments, "env");
+  llvm::json::Object environment;
+  for (const std::string &env : envs) {
+    size_t index = env.find("=");
+    environment.try_emplace(env.substr(0, index), env.substr(index + 1));
+  }
+  run_in_terminal_args.try_emplace("env",
+                                   llvm::json::Value(std::move(environment)));
+
+  reverse_request.try_emplace(
+      "arguments", llvm::json::Value(std::move(run_in_terminal_args)));
+  return reverse_request;
+}
+
 } // namespace lldb_vscode

diff  --git a/lldb/tools/lldb-vscode/JSONUtils.h b/lldb/tools/lldb-vscode/JSONUtils.h
index df4428f390ba..88cbef9e5fdd 100644
--- a/lldb/tools/lldb-vscode/JSONUtils.h
+++ b/lldb/tools/lldb-vscode/JSONUtils.h
@@ -443,6 +443,18 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
 
 llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit unit);
 
+/// Create a runInTerminal reverse request object
+///
+/// \param[in] launch_request
+///     The original launch_request object whose fields are used to construct
+///     the reverse request object.
+///
+/// \return
+///     A "runInTerminal" JSON object that follows the specification outlined by
+///     Microsoft.
+llvm::json::Object
+CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request);
+
 } // namespace lldb_vscode
 
 #endif

diff  --git a/lldb/tools/lldb-vscode/VSCode.cpp b/lldb/tools/lldb-vscode/VSCode.cpp
index 537cae786863..9450cdf3132a 100644
--- a/lldb/tools/lldb-vscode/VSCode.cpp
+++ b/lldb/tools/lldb-vscode/VSCode.cpp
@@ -38,7 +38,8 @@ VSCode::VSCode()
            {"swift_catch", "Swift Catch", lldb::eLanguageTypeSwift},
            {"swift_throw", "Swift Throw", lldb::eLanguageTypeSwift}}),
       focus_tid(LLDB_INVALID_THREAD_ID), sent_terminated_event(false),
-      stop_at_entry(false), is_attach(false) {
+      stop_at_entry(false), is_attach(false),
+      reverse_request_seq(0), waiting_for_run_in_terminal(false) {
   const char *log_file_path = getenv("LLDBVSCODE_LOG");
 #if defined(_WIN32)
   // Windows opens stdout and stdin in text mode which converts \n to 13,10
@@ -362,4 +363,71 @@ void VSCode::SetTarget(const lldb::SBTarget target) {
   }
 }
 
+PacketStatus VSCode::GetNextObject(llvm::json::Object &object) {
+  std::string json = ReadJSON();
+  if (json.empty())
+    return PacketStatus::EndOfFile;
+
+  llvm::StringRef json_sref(json);
+  llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref);
+  if (!json_value) {
+    auto error = json_value.takeError();
+    if (log) {
+      std::string error_str;
+      llvm::raw_string_ostream strm(error_str);
+      strm << error;
+      strm.flush();
+      *log << "error: failed to parse JSON: " << error_str << std::endl
+           << json << std::endl;
+    }
+    return PacketStatus::JSONMalformed;
+  }
+  object = *json_value->getAsObject();
+  if (!json_value->getAsObject()) {
+    if (log)
+      *log << "error: json packet isn't a object" << std::endl;
+    return PacketStatus::JSONNotObject;
+  }
+  return PacketStatus::Success;
+}
+
+bool VSCode::HandleObject(const llvm::json::Object &object) {
+  const auto packet_type = GetString(object, "type");
+  if (packet_type == "request") {
+    const auto command = GetString(object, "command");
+    auto handler_pos = request_handlers.find(std::string(command));
+    if (handler_pos != request_handlers.end()) {
+      handler_pos->second(object);
+      return true; // Success
+    } else {
+      if (log)
+        *log << "error: unhandled command \"" << command.data() << std::endl;
+      return false; // Fail
+    }
+  }
+  return false;
+}
+
+PacketStatus VSCode::SendReverseRequest(llvm::json::Object request,
+                                        llvm::json::Object &response) {
+  request.try_emplace("seq", ++reverse_request_seq);
+  SendJSON(llvm::json::Value(std::move(request)));
+  while (true) {
+    PacketStatus status = GetNextObject(response);
+    const auto packet_type = GetString(response, "type");
+    if (packet_type == "response")
+      return status;
+    else {
+      // Not our response, we got another packet
+      HandleObject(response);
+    }
+  }
+  return PacketStatus::EndOfFile;
+}
+
+void VSCode::RegisterRequestCallback(std::string request,
+                                     RequestCallback callback) {
+  request_handlers[request] = callback;
+}
+
 } // namespace lldb_vscode

diff  --git a/lldb/tools/lldb-vscode/VSCode.h b/lldb/tools/lldb-vscode/VSCode.h
index 88a0c08de245..28e9eef13d6b 100644
--- a/lldb/tools/lldb-vscode/VSCode.h
+++ b/lldb/tools/lldb-vscode/VSCode.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_TOOLS_LLDB_VSCODE_VSCODE_H
 #define LLDB_TOOLS_LLDB_VSCODE_VSCODE_H
 
+#include <condition_variable>
 #include <iosfwd>
 #include <map>
 #include <set>
@@ -19,6 +20,7 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/JSON.h"
 #include "llvm/Support/raw_ostream.h"
 
 #include "lldb/API/SBAttachInfo.h"
@@ -65,6 +67,15 @@ enum class OutputType { Console, Stdout, Stderr, Telemetry };
 
 enum VSCodeBroadcasterBits { eBroadcastBitStopEventThread = 1u << 0 };
 
+typedef void (*RequestCallback)(const llvm::json::Object &command);
+
+enum class PacketStatus {
+  Success = 0,
+  EndOfFile,
+  JSONMalformed,
+  JSONNotObject
+};
+
 struct VSCode {
   InputStream input;
   OutputStream output;
@@ -91,6 +102,10 @@ struct VSCode {
   bool sent_terminated_event;
   bool stop_at_entry;
   bool is_attach;
+  uint32_t reverse_request_seq;
+  std::map<std::string, RequestCallback> request_handlers;
+  std::condition_variable request_in_terminal_cv;
+  bool waiting_for_run_in_terminal;
   // Keep track of the last stop thread index IDs as threads won't go away
   // unless we send a "thread" event to indicate the thread exited.
   llvm::DenseSet<lldb::tid_t> thread_ids;
@@ -152,6 +167,36 @@ struct VSCode {
   /// Set given target object as a current target for lldb-vscode and start
   /// listeing for its breakpoint events.
   void SetTarget(const lldb::SBTarget target);
+
+  const std::map<std::string, RequestCallback> &GetRequestHandlers();
+
+  PacketStatus GetNextObject(llvm::json::Object &object);
+  bool HandleObject(const llvm::json::Object &object);
+
+  /// Send a Debug Adapter Protocol reverse request to the IDE
+  ///
+  /// \param[in] request
+  ///   The payload of the request to send.
+  ///
+  /// \param[out] response
+  ///   The response of the IDE. It might be undefined if there was an error.
+  ///
+  /// \return
+  ///   A \a PacketStatus object indicating the sucess or failure of the
+  ///   request.
+  PacketStatus SendReverseRequest(llvm::json::Object request,
+                                  llvm::json::Object &response);
+
+  /// Registers a callback handler for a Debug Adapter Protocol request
+  ///
+  /// \param[in] request
+  ///     The name of the request following the Debug Adapter Protocol
+  ///     specification.
+  ///
+  /// \param[in] callback
+  ///     The callback to execute when the given request is triggered by the
+  ///     IDE.
+  void RegisterRequestCallback(std::string request, RequestCallback callback);
 };
 
 extern VSCode g_vsc;

diff  --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp
index 7d7d0f9ebe91..08973ec0f171 100644
--- a/lldb/tools/lldb-vscode/lldb-vscode.cpp
+++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp
@@ -384,7 +384,12 @@ void EventThreadFunction() {
             break;
           case lldb::eStateSuspended:
             break;
-          case lldb::eStateStopped:
+          case lldb::eStateStopped: {
+            if (g_vsc.waiting_for_run_in_terminal) {
+              g_vsc.waiting_for_run_in_terminal = false;
+              g_vsc.request_in_terminal_cv.notify_one();
+            }
+          }
             // Only report a stopped event if the process was not restarted.
             if (!lldb::SBProcess::GetRestartedFromEvent(event)) {
               SendStdOutStdErr(process);
@@ -1374,6 +1379,9 @@ void request_initialize(const llvm::json::Object &request) {
     filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp));
   }
   body.try_emplace("exceptionBreakpointFilters", std::move(filters));
+  // The debug adapter supports launching a debugee in intergrated VSCode
+  // terminal.
+  body.try_emplace("supportsRunInTerminalRequest", true);
   // The debug adapter supports stepping back via the stepBack and
   // reverseContinue requests.
   body.try_emplace("supportsStepBack", false);
@@ -1433,6 +1441,49 @@ void request_initialize(const llvm::json::Object &request) {
   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
 }
 
+void request_runInTerminal(const llvm::json::Object &launch_request,
+                           llvm::json::Object &launch_response) {
+  // We have already created a target that has a valid "program" path to the
+  // executable. We will attach to the next process whose name matches that
+  // of the target's.
+  g_vsc.is_attach = true;
+  lldb::SBAttachInfo attach_info;
+  lldb::SBError error;
+  attach_info.SetWaitForLaunch(true, /*async*/ true);
+  g_vsc.target.Attach(attach_info, error);
+
+  llvm::json::Object reverse_request =
+      CreateRunInTerminalReverseRequest(launch_request);
+  llvm::json::Object reverse_response;
+  lldb_vscode::PacketStatus status =
+      g_vsc.SendReverseRequest(reverse_request, reverse_response);
+  if (status != lldb_vscode::PacketStatus::Success)
+    error.SetErrorString("Process cannot be launched by IDE.");
+
+  if (error.Success()) {
+    // Wait for the attach stop event to happen or for a timeout.
+    g_vsc.waiting_for_run_in_terminal = true;
+    static std::mutex mutex;
+    std::unique_lock<std::mutex> locker(mutex);
+    g_vsc.request_in_terminal_cv.wait_for(locker, std::chrono::seconds(10));
+
+    auto attached_pid = g_vsc.target.GetProcess().GetProcessID();
+    if (attached_pid == LLDB_INVALID_PROCESS_ID)
+      error.SetErrorString("Failed to attach to a process");
+    else
+      SendProcessEvent(Attach);
+  }
+
+  if (error.Fail()) {
+    launch_response["success"] = llvm::json::Value(false);
+    EmplaceSafeString(launch_response, "message",
+                      std::string(error.GetCString()));
+  } else {
+    launch_response["success"] = llvm::json::Value(true);
+    g_vsc.SendJSON(CreateEventObject("initialized"));
+  }
+}
+
 // "LaunchRequest": {
 //   "allOf": [ { "$ref": "#/definitions/Request" }, {
 //     "type": "object",
@@ -1505,6 +1556,12 @@ void request_launch(const llvm::json::Object &request) {
     return;
   }
 
+  if (GetBoolean(arguments, "runInTerminal", false)) {
+    request_runInTerminal(request, response);
+    g_vsc.SendJSON(llvm::json::Value(std::move(response)));
+    return;
+  }
+
   // Instantiate a launch info instance for the target.
   auto launch_info = g_vsc.target.GetLaunchInfo();
 
@@ -2831,39 +2888,35 @@ void request__testGetTargetBreakpoints(const llvm::json::Object &request) {
   g_vsc.SendJSON(llvm::json::Value(std::move(response)));
 }
 
-const std::map<std::string, RequestCallback> &GetRequestHandlers() {
-#define REQUEST_CALLBACK(name)                                                 \
-  { #name, request_##name }
-  static std::map<std::string, RequestCallback> g_request_handlers = {
-      // VSCode Debug Adaptor requests
-      REQUEST_CALLBACK(attach),
-      REQUEST_CALLBACK(completions),
-      REQUEST_CALLBACK(continue),
-      REQUEST_CALLBACK(configurationDone),
-      REQUEST_CALLBACK(disconnect),
-      REQUEST_CALLBACK(evaluate),
-      REQUEST_CALLBACK(exceptionInfo),
-      REQUEST_CALLBACK(getCompileUnits),
-      REQUEST_CALLBACK(initialize),
-      REQUEST_CALLBACK(launch),
-      REQUEST_CALLBACK(next),
-      REQUEST_CALLBACK(pause),
-      REQUEST_CALLBACK(scopes),
-      REQUEST_CALLBACK(setBreakpoints),
-      REQUEST_CALLBACK(setExceptionBreakpoints),
-      REQUEST_CALLBACK(setFunctionBreakpoints),
-      REQUEST_CALLBACK(setVariable),
-      REQUEST_CALLBACK(source),
-      REQUEST_CALLBACK(stackTrace),
-      REQUEST_CALLBACK(stepIn),
-      REQUEST_CALLBACK(stepOut),
-      REQUEST_CALLBACK(threads),
-      REQUEST_CALLBACK(variables),
-      // Testing requests
-      REQUEST_CALLBACK(_testGetTargetBreakpoints),
-  };
-#undef REQUEST_CALLBACK
-  return g_request_handlers;
+void RegisterRequestCallbacks() {
+  g_vsc.RegisterRequestCallback("attach", request_attach);
+  g_vsc.RegisterRequestCallback("completions", request_completions);
+  g_vsc.RegisterRequestCallback("continue", request_continue);
+  g_vsc.RegisterRequestCallback("configurationDone", request_configurationDone);
+  g_vsc.RegisterRequestCallback("disconnect", request_disconnect);
+  g_vsc.RegisterRequestCallback("evaluate", request_evaluate);
+  g_vsc.RegisterRequestCallback("exceptionInfo", request_exceptionInfo);
+  g_vsc.RegisterRequestCallback("getCompileUnits", request_getCompileUnits);
+  g_vsc.RegisterRequestCallback("initialize", request_initialize);
+  g_vsc.RegisterRequestCallback("launch", request_launch);
+  g_vsc.RegisterRequestCallback("next", request_next);
+  g_vsc.RegisterRequestCallback("pause", request_pause);
+  g_vsc.RegisterRequestCallback("scopes", request_scopes);
+  g_vsc.RegisterRequestCallback("setBreakpoints", request_setBreakpoints);
+  g_vsc.RegisterRequestCallback("setExceptionBreakpoints",
+                                request_setExceptionBreakpoints);
+  g_vsc.RegisterRequestCallback("setFunctionBreakpoints",
+                                request_setFunctionBreakpoints);
+  g_vsc.RegisterRequestCallback("setVariable", request_setVariable);
+  g_vsc.RegisterRequestCallback("source", request_source);
+  g_vsc.RegisterRequestCallback("stackTrace", request_stackTrace);
+  g_vsc.RegisterRequestCallback("stepIn", request_stepIn);
+  g_vsc.RegisterRequestCallback("stepOut", request_stepOut);
+  g_vsc.RegisterRequestCallback("threads", request_threads);
+  g_vsc.RegisterRequestCallback("variables", request_variables);
+  // Testing requests
+  g_vsc.RegisterRequestCallback("_testGetTargetBreakpoints",
+                                request__testGetTargetBreakpoints);
 }
 
 } // anonymous namespace
@@ -2895,6 +2948,8 @@ int main(int argc, char *argv[]) {
   // Initialize LLDB first before we do anything.
   lldb::SBDebugger::Initialize();
 
+  RegisterRequestCallbacks();
+
   int portno = -1;
 
   LLDBVSCodeOptTable T;
@@ -2937,49 +2992,17 @@ int main(int argc, char *argv[]) {
     g_vsc.output.descriptor =
         StreamDescriptor::from_file(fileno(stdout), false);
   }
-  auto request_handlers = GetRequestHandlers();
   uint32_t packet_idx = 0;
   while (!g_vsc.sent_terminated_event) {
-    std::string json = g_vsc.ReadJSON();
-    if (json.empty())
+    llvm::json::Object object;
+    lldb_vscode::PacketStatus status = g_vsc.GetObject(object);
+    if (status == lldb_vscode::PacketStatus::EndOfFile)
       break;
+    if (status != lldb_vscode::PacketStatus::Success)
+      return 1; // Fatal error
 
-    llvm::StringRef json_sref(json);
-    llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref);
-    if (!json_value) {
-      auto error = json_value.takeError();
-      if (g_vsc.log) {
-        std::string error_str;
-        llvm::raw_string_ostream strm(error_str);
-        strm << error;
-        strm.flush();
-
-        *g_vsc.log << "error: failed to parse JSON: " << error_str << std::endl
-                   << json << std::endl;
-      }
-      return 1;
-    }
-
-    auto object = json_value->getAsObject();
-    if (!object) {
-      if (g_vsc.log)
-        *g_vsc.log << "error: json packet isn't a object" << std::endl;
+    if (!g_vsc.HandleObject(object))
       return 1;
-    }
-
-    const auto packet_type = GetString(object, "type");
-    if (packet_type == "request") {
-      const auto command = GetString(object, "command");
-      auto handler_pos = request_handlers.find(std::string(command));
-      if (handler_pos != request_handlers.end()) {
-        handler_pos->second(*object);
-      } else {
-        if (g_vsc.log)
-          *g_vsc.log << "error: unhandled command \"" << command.data()
-                     << std::endl;
-        return 1;
-      }
-    }
     ++packet_idx;
   }
 

diff  --git a/lldb/tools/lldb-vscode/package.json b/lldb/tools/lldb-vscode/package.json
index 29ca06dd17d6..9077ab51dd7f 100644
--- a/lldb/tools/lldb-vscode/package.json
+++ b/lldb/tools/lldb-vscode/package.json
@@ -175,6 +175,11 @@
 								"type": "array",
 								"description": "Commands executed at the end of debugging session.",
 								"default": []
+							},
+							"runInTerminal": {
+								"type": "boolean",
+								"description": "Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs",
+								"default": false
 							}
 						}
 					},


        


More information about the lldb-commits mailing list