llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

<details>
<summary>Changes</summary>

In #<!-- -->128943, we decided that the VS Code extension should use LLDB's 
platform abstraction to power the process picker. The benefits of this approach 
are that it's cross platform and can support listing remote processes when 
connected to a platform server.

In preparation for that, this PR adds a `--list-processes` flag. The host 
platform is used by default. The `--platform` and `--platform-url` flags allow 
specifying and connecting to a (remote) platform.

The result is a JSON array printed to stdout. Here's what that looks like:

```
  [ { "pid": number, "name": string, "triple": string,
      "executable": string, "user": number }, ... ]
```

Keys other than `pid` are optional. A follow-up will teach the VS Code 
extension to use this as input for the process picker.

---
Full diff: https://github.com/llvm/llvm-project/pull/197330.diff


4 Files Affected:

- (modified) lldb/test/Shell/DAP/TestHelp.test (+3) 
- (added) lldb/test/Shell/DAP/TestListProcesses.test (+25) 
- (modified) lldb/tools/lldb-dap/tool/Options.td (+23) 
- (modified) lldb/tools/lldb-dap/tool/lldb-dap.cpp (+104) 


``````````diff
diff --git a/lldb/test/Shell/DAP/TestHelp.test 
b/lldb/test/Shell/DAP/TestHelp.test
index 6033cf15e3835..08afa414da503 100644
--- a/lldb/test/Shell/DAP/TestHelp.test
+++ b/lldb/test/Shell/DAP/TestHelp.test
@@ -3,6 +3,9 @@
 # CHECK: -g
 # CHECK: --help
 # CHECK: -h
+# CHECK: --list-processes
+# CHECK: --platform
+# CHECK: --platform-url
 # CHECK: --repl-mode
 # CHECK: --version
 # CHECK: --wait-for-debugger
diff --git a/lldb/test/Shell/DAP/TestListProcesses.test 
b/lldb/test/Shell/DAP/TestListProcesses.test
new file mode 100644
index 0000000000000..7008dd4272946
--- /dev/null
+++ b/lldb/test/Shell/DAP/TestListProcesses.test
@@ -0,0 +1,25 @@
+# Verify that `lldb-dap --list-processes` emits a JSON array on stdout with at
+# least one entry carrying a `pid` field, and that common optional keys
+# (`name`, `triple`) appear in the output.
+
+# RUN: lldb-dap --list-processes | FileCheck %s --check-prefix=HOST
+
+# HOST: [{
+# HOST-DAG: "pid":{{[0-9]+}}
+# HOST-DAG: "name":
+# HOST-DAG: "triple":
+
+# Selecting an unknown platform should fail with a clear error message on
+# stderr and a non-zero exit status.
+
+# RUN: not lldb-dap --list-processes --platform does-not-exist 2>&1 \
+# RUN:   | FileCheck %s --check-prefix=BAD-PLATFORM
+
+# BAD-PLATFORM: unknown platform: does-not-exist
+
+# --platform-url without --platform should be rejected up front.
+
+# RUN: not lldb-dap --list-processes --platform-url connect://foo:1234 2>&1 \
+# RUN:   | FileCheck %s --check-prefix=URL-WITHOUT-PLATFORM
+
+# URL-WITHOUT-PLATFORM: --platform-url requires --platform
diff --git a/lldb/tools/lldb-dap/tool/Options.td 
b/lldb/tools/lldb-dap/tool/Options.td
index 048021cd4457f..cbf73a6d1387b 100644
--- a/lldb/tools/lldb-dap/tool/Options.td
+++ b/lldb/tools/lldb-dap/tool/Options.td
@@ -94,4 +94,27 @@ def client
       HelpText<
           "Use lldb-dap as a launcher for a curated number of DAP client.">;
 
+def list_processes
+    : F<"list-processes">,
+      HelpText<
+          "List the processes visible to LLDB's platform as JSON on stdout, "
+          "then exit. Use --platform and --platform-url to select a non-host "
+          "platform. The emitted array contains objects with the keys 'pid', "
+          "'name', 'triple', 'user', and 'executable'.">;
+
+def platform_name
+    : S<"platform">,
+      MetaVarName<"<name>">,
+      HelpText<
+          "The name of the LLDB platform to select (e.g. 'host', "
+          "'remote-linux'). Used in combination with non-session modes such as 
"
+          "--list-processes.">;
+
+def platform_url
+    : S<"platform-url">,
+      MetaVarName<"<url>">,
+      HelpText<
+          "Connect the selected platform to the given URL before performing "
+          "the requested operation. Requires --platform.">;
+
 def REM : R<["--"], "">;
diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp 
b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
index f9a97563e394c..735e69ce26c1a 100644
--- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
@@ -12,9 +12,13 @@
 #include "EventHelper.h"
 #include "Handler/RequestHandler.h"
 #include "Handler/ResponseHandler.h"
+#include "LLDBUtils.h"
 #include "RunInTerminal.h"
 #include "Transport.h"
 #include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBPlatform.h"
+#include "lldb/API/SBProcessInfo.h"
+#include "lldb/API/SBProcessInfoList.h"
 #include "lldb/API/SBStream.h"
 #include "lldb/Host/Config.h"
 #include "lldb/Host/File.h"
@@ -41,6 +45,7 @@
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/JSON.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/PrettyStackTrace.h"
 #include "llvm/Support/Signals.h"
@@ -182,6 +187,97 @@ static llvm::Error LaunchClient(const 
llvm::opt::InputArgList &args) {
   return ClientLauncher::GetLauncher(*client)->Launch(launch_args);
 }
 
+/// Handles `--list-processes`: print the processes visible to the selected
+/// platform as a JSON array on stdout, then exit.
+///
+/// The JSON shape is intentionally minimal and stable:
+///
+///   [ { "pid": number, "name": string, "triple": string,
+///       "user": number, "executable": string }, ... ]
+///
+/// Fields other than `pid` are omitted if not available.
+static llvm::Error ListProcesses(const llvm::opt::InputArgList &args) {
+  llvm::StringRef platform_name = args.getLastArgValue(OPT_platform_name);
+  llvm::StringRef platform_url = args.getLastArgValue(OPT_platform_url);
+
+  if (!platform_url.empty() && platform_name.empty())
+    return llvm::createStringError("--platform-url requires --platform");
+
+  if (lldb::SBError init_error =
+          lldb::SBDebugger::InitializeWithErrorHandling();
+      init_error.Fail())
+    return llvm::createStringError(llvm::formatv(
+        "failed to initialize lldb: {0}", init_error.GetCString()));
+  llvm::scope_exit cleanup{[]() { lldb::SBDebugger::Terminate(); }};
+
+  lldb::SBDebugger debugger =
+      lldb::SBDebugger::Create(/*source_init_files=*/false);
+  if (!debugger.IsValid())
+    return llvm::createStringError("failed to create debugger");
+
+  lldb::SBPlatform platform =
+      platform_name.empty() ? lldb::SBPlatform::GetHostPlatform()
+                            : lldb::SBPlatform(platform_name.str().c_str());
+  if (!platform.IsValid())
+    return llvm::createStringError(
+        llvm::formatv("unknown platform: {0}", platform_name));
+
+  bool connected = false;
+  if (!platform_url.empty()) {
+    lldb::SBPlatformConnectOptions opts(platform_url.str().c_str());
+    lldb::SBError error = platform.ConnectRemote(opts);
+    if (error.Fail())
+      return llvm::createStringError(
+          llvm::formatv("failed to connect to platform {0} at {1}: {2}",
+                        platform.GetName(), platform_url, error.GetCString()));
+    connected = true;
+  }
+  llvm::scope_exit disconnect{[&]() {
+    if (connected)
+      platform.DisconnectRemote();
+  }};
+
+  lldb::SBError error;
+  lldb::SBProcessInfoList processes = platform.GetAllProcesses(error);
+  if (error.Fail()) {
+    if (!platform.IsConnected() && platform_url.empty())
+      return llvm::createStringError(
+          llvm::formatv("platform {0} is not connected; pass --platform-url "
+                        "to connect to a remote platform",
+                        platform.GetName()));
+    return llvm::createStringError(
+        llvm::formatv("failed to list processes: {0}", error.GetCString()));
+  }
+
+  llvm::json::Array array;
+  for (uint32_t i = 0, n = processes.GetSize(); i < n; ++i) {
+    lldb::SBProcessInfo info;
+    if (!processes.GetProcessInfoAtIndex(i, info))
+      continue;
+
+    llvm::json::Object entry;
+    entry["pid"] = info.GetProcessID();
+    if (const char *name = info.GetName())
+      entry["name"] = name;
+    if (const char *triple = info.GetTriple())
+      entry["triple"] = triple;
+    if (info.UserIDIsValid())
+      entry["user"] = info.GetUserID();
+
+    lldb::SBFileSpec exe = info.GetExecutableFile();
+    if (exe.IsValid()) {
+      std::string path = lldb_dap::GetSBFileSpecPath(exe);
+      if (!path.empty())
+        entry["executable"] = path;
+    }
+
+    array.push_back(std::move(entry));
+  }
+
+  llvm::outs() << llvm::formatv("{0}\n", llvm::json::Value(std::move(array)));
+  return llvm::Error::success();
+}
+
 llvm::Error
 notifyError(RunInTerminalLauncherCommChannel &comm_channel, std::string 
message,
             std::optional<std::error_code> error_code = std::nullopt) {
@@ -705,6 +801,14 @@ int main(int argc, char *argv[]) {
     return EXIT_SUCCESS;
   }
 
+  if (input_args.hasArg(OPT_list_processes)) {
+    if (llvm::Error error = ListProcesses(input_args)) {
+      llvm::WithColor::error() << llvm::toString(std::move(error)) << '\n';
+      return EXIT_FAILURE;
+    }
+    return EXIT_SUCCESS;
+  }
+
   ReplMode default_repl_mode = ReplMode::Auto;
   if (input_args.hasArg(OPT_repl_mode)) {
     llvm::opt::Arg *repl_mode = input_args.getLastArg(OPT_repl_mode);

``````````

</details>


https://github.com/llvm/llvm-project/pull/197330
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to