Skip to content

Conversation

@cs01
Copy link
Contributor

@cs01 cs01 commented Oct 9, 2025

The lldb-server platform help text is inconsistent with lldb-server gdbserver help text. This PR modernizes the platform server to use LLVM's TableGen-based option parsing (matching the existing gdbserver implementation), which auto-generates option parsing code and help text.

The changes improve documentation quality by adding comprehensive option descriptions,, adding support for -h/--help flags, and organizing help output with DESCRIPTION and EXAMPLES sections. Internal-only options (--child-platform-fd) and unused legacy options (--debug, --verbose) are now hidden from help while maintaining backward compatibility. All functional behavior remains unchanged—this is purely a documentation and code modernization improvement.

before

> /opt/llvm/bin/lldb-server p -h
p: unrecognized option '-h'
Usage:
  /opt/llvm/bin/lldb-server p [--log-file log-file-name] [--log-channels log-channel-list] [--port-file port-file-path] --server --listen port

after

lldb-server p -h 
OVERVIEW: lldb-server platform

USAGE: lldb-server p [options] --listen <[host]:port> [[--] program args...]

CONNECTION OPTIONS:
  --gdbserver-port <port> Port to use for spawned gdbserver instances. If 0 or unspecified, a port will be chosen automatically. Short form: -P
  --listen <[host]:port>  Host and port to listen on. Format: [host]:port or protocol://[host]:port (e.g., tcp://localhost:1234, unix:///path/to/socket). Short form: -L
  --socket-file <path>    Write listening socket information (port number for TCP or path for Unix domain sockets) to the specified file. Short form: -f

GENERAL OPTIONS:
  --help            Display this help message and exit.
  --log-channels <channel1 categories...:channel2 categories...>
                    Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories. Common channels: lldb, gdb-remote, platform, process. Short form: -c
  --log-file <file> Destination file to log to. If empty, log to stderr. Short form: -l
  --server          Run in server mode, accepting multiple client connections sequentially. Without this flag, the server exits after handling the first connection.

OPTIONS:
  -- program args Arguments to pass to launched gdbserver instances.

DESCRIPTION
  Acts as a platform server for remote debugging. When LLDB clients connect,
  the platform server handles platform operations (file transfers, process
  launching) and spawns debug server instances (lldb-server gdbserver) to
  handle actual debugging sessions.

  By default, the server exits after handling one connection. Use --server
  to keep running and accept multiple connections sequentially.

EXAMPLES
  # Listen on port 1234, exit after first connection
  lldb-server platform --listen tcp://0.0.0.0:1234

  # Listen on port 5555, accept multiple connections
  lldb-server platform --server --listen tcp://localhost:5555

  # Listen on Unix domain socket
  lldb-server platform --listen unix:///tmp/lldb-server.sock

For comparison, here is the gdbserver help text:

lldb-server g -h
OVERVIEW: lldb-server

USAGE: lldb-server g[dbserver] [options] [[host]:port] [[--] program args...]

CONNECTION:
  --fd <fd>           Communicate over the given file descriptor.
  --named-pipe <name> Write port lldb-server will listen on to the given named pipe.
  --pipe <fd>         Write port lldb-server will listen on to the given file descriptor.
  --reverse-connect   Connect to the client instead of passively waiting for a connection. In this case [host]:port denotes the remote address to connect to.

GENERAL OPTIONS:
  --help            Prints out the usage information for lldb-server.
  --log-channels <channel1 categories...:channel2 categories...>
                    Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories.
  --log-file <file> Destination file to log to. If empty, log to stderr.
  --setsid          Run lldb-server in a new session.

TARGET SELECTION:
  --attach <pid-or-name> Attach to the process given by a (numeric) process id or a name.
  -- program args        Launch program for debugging.

DESCRIPTION
  lldb-server connects to the LLDB client, which drives the debugging session.
  If no connection options are given, the [host]:port argument must be present
  and will denote the address that lldb-server will listen on. [host] defaults
  to "localhost" if empty. Port can be zero, in which case the port number will
  be chosen dynamically and written to destinations given by --named-pipe and
  --pipe arguments.

  If no target is selected at startup, lldb-server can be directed by the LLDB
  client to launch or attach to a process.

@cs01 cs01 requested a review from JDevlieghere as a code owner October 9, 2025 20:34
@llvmbot llvmbot added the lldb label Oct 9, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 9, 2025

@llvm/pr-subscribers-lldb

Author: Chad Smith (cs01)

Changes

The lldb-server platform help text is inconsistent with lldb-server gdbserver help text. This PR modernizes the platform server to use LLVM's TableGen-based option parsing (matching the existing gdbserver implementation), which auto-generates option parsing code and help text.

The changes improve documentation quality by adding comprehensive option descriptions, fixing incorrect option names (e.g., --port-file--socket-file), adding support for -h/--help flags, and organizing help output with DESCRIPTION and EXAMPLES sections. Internal-only options (--child-platform-fd) and unused legacy options (--debug, --verbose) are now hidden from help while maintaining backward compatibility. All functional behavior remains unchanged—this is purely a documentation and code modernization improvement.

before

&gt; /opt/llvm/bin/lldb-server p -h
p: unrecognized option '-h'
Usage:
  /opt/llvm/bin/lldb-server p [--log-file log-file-name] [--log-channels log-channel-list] [--port-file port-file-path] --server --listen port

after

lldb-server p -h
OVERVIEW: lldb-server platform

USAGE: lldb-server p [options] --listen &lt;[host]:port&gt; [[--] program args...]

CONNECTION OPTIONS:
  --gdbserver-port &lt;port&gt; Port to use for spawned gdbserver instances. If 0 or unspecified, a port will be chosen automatically.
  --listen &lt;[host]:port&gt;  Host and port to listen on. Format: [host]:port or protocol://[host]:port (e.g., tcp://localhost:1234, unix:///path/to/socket).
  --socket-file &lt;path&gt;    Write listening socket information (port number for TCP or path for Unix domain sockets) to the specified file.

GENERAL OPTIONS:
  --help            Display this help message and exit.
  --log-channels &lt;channel1 categories...:channel2 categories...&gt;
                    Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories. Common channels: lldb, gdb-remote, platform, process.
  --log-file &lt;file&gt; Destination file to log to. If empty, log to stderr.
  --server          Run in server mode, accepting multiple client connections sequentially. Without this flag, the server exits after handling the first connection.

OPTIONS:
  -- program args Arguments to pass to launched gdbserver instances.

DESCRIPTION
  Acts as a platform server for remote debugging. When LLDB clients connect,
  the platform server handles platform operations (file transfers, process
  launching) and spawns debug server instances (lldb-server gdbserver) to
  handle actual debugging sessions.

  By default, the server exits after handling one connection. Use --server
  to keep running and accept multiple connections sequentially.

EXAMPLES
  # Listen on port 1234, exit after first connection
  lldb-server platform --listen tcp://0.0.0.0:1234

  # Listen on port 5555, accept multiple connections
  lldb-server platform --server --listen tcp://localhost:5555

  # Listen on Unix domain socket
  lldb-server platform --listen unix:///tmp/lldb-server.sock


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

3 Files Affected:

  • (modified) lldb/tools/lldb-server/CMakeLists.txt (+5)
  • (added) lldb/tools/lldb-server/LLPlatformOptions.td (+65)
  • (modified) lldb/tools/lldb-server/lldb-platform.cpp (+161-108)
diff --git a/lldb/tools/lldb-server/CMakeLists.txt b/lldb/tools/lldb-server/CMakeLists.txt
index 1d8dc72a3f872..50f294f1b5712 100644
--- a/lldb/tools/lldb-server/CMakeLists.txt
+++ b/lldb/tools/lldb-server/CMakeLists.txt
@@ -2,6 +2,10 @@ set(LLVM_TARGET_DEFINITIONS LLGSOptions.td)
 tablegen(LLVM LLGSOptions.inc -gen-opt-parser-defs)
 add_public_tablegen_target(LLGSOptionsTableGen)
 
+set(LLVM_TARGET_DEFINITIONS LLPlatformOptions.td)
+tablegen(LLVM LLPlatformOptions.inc -gen-opt-parser-defs)
+add_public_tablegen_target(LLPlatformOptionsTableGen)
+
 set(LLDB_PLUGINS)
 
 if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
@@ -67,6 +71,7 @@ add_lldb_tool(lldb-server
 
 add_dependencies(lldb-server
   LLGSOptionsTableGen
+  LLPlatformOptionsTableGen
   ${tablegen_deps}
 )
 target_include_directories(lldb-server PRIVATE "${LLDB_SOURCE_DIR}/source")
diff --git a/lldb/tools/lldb-server/LLPlatformOptions.td b/lldb/tools/lldb-server/LLPlatformOptions.td
new file mode 100644
index 0000000000000..76f0f264ecd53
--- /dev/null
+++ b/lldb/tools/lldb-server/LLPlatformOptions.td
@@ -0,0 +1,65 @@
+include "llvm/Option/OptParser.td"
+
+class F<string name>: Flag<["--", "-"], name>;
+class R<list<string> prefixes, string name>
+  : Option<prefixes, name, KIND_REMAINING_ARGS>;
+
+multiclass SJ<string name, string help> {
+  def NAME: Separate<["--", "-"], name>,
+    HelpText<help>;
+  def NAME # _eq: Joined<["--", "-"], name # "=">,
+    Alias<!cast<Separate>(NAME)>;
+}
+
+def grp_connect : OptionGroup<"connection">, HelpText<"CONNECTION OPTIONS">;
+
+defm listen: SJ<"listen", "Host and port to listen on. Format: [host]:port or protocol://[host]:port (e.g., tcp://localhost:1234, unix:///path/to/socket).">,
+  MetaVarName<"<[host]:port>">,
+  Group<grp_connect>;
+
+defm socket_file: SJ<"socket-file", "Write listening socket information (port number for TCP or path for Unix domain sockets) to the specified file.">,
+  MetaVarName<"<path>">,
+  Group<grp_connect>;
+
+defm gdbserver_port: SJ<"gdbserver-port", "Port to use for spawned gdbserver instances. If 0 or unspecified, a port will be chosen automatically.">,
+  MetaVarName<"<port>">,
+  Group<grp_connect>;
+
+defm child_platform_fd: SJ<"child-platform-fd", "File descriptor for communication with parent platform process (internal use only).">,
+  MetaVarName<"<fd>">,
+  Group<grp_connect>,
+  Flags<[HelpHidden]>;
+
+def grp_general : OptionGroup<"general options">, HelpText<"GENERAL OPTIONS">;
+
+def server: F<"server">,
+  HelpText<"Run in server mode, accepting multiple client connections sequentially. Without this flag, the server exits after handling the first connection.">,
+  Group<grp_general>;
+
+defm log_channels: SJ<"log-channels", "Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories. Common channels: lldb, gdb-remote, platform, process.">,
+  MetaVarName<"<channel1 categories...:channel2 categories...>">,
+  Group<grp_general>;
+
+defm log_file: SJ<"log-file", "Destination file to log to. If empty, log to stderr.">,
+  MetaVarName<"<file>">,
+  Group<grp_general>;
+
+def debug: F<"debug">,
+  HelpText<"(Unused, kept for backward compatibility)">,
+  Group<grp_general>,
+  Flags<[HelpHidden]>;
+
+def verbose: F<"verbose">,
+  HelpText<"(Unused, kept for backward compatibility)">,
+  Group<grp_general>,
+  Flags<[HelpHidden]>;
+
+def help: F<"help">, 
+  HelpText<"Display this help message and exit.">,
+  Group<grp_general>;
+def: Flag<["-"], "h">, Alias<help>,
+  Group<grp_general>;
+
+def REM : R<["--"], "">, 
+  HelpText<"Arguments to pass to launched gdbserver instances.">,
+  MetaVarName<"program args">;
diff --git a/lldb/tools/lldb-server/lldb-platform.cpp b/lldb/tools/lldb-server/lldb-platform.cpp
index 0bd928507ba89..37f0e1b95570c 100644
--- a/lldb/tools/lldb-server/lldb-platform.cpp
+++ b/lldb/tools/lldb-server/lldb-platform.cpp
@@ -21,6 +21,9 @@
 #include <fstream>
 #include <optional>
 
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Option/Option.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/WithColor.h"
@@ -56,22 +59,69 @@ using namespace llvm;
 // of target CPUs. For now, let's just use 100.
 static const int backlog = 100;
 static const int socket_error = -1;
-static int g_debug = 0;
-static int g_verbose = 0;
-static int g_server = 0;
-
-// option descriptors for getopt_long_only()
-static struct option g_long_options[] = {
-    {"debug", no_argument, &g_debug, 1},
-    {"verbose", no_argument, &g_verbose, 1},
-    {"log-file", required_argument, nullptr, 'l'},
-    {"log-channels", required_argument, nullptr, 'c'},
-    {"listen", required_argument, nullptr, 'L'},
-    {"gdbserver-port", required_argument, nullptr, 'P'},
-    {"socket-file", required_argument, nullptr, 'f'},
-    {"server", no_argument, &g_server, 1},
-    {"child-platform-fd", required_argument, nullptr, 2},
-    {nullptr, 0, nullptr, 0}};
+
+namespace {
+using namespace llvm::opt;
+
+enum ID {
+  OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
+#include "LLPlatformOptions.inc"
+#undef OPTION
+};
+
+#define OPTTABLE_STR_TABLE_CODE
+#include "LLPlatformOptions.inc"
+#undef OPTTABLE_STR_TABLE_CODE
+
+#define OPTTABLE_PREFIXES_TABLE_CODE
+#include "LLPlatformOptions.inc"
+#undef OPTTABLE_PREFIXES_TABLE_CODE
+
+static constexpr opt::OptTable::Info InfoTable[] = {
+#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#include "LLPlatformOptions.inc"
+#undef OPTION
+};
+
+class LLPlatformOptTable : public opt::GenericOptTable {
+public:
+  LLPlatformOptTable()
+      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+
+  void PrintHelp(llvm::StringRef Name) {
+    std::string Usage =
+        (Name + " [options] --listen <[host]:port> [[--] program args...]")
+            .str();
+
+    std::string Title = "lldb-server platform";
+
+    OptTable::printHelp(llvm::outs(), Usage.c_str(), Title.c_str());
+
+    llvm::outs() << R"(
+DESCRIPTION
+  Acts as a platform server for remote debugging. When LLDB clients connect,
+  the platform server handles platform operations (file transfers, process
+  launching) and spawns debug server instances (lldb-server gdbserver) to
+  handle actual debugging sessions.
+
+  By default, the server exits after handling one connection. Use --server
+  to keep running and accept multiple connections sequentially.
+
+EXAMPLES
+  # Listen on port 1234, exit after first connection
+  lldb-server platform --listen tcp://0.0.0.0:1234
+
+  # Listen on port 5555, accept multiple connections
+  lldb-server platform --server --listen tcp://localhost:5555
+
+  # Listen on Unix domain socket
+  lldb-server platform --listen unix:///tmp/lldb-server.sock
+
+)";
+  }
+};
+} // namespace
 
 #if defined(__APPLE__)
 #define LOW_PORT (IPPORT_RESERVED)
@@ -97,12 +147,11 @@ static void signal_handler(int signo) {
 }
 #endif
 
-static void display_usage(const char *progname, const char *subcommand) {
-  fprintf(stderr, "Usage:\n  %s %s [--log-file log-file-name] [--log-channels "
-                  "log-channel-list] [--port-file port-file-path] --server "
-                  "--listen port\n",
-          progname, subcommand);
-  exit(0);
+static void display_usage(LLPlatformOptTable &Opts, const char *progname,
+                          const char *subcommand) {
+  std::string Name =
+      (llvm::sys::path::filename(progname) + " " + subcommand).str();
+  Opts.PrintHelp(Name);
 }
 
 static Status parse_listen_host_port(Socket::SocketProtocol &protocol,
@@ -261,7 +310,8 @@ static Status spawn_process(const char *progname, const FileSpec &prog,
                             const Socket *conn_socket, uint16_t gdb_port,
                             const lldb_private::Args &args,
                             const std::string &log_file,
-                            const StringRef log_channels, MainLoop &main_loop) {
+                            const StringRef log_channels, MainLoop &main_loop,
+                            bool multi_client) {
   Status error;
   SharedSocket shared_socket(conn_socket, error);
   if (error.Fail())
@@ -297,9 +347,12 @@ static Status spawn_process(const char *progname, const FileSpec &prog,
 
   launch_info.SetLaunchInSeparateProcessGroup(false);
 
-  if (g_server)
+  // Set up process monitor callback based on whether we're in server mode
+  if (multi_client)
+    // In server mode: empty callback (don't terminate when child exits)
     launch_info.SetMonitorProcessCallback([](lldb::pid_t, int, int) {});
   else
+    // In single-client mode: terminate main loop when child exits
     launch_info.SetMonitorProcessCallback([&main_loop](lldb::pid_t, int, int) {
       main_loop.AddPendingCallback(
           [](MainLoopBase &loop) { loop.RequestTermination(); });
@@ -371,107 +424,107 @@ int main_platform(int argc, char *argv[]) {
   signal(SIGPIPE, SIG_IGN);
   signal(SIGHUP, signal_handler);
 #endif
-  int long_option_index = 0;
+
+  // Special handling for 'help' as first argument
+  if (argc > 0 && strcmp(argv[0], "help") == 0) {
+    LLPlatformOptTable Opts;
+    display_usage(Opts, progname, subcommand);
+    return 0;
+  }
+
   Status error;
   std::string listen_host_port;
-  int ch;
-
   std::string log_file;
-  StringRef
-      log_channels; // e.g. "lldb process threads:gdb-remote default:linux all"
-
+  StringRef log_channels;
   shared_fd_t fd = SharedSocket::kInvalidFD;
-
   uint16_t gdbserver_port = 0;
-
   FileSpec socket_file;
-  bool show_usage = false;
-  int option_error = 0;
-
-  std::string short_options(OptionParser::GetShortOptionString(g_long_options));
-
-#if __GLIBC__
-  optind = 0;
-#else
-  optreset = 1;
-  optind = 1;
-#endif
-
-  while ((ch = getopt_long_only(argc, argv, short_options.c_str(),
-                                g_long_options, &long_option_index)) != -1) {
-    switch (ch) {
-    case 0: // Any optional that auto set themselves will return 0
-      break;
-
-    case 'L':
-      listen_host_port.append(optarg);
-      break;
+  bool multi_client = false;
+  [[maybe_unused]] bool debug = false;
+  [[maybe_unused]] bool verbose = false;
+
+  LLPlatformOptTable Opts;
+  llvm::BumpPtrAllocator Alloc;
+  llvm::StringSaver Saver(Alloc);
+  bool HasError = false;
+
+  opt::InputArgList Args =
+      Opts.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](llvm::StringRef Msg) {
+        WithColor::error() << Msg << "\n";
+        HasError = true;
+      });
+
+  std::string Name =
+      (llvm::sys::path::filename(progname) + " " + subcommand).str();
+  std::string HelpText =
+      "Use '" + Name + " --help' for a complete list of options.\n";
+
+  if (HasError) {
+    llvm::errs() << HelpText;
+    return 1;
+  }
 
-    case 'l': // Set Log File
-      if (optarg && optarg[0])
-        log_file.assign(optarg);
-      break;
+  if (Args.hasArg(OPT_help)) {
+    display_usage(Opts, progname, subcommand);
+    return 0;
+  }
 
-    case 'c': // Log Channels
-      if (optarg && optarg[0])
-        log_channels = StringRef(optarg);
-      break;
+  // Parse arguments
+  listen_host_port = Args.getLastArgValue(OPT_listen).str();
+  log_file = Args.getLastArgValue(OPT_log_file).str();
+  log_channels = Args.getLastArgValue(OPT_log_channels);
+  multi_client = Args.hasArg(OPT_server);
+  debug = Args.hasArg(OPT_debug);
+  verbose = Args.hasArg(OPT_verbose);
+
+  if (Args.hasArg(OPT_socket_file)) {
+    socket_file.SetFile(Args.getLastArgValue(OPT_socket_file),
+                        FileSpec::Style::native);
+  }
 
-    case 'f': // Socket file
-      if (optarg && optarg[0])
-        socket_file.SetFile(optarg, FileSpec::Style::native);
-      break;
+  if (Args.hasArg(OPT_gdbserver_port)) {
+    if (!llvm::to_integer(Args.getLastArgValue(OPT_gdbserver_port),
+                          gdbserver_port)) {
+      WithColor::error() << "invalid --gdbserver-port value\n";
+      return 1;
+    }
+  }
 
-    case 'P':
-    case 'm':
-    case 'M': {
-      uint16_t portnum;
-      if (!llvm::to_integer(optarg, portnum)) {
-        WithColor::error() << "invalid port number string " << optarg << "\n";
-        option_error = 2;
-        break;
-      }
-      // Note the condition gdbserver_port > HIGH_PORT is valid in case of using
-      // --child-platform-fd. Check gdbserver_port later.
-      if (ch == 'P')
-        gdbserver_port = portnum;
-      else if (gdbserver_port == 0)
-        gdbserver_port = portnum;
-    } break;
-
-    case 2: {
-      uint64_t _fd;
-      if (!llvm::to_integer(optarg, _fd)) {
-        WithColor::error() << "invalid fd " << optarg << "\n";
-        option_error = 6;
-      } else
-        fd = (shared_fd_t)_fd;
-    } break;
-
-    case 'h': /* fall-through is intentional */
-    case '?':
-      show_usage = true;
-      break;
+  if (Args.hasArg(OPT_child_platform_fd)) {
+    uint64_t _fd;
+    if (!llvm::to_integer(Args.getLastArgValue(OPT_child_platform_fd), _fd)) {
+      WithColor::error() << "invalid --child-platform-fd value\n";
+      return 1;
     }
+    fd = (shared_fd_t)_fd;
   }
 
   if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
     return -1;
 
   // Print usage and exit if no listening port is specified.
-  if (listen_host_port.empty() && fd == SharedSocket::kInvalidFD)
-    show_usage = true;
+  if (listen_host_port.empty() && fd == SharedSocket::kInvalidFD) {
+    WithColor::error() << "either --listen or --child-platform-fd is required\n"
+                       << HelpText;
+    return 1;
+  }
 
-  if (show_usage || option_error) {
-    display_usage(progname, subcommand);
-    exit(option_error);
+  // Get remaining arguments for inferior
+  std::vector<llvm::StringRef> Inputs;
+  for (opt::Arg *Arg : Args.filtered(OPT_INPUT))
+    Inputs.push_back(Arg->getValue());
+  if (opt::Arg *Arg = Args.getLastArg(OPT_REM)) {
+    for (const char *Val : Arg->getValues())
+      Inputs.push_back(Val);
   }
 
-  // Skip any options we consumed with getopt_long_only.
-  argc -= optind;
-  argv += optind;
   lldb_private::Args inferior_arguments;
-  inferior_arguments.SetArguments(argc, const_cast<const char **>(argv));
+  if (!Inputs.empty()) {
+    std::vector<const char *> args_ptrs;
+    for (const auto &Input : Inputs)
+      args_ptrs.push_back(Input.data());
+    inferior_arguments.SetArguments(args_ptrs.size(), args_ptrs.data());
+  }
 
   FileSpec debugserver_path = GetDebugserverPath();
   if (!debugserver_path) {
@@ -577,22 +630,22 @@ int main_platform(int argc, char *argv[]) {
     llvm::Expected<std::vector<MainLoopBase::ReadHandleUP>> platform_handles =
         platform_sock->Accept(
             main_loop, [progname, gdbserver_port, &inferior_arguments, log_file,
-                        log_channels, &main_loop,
+                        log_channels, &main_loop, multi_client,
                         &platform_handles](std::unique_ptr<Socket> sock_up) {
               printf("Connection established.\n");
               Status error = spawn_process(
                   progname, HostInfo::GetProgramFileSpec(), sock_up.get(),
                   gdbserver_port, inferior_arguments, log_file, log_channels,
-                  main_loop);
+                  main_loop, multi_client);
               if (error.Fail()) {
                 Log *log = GetLog(LLDBLog::Platform);
                 LLDB_LOGF(log, "spawn_process failed: %s", error.AsCString());
                 WithColor::error()
                     << "spawn_process failed: " << error.AsCString() << "\n";
-                if (!g_server)
+                if (!multi_client)
                   main_loop.RequestTermination();
               }
-              if (!g_server)
+              if (!multi_client)
                 platform_handles->clear();
             });
     if (!platform_handles) {

@JDevlieghere
Copy link
Member

Yay for TableGen! If a test like this doesn't exist already, can you add something like Shell/Driver/TestHelp.test that makes sure all the options are correctly printed?

@cs01 cs01 force-pushed the cs01/lldb-platform-help-text branch from 17d6190 to 6d6cabb Compare October 9, 2025 20:50
@cs01
Copy link
Contributor Author

cs01 commented Oct 9, 2025

Yay for TableGen! If a test like this doesn't exist already, can you add something like Shell/Driver/TestHelp.test that makes sure all the options are correctly printed?

Sounds good, I'll take a look

@cs01 cs01 force-pushed the cs01/lldb-platform-help-text branch 2 times, most recently from 98e4f98 to eab11a4 Compare October 9, 2025 21:26
@cs01
Copy link
Contributor Author

cs01 commented Oct 9, 2025

Added a few tests, one for help text, one for error messages, and one for successful startups. Thank you for the suggestion!

llvm-lit -v lldb-server/TestPlatformHelp.test lldb-server/TestPlatformErrorMessages.test lldb-server/TestPlatformSuccessfulStartup.test
...
-- Testing: 3 tests, 3 workers --
PASS: lldb-shell :: lldb-server/TestPlatformHelp.test (1 of 3)
PASS: lldb-shell :: lldb-server/TestPlatformErrorMessages.test (2 of 3)
PASS: lldb-shell :: lldb-server/TestPlatformSuccessfulStartup.test (3 of 3)

Testing Time: 1.08s

Total Discovered Tests: 3
  Passed: 3 (100.00%)

1 warning(s) in tests

I also renamed

lldb-server/TestErrorMessages.test‎ to TestGdbserverErrorMessages.test‎

to disambiguate it from lldb-server platform tests.

@cs01 cs01 changed the title update lldb-server platform help text update lldb-server platform help parsing Oct 9, 2025
@royitaqi
Copy link
Contributor

royitaqi commented Oct 9, 2025

Nice! Thanks for the change!

(I will let Jonas accept.)

@cs01 cs01 force-pushed the cs01/lldb-platform-help-text branch from eab11a4 to e0cf097 Compare October 9, 2025 22:24
@cs01
Copy link
Contributor Author

cs01 commented Oct 9, 2025

Updated per your feedback @JDevlieghere

The one question I had was regarding

  if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
    return -1;

and whether I should replace the -1 with EXIT_FAILURE

@cs01
Copy link
Contributor Author

cs01 commented Oct 9, 2025

Btw, I plan to make a few more pull requests to improve the API of lldb-server and the messages it prints. One for lldb-server's help itself.

Another for lldb-server p's messages that it logs to stderr (it's completely silent when it starts and is unclear if it's working or hung).

And one more to hide the --server option and replace it with --daemon or --multi-connect, since lldb-server --server is repetitive and a bit unclear (IMO). Hope that is okay.

@JDevlieghere
Copy link
Member

The one question I had was regarding

  if (!LLDBServerUtilities::SetupLogging(log_file, log_channels, 0))
    return -1;

and whether I should replace the -1 with EXIT_FAILURE

Personally I would keep the current value, as it seems to have been done on purpose, and the risk of breaking someone's workflow outweighs the benefit of slightly improving consistency.

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I added some other active contributors to lldb-server for visibility.

@cs01 cs01 force-pushed the cs01/lldb-platform-help-text branch from e0cf097 to 7673bc3 Compare October 9, 2025 23:17
@DavidSpickett
Copy link
Collaborator

DavidSpickett commented Oct 13, 2025

Some of this testing can be run on Windows, we do build lldb-server:

725.239 [76/10/6932] Linking CXX executable bin\lldb-server.exe

I'm not sure to what extent it works, but some of these error messages will work.

Don't have the time to check right now, please do if you can. I'm not too bothered either way though, I just know some tests do run on Windows right now.

But if you had to split the tests because of it, not worth it.

Copy link
Collaborator

@DavidSpickett DavidSpickett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the direction, and making --help actually work, surprising how many applications fall back on the "unknown option" message for it.

RUN: %lldb-server platform -h 2>&1 | FileCheck %s

CHECK: OVERVIEW: lldb-server platform
CHECK: USAGE: lldb-server {{p|platform}} [options] --listen <{{[[]}}host]:port> {{[[]}}[--] program args...]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you confirm what {{ are part of the output and which are some kind of escape character? ISTR FileCheck regex uses {{}} so not sure what is what.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was kinda hard to read, it was basically looking for a [ but was put inside []. I changed it to be \[ so now it's {{\[}}. Hopefully it is a bit easier to read.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you forgot to update the changes, but in any case:

  • I did not realise that's how regex character [] worked, TIL.
  • Couldn't you just write [ here?

{{[[]}} is a regex [[] and that could be written as a non-regex [.

What am I missing here that needs the regex? Is [ special to FileCheck? You have [options] there, and that didn't need a regex. Only certain combinations of [...] are special?

Copy link
Contributor Author

@cs01 cs01 Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The actual help text looks like this:

> ./bin/lldb-server p -h
OVERVIEW: lldb-server platform

USAGE: lldb-server p [options] --listen <[host]:port> [[--] program args...]

The regex is only needed with the double brackets, so you were right, there were a couple that were unnecessary. Should be fixed now.

It's only needed at the [[--] part because [[ is interpreted by FileCheck as variable substitution. For example in cross-project-tests/dtlto/link-archive-thin.test PID is substituted:

## JSON jobs description.
OUTPUTS-DAG: my.[[PID:[a-zA-Z0-9_]+]].dist-file.json

## Individual summary index files.
OUTPUTS-DAG: start.1.[[PID]].native.o.thinlto.bc{{$}}
OUTPUTS-DAG:   dog.2.[[PID]].native.o.thinlto.bc{{$}}
OUTPUTS-DAG:   foo.3.[[PID]].native.o.thinlto.bc{{$}}
OUTPUTS-DAG:   bar.4.[[PID]].native.o.thinlto.bc{{$}}

@DavidSpickett
Copy link
Collaborator

Don't have the time to check right now, please do if you can. I'm not too bothered either way though, I just know some tests do run on Windows right now.

You could use the CI here to check it. Try enabling the platform mode tests and see what happens.

@cs01
Copy link
Contributor Author

cs01 commented Oct 13, 2025

Thank you for the suggestions! I’m about to go out of town for one week. I will get back to this the following week. Thankfully it is not time sensitive so I’m fine leaving this PR open until then if you all are.

@DavidSpickett
Copy link
Collaborator

I’m fine leaving this PR open until then if you all are.

No problem with that.

@cs01
Copy link
Contributor Author

cs01 commented Oct 22, 2025

You could use the CI here to check it. Try enabling the platform mode tests and see what happens.

I removed the # UNSUPPORTED: system-windows line at the top and pushed. Is that all I have to do, or do I have to somehow enable platform mode tests manually? And aren't there more tests that run after the PR is merged? Is it possible to run those before landing too?

Otherwise it's ready for another review.

@DavidSpickett
Copy link
Collaborator

I think you forgot to push your latest changes.

Regardless, I thought that Windows CI would be testing LLDB but it is not. Oh well, we can always put back the unsupported if I'm wrong about this.

@DavidSpickett
Copy link
Collaborator

I removed the # UNSUPPORTED: system-windows line at the top and pushed. Is that all I have to do, or do I have to somehow enable platform mode tests manually?

Nothing else to do.

And aren't there more tests that run after the PR is merged? Is it possible to run those before landing too?

Mostly the same tests on a bunch of platforms but yes there is more that is done. It is technically possible to run them before landing but in this case it's easier to just land it and see what happens. Reverts and fixups are a normal part of "live at main" development.

@cs01 cs01 force-pushed the cs01/lldb-platform-help-text branch from 7673bc3 to a3f3f8f Compare October 23, 2025 13:54
@DavidSpickett DavidSpickett changed the title update lldb-server platform help parsing [lldb] update lldb-server platform help parsing Oct 23, 2025
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Oct 23, 2025
Fix windows test failures from
llvm/llvm-project#162730 by including and
optional .exe on the lldb-server name. Still passes on linux, but should
pass on windows now.

```
> bin/llvm-lit -v tools/lldb/test/Shell/lldb-server/
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using clang: llvm-project/build/bin/clang
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld.lld: /usr/bin/ld.lld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using lld-link: /usr/bin/lld-link
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld64.lld: /usr/bin/ld64.lld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using wasm-ld: /usr/bin/wasm-ld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/subst.py:126: note: Did not find obj2yaml in llvm-project/build/./bin:llvm-project/build/./bin
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/subst.py:126: note: Did not find llvm-objdump in llvm-project/build/./bin:llvm-project/build/./bin
llvm-lit: llvm-project/lldb/test/Shell/lit.cfg.py:125: warning: Could not set a default per-test timeout. Requires the Python psutil module but it could not be found. Try installing it via pip or via your operating system's package manager.
-- Testing: 4 tests, 4 workers --
PASS: lldb-shell :: lldb-server/TestGdbserverErrorMessages.test (1 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformHelp.test (2 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformErrorMessages.test (3 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformSuccessfulStartup.test (4 of 4)

Testing Time: 1.10s

Total Discovered Tests: 4
  Passed: 4 (100.00%)

1 warning(s) in tests
```
@adrian-prantl
Copy link
Collaborator

@cs01 This doesn't seem to work on macOS:

[2025-10-23T17:00:02.993Z] ******************** TEST 'lldb-shell :: lldb-server/TestPlatformSuccessfulStartup.test' FAILED ********************
[2025-10-23T17:00:02.993Z] Exit Code: 127
[2025-10-23T17:00:02.993Z] 
[2025-10-23T17:00:02.993Z] Command Output (stdout):
[2025-10-23T17:00:02.993Z] --
[2025-10-23T17:00:02.993Z] # RUN: at line 4
[2025-10-23T17:00:02.993Z] rm -f /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/lldb-build/tools/lldb/test/Shell/lldb-server/Output/TestPlatformSuccessfulStartup.test.tmp.socket1
[2025-10-23T17:00:02.993Z] # executed command: rm -f /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/lldb-build/tools/lldb/test/Shell/lldb-server/Output/TestPlatformSuccessfulStartup.test.tmp.socket1
[2025-10-23T17:00:02.993Z] # note: command had no output on stdout or stderr
[2025-10-23T17:00:02.993Z] # RUN: at line 5
[2025-10-23T17:00:02.993Z] timeout 0.2s /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/lldb-build/bin/lldb-server platform --listen tcp://127.0.0.1:0 --socket-file /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/lldb-build/tools/lldb/test/Shell/lldb-server/Output/TestPlatformSuccessfulStartup.test.tmp.socket1 > /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/lldb-build/tools/lldb/test/Shell/lldb-server/Output/TestPlatformSuccessfulStartup.test.tmp.out1 2>&1 || true
[2025-10-23T17:00:02.993Z] # executed command: timeout 0.2s /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/lldb-build/bin/lldb-server platform --listen tcp://127.0.0.1:0 --socket-file /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/lldb-build/tools/lldb/test/Shell/lldb-server/Output/TestPlatformSuccessfulStartup.test.tmp.socket1
[2025-10-23T17:00:02.993Z] # .---command stderr------------
[2025-10-23T17:00:02.993Z] # | 'timeout': command not found
[2025-10-23T17:00:02.993Z] # `-----------------------------
[2025-10-23T17:00:02.993Z] # error: command failed with exit status: 127
[2025-10-23T17:00:02.993Z] 
[2025-10-23T17:00:02.993Z] --

https://green.lab.llvm.org/job/llvm.org/view/LLDB/job/lldb-cmake/16164/changes#faf7af864f9258768133894764f1fae58d43bb09

@adrian-prantl
Copy link
Collaborator

I also should point out that a timeout of 0.2s is way to short for any kind of CI system under load. They run 24/7 and at some random point the OS will halt everything to do various cleanup jobs and then these timeouts time out. Why does this need any timeout on top of the LIT timeout?

@adrian-prantl
Copy link
Collaborator

Based on the conversation you don't seem to have commit access so I'll go ahead and revert this for you.

@cs01
Copy link
Contributor Author

cs01 commented Oct 23, 2025

Thanks for the heads up. I attempted to fix the windows issue in #164843. I am not sure of the normal workflow in cases like this, but in the future it would be easier for me (and probably reviewers) if the change was not reverted entirely and I could try and patch a fix, similar to #164843.

@cs01
Copy link
Contributor Author

cs01 commented Oct 23, 2025

Would it be possible for me to get commit access?

@cs01
Copy link
Contributor Author

cs01 commented Oct 23, 2025

Why does this need any timeout on top of the LIT timeout?

It starts lldb-server and tests that it can successfully listen on a socket, but it must be killed, since it just runs indefinitely. I just removed the test for now to increase the chances of merging without further issue.
(#164904). Hopefully that helps it pass on mac.

@adrian-prantl
Copy link
Collaborator

Thanks for the heads up. I attempted to fix the windows issue in #164843. I am not sure of the normal workflow in cases like this, but in the future it would be easier for me (and probably reviewers) if the change was not reverted entirely and I could try and patch a fix, similar to #164843.

I have no problem with you fixing tests "in production" (within reason) since nobody has access to all the platforms tested by LLVM bots. But I'd much prefer if you revert the failing commit and then reland it with a fix, rather than layering the fix on top of the previous commit. This also makes it easier to cherry-pick the commit to release branches later on.

Today getting the bots clean was particularly urgent since we had an outage on the arm64 machines and were running on the much slower x86 nodes, so I went ahead and did that.

Would it be possible for me to get commit access?

https://llvm.org/docs/DeveloperPolicy.html#obtaining-commit-access

Why does this need any timeout on top of the LIT timeout?

It starts lldb-server and tests that it can successfully listen on a socket, but it must be killed, since it just runs indefinitely. I just removed the test for now to increase the chances of merging without further issue.

Synchronization via timeouts is not really feasible in a CI setting. In order to work with machines under load (or worse, ASANIfied builds of LLDB) the timeout would need to be north of 60s, but then that also means that each successful test would take that long.

In this case it would probably be a better to write this as an API test. You'd want the inner process to, e.g., write to a pipe, wait on that and then deterministically kill the process.

@JDevlieghere
Copy link
Member

It's also worth noting that because of our post-commit testing, heavier use of reverts is a natural part of our development workflow. There's a section in the LLVM Developer Policy that sheds some more light on that as it tends to be different from other OSS projects.

googlewalt added a commit that referenced this pull request Oct 24, 2025
googlewalt added a commit that referenced this pull request Oct 24, 2025
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Oct 24, 2025
dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
The lldb-server platform help text is inconsistent with lldb-server
gdbserver help text. This PR modernizes the platform server to use
LLVM's [TableGen](https://llvm.org/docs/TableGen/)-based option parsing
(matching the existing gdbserver implementation), which auto-generates
option parsing code and help text.

The changes improve documentation quality by adding comprehensive option
descriptions,, adding support for `-h`/`--help` flags, and organizing
help output with DESCRIPTION and EXAMPLES sections. Internal-only
options (`--child-platform-fd`) and unused legacy options (`--debug`,
`--verbose`) are now hidden from help while maintaining backward
compatibility. All functional behavior remains unchanged—this is purely
a documentation and code modernization improvement.

## before
```
> /opt/llvm/bin/lldb-server p -h
p: unrecognized option '-h'
Usage:
  /opt/llvm/bin/lldb-server p [--log-file log-file-name] [--log-channels log-channel-list] [--port-file port-file-path] --server --listen port
```

## after
```
lldb-server p -h 
OVERVIEW: lldb-server platform

USAGE: lldb-server p [options] --listen <[host]:port> [[--] program args...]

CONNECTION OPTIONS:
  --gdbserver-port <port> Port to use for spawned gdbserver instances. If 0 or unspecified, a port will be chosen automatically. Short form: -P
  --listen <[host]:port>  Host and port to listen on. Format: [host]:port or protocol://[host]:port (e.g., tcp://localhost:1234, unix:///path/to/socket). Short form: -L
  --socket-file <path>    Write listening socket information (port number for TCP or path for Unix domain sockets) to the specified file. Short form: -f

GENERAL OPTIONS:
  --help            Display this help message and exit.
  --log-channels <channel1 categories...:channel2 categories...>
                    Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories. Common channels: lldb, gdb-remote, platform, process. Short form: -c
  --log-file <file> Destination file to log to. If empty, log to stderr. Short form: -l
  --server          Run in server mode, accepting multiple client connections sequentially. Without this flag, the server exits after handling the first connection.

OPTIONS:
  -- program args Arguments to pass to launched gdbserver instances.

DESCRIPTION
  Acts as a platform server for remote debugging. When LLDB clients connect,
  the platform server handles platform operations (file transfers, process
  launching) and spawns debug server instances (lldb-server gdbserver) to
  handle actual debugging sessions.

  By default, the server exits after handling one connection. Use --server
  to keep running and accept multiple connections sequentially.

EXAMPLES
  # Listen on port 1234, exit after first connection
  lldb-server platform --listen tcp://0.0.0.0:1234

  # Listen on port 5555, accept multiple connections
  lldb-server platform --server --listen tcp://localhost:5555

  # Listen on Unix domain socket
  lldb-server platform --listen unix:///tmp/lldb-server.sock

```

For comparison, here is the **gdbserver** help text:
```
lldb-server g -h
OVERVIEW: lldb-server

USAGE: lldb-server g[dbserver] [options] [[host]:port] [[--] program args...]

CONNECTION:
  --fd <fd>           Communicate over the given file descriptor.
  --named-pipe <name> Write port lldb-server will listen on to the given named pipe.
  --pipe <fd>         Write port lldb-server will listen on to the given file descriptor.
  --reverse-connect   Connect to the client instead of passively waiting for a connection. In this case [host]:port denotes the remote address to connect to.

GENERAL OPTIONS:
  --help            Prints out the usage information for lldb-server.
  --log-channels <channel1 categories...:channel2 categories...>
                    Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories.
  --log-file <file> Destination file to log to. If empty, log to stderr.
  --setsid          Run lldb-server in a new session.

TARGET SELECTION:
  --attach <pid-or-name> Attach to the process given by a (numeric) process id or a name.
  -- program args        Launch program for debugging.

DESCRIPTION
  lldb-server connects to the LLDB client, which drives the debugging session.
  If no connection options are given, the [host]:port argument must be present
  and will denote the address that lldb-server will listen on. [host] defaults
  to "localhost" if empty. Port can be zero, in which case the port number will
  be chosen dynamically and written to destinations given by --named-pipe and
  --pipe arguments.

  If no target is selected at startup, lldb-server can be directed by the LLDB
  client to launch or attach to a process.
```
dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
Fix windows test failures from
llvm#162730 by including and
optional .exe on the lldb-server name. Still passes on linux, but should
pass on windows now.

```
> bin/llvm-lit -v tools/lldb/test/Shell/lldb-server/
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using clang: llvm-project/build/bin/clang
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld.lld: /usr/bin/ld.lld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using lld-link: /usr/bin/lld-link
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld64.lld: /usr/bin/ld64.lld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using wasm-ld: /usr/bin/wasm-ld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/subst.py:126: note: Did not find obj2yaml in llvm-project/build/./bin:llvm-project/build/./bin
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/subst.py:126: note: Did not find llvm-objdump in llvm-project/build/./bin:llvm-project/build/./bin
llvm-lit: llvm-project/lldb/test/Shell/lit.cfg.py:125: warning: Could not set a default per-test timeout. Requires the Python psutil module but it could not be found. Try installing it via pip or via your operating system's package manager.
-- Testing: 4 tests, 4 workers --
PASS: lldb-shell :: lldb-server/TestGdbserverErrorMessages.test (1 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformHelp.test (2 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformErrorMessages.test (3 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformSuccessfulStartup.test (4 of 4)

Testing Time: 1.10s

Total Discovered Tests: 4
  Passed: 4 (100.00%)

1 warning(s) in tests
```
dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
The lldb-server platform help text is inconsistent with lldb-server
gdbserver help text. This PR modernizes the platform server to use
LLVM's [TableGen](https://llvm.org/docs/TableGen/)-based option parsing
(matching the existing gdbserver implementation), which auto-generates
option parsing code and help text.

The changes improve documentation quality by adding comprehensive option
descriptions,, adding support for `-h`/`--help` flags, and organizing
help output with DESCRIPTION and EXAMPLES sections. Internal-only
options (`--child-platform-fd`) and unused legacy options (`--debug`,
`--verbose`) are now hidden from help while maintaining backward
compatibility. All functional behavior remains unchanged—this is purely
a documentation and code modernization improvement.

## before
```
> /opt/llvm/bin/lldb-server p -h
p: unrecognized option '-h'
Usage:
  /opt/llvm/bin/lldb-server p [--log-file log-file-name] [--log-channels log-channel-list] [--port-file port-file-path] --server --listen port
```

## after
```
lldb-server p -h 
OVERVIEW: lldb-server platform

USAGE: lldb-server p [options] --listen <[host]:port> [[--] program args...]

CONNECTION OPTIONS:
  --gdbserver-port <port> Port to use for spawned gdbserver instances. If 0 or unspecified, a port will be chosen automatically. Short form: -P
  --listen <[host]:port>  Host and port to listen on. Format: [host]:port or protocol://[host]:port (e.g., tcp://localhost:1234, unix:///path/to/socket). Short form: -L
  --socket-file <path>    Write listening socket information (port number for TCP or path for Unix domain sockets) to the specified file. Short form: -f

GENERAL OPTIONS:
  --help            Display this help message and exit.
  --log-channels <channel1 categories...:channel2 categories...>
                    Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories. Common channels: lldb, gdb-remote, platform, process. Short form: -c
  --log-file <file> Destination file to log to. If empty, log to stderr. Short form: -l
  --server          Run in server mode, accepting multiple client connections sequentially. Without this flag, the server exits after handling the first connection.

OPTIONS:
  -- program args Arguments to pass to launched gdbserver instances.

DESCRIPTION
  Acts as a platform server for remote debugging. When LLDB clients connect,
  the platform server handles platform operations (file transfers, process
  launching) and spawns debug server instances (lldb-server gdbserver) to
  handle actual debugging sessions.

  By default, the server exits after handling one connection. Use --server
  to keep running and accept multiple connections sequentially.

EXAMPLES
  # Listen on port 1234, exit after first connection
  lldb-server platform --listen tcp://0.0.0.0:1234

  # Listen on port 5555, accept multiple connections
  lldb-server platform --server --listen tcp://localhost:5555

  # Listen on Unix domain socket
  lldb-server platform --listen unix:///tmp/lldb-server.sock

```

For comparison, here is the **gdbserver** help text:
```
lldb-server g -h
OVERVIEW: lldb-server

USAGE: lldb-server g[dbserver] [options] [[host]:port] [[--] program args...]

CONNECTION:
  --fd <fd>           Communicate over the given file descriptor.
  --named-pipe <name> Write port lldb-server will listen on to the given named pipe.
  --pipe <fd>         Write port lldb-server will listen on to the given file descriptor.
  --reverse-connect   Connect to the client instead of passively waiting for a connection. In this case [host]:port denotes the remote address to connect to.

GENERAL OPTIONS:
  --help            Prints out the usage information for lldb-server.
  --log-channels <channel1 categories...:channel2 categories...>
                    Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories.
  --log-file <file> Destination file to log to. If empty, log to stderr.
  --setsid          Run lldb-server in a new session.

TARGET SELECTION:
  --attach <pid-or-name> Attach to the process given by a (numeric) process id or a name.
  -- program args        Launch program for debugging.

DESCRIPTION
  lldb-server connects to the LLDB client, which drives the debugging session.
  If no connection options are given, the [host]:port argument must be present
  and will denote the address that lldb-server will listen on. [host] defaults
  to "localhost" if empty. Port can be zero, in which case the port number will
  be chosen dynamically and written to destinations given by --named-pipe and
  --pipe arguments.

  If no target is selected at startup, lldb-server can be directed by the LLDB
  client to launch or attach to a process.
```
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
Fix windows test failures from
llvm#162730 by including and
optional .exe on the lldb-server name. Still passes on linux, but should
pass on windows now.

```
> bin/llvm-lit -v tools/lldb/test/Shell/lldb-server/
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using clang: llvm-project/build/bin/clang
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld.lld: /usr/bin/ld.lld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using lld-link: /usr/bin/lld-link
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld64.lld: /usr/bin/ld64.lld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using wasm-ld: /usr/bin/wasm-ld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/subst.py:126: note: Did not find obj2yaml in llvm-project/build/./bin:llvm-project/build/./bin
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/subst.py:126: note: Did not find llvm-objdump in llvm-project/build/./bin:llvm-project/build/./bin
llvm-lit: llvm-project/lldb/test/Shell/lit.cfg.py:125: warning: Could not set a default per-test timeout. Requires the Python psutil module but it could not be found. Try installing it via pip or via your operating system's package manager.
-- Testing: 4 tests, 4 workers --
PASS: lldb-shell :: lldb-server/TestGdbserverErrorMessages.test (1 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformHelp.test (2 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformErrorMessages.test (3 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformSuccessfulStartup.test (4 of 4)

Testing Time: 1.10s

Total Discovered Tests: 4
  Passed: 4 (100.00%)

1 warning(s) in tests
```
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
The lldb-server platform help text is inconsistent with lldb-server
gdbserver help text. This PR modernizes the platform server to use
LLVM's [TableGen](https://llvm.org/docs/TableGen/)-based option parsing
(matching the existing gdbserver implementation), which auto-generates
option parsing code and help text.

The changes improve documentation quality by adding comprehensive option
descriptions,, adding support for `-h`/`--help` flags, and organizing
help output with DESCRIPTION and EXAMPLES sections. Internal-only
options (`--child-platform-fd`) and unused legacy options (`--debug`,
`--verbose`) are now hidden from help while maintaining backward
compatibility. All functional behavior remains unchanged—this is purely
a documentation and code modernization improvement.

## before
```
> /opt/llvm/bin/lldb-server p -h
p: unrecognized option '-h'
Usage:
  /opt/llvm/bin/lldb-server p [--log-file log-file-name] [--log-channels log-channel-list] [--port-file port-file-path] --server --listen port
```

## after
```
lldb-server p -h 
OVERVIEW: lldb-server platform

USAGE: lldb-server p [options] --listen <[host]:port> [[--] program args...]

CONNECTION OPTIONS:
  --gdbserver-port <port> Port to use for spawned gdbserver instances. If 0 or unspecified, a port will be chosen automatically. Short form: -P
  --listen <[host]:port>  Host and port to listen on. Format: [host]:port or protocol://[host]:port (e.g., tcp://localhost:1234, unix:///path/to/socket). Short form: -L
  --socket-file <path>    Write listening socket information (port number for TCP or path for Unix domain sockets) to the specified file. Short form: -f

GENERAL OPTIONS:
  --help            Display this help message and exit.
  --log-channels <channel1 categories...:channel2 categories...>
                    Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories. Common channels: lldb, gdb-remote, platform, process. Short form: -c
  --log-file <file> Destination file to log to. If empty, log to stderr. Short form: -l
  --server          Run in server mode, accepting multiple client connections sequentially. Without this flag, the server exits after handling the first connection.

OPTIONS:
  -- program args Arguments to pass to launched gdbserver instances.

DESCRIPTION
  Acts as a platform server for remote debugging. When LLDB clients connect,
  the platform server handles platform operations (file transfers, process
  launching) and spawns debug server instances (lldb-server gdbserver) to
  handle actual debugging sessions.

  By default, the server exits after handling one connection. Use --server
  to keep running and accept multiple connections sequentially.

EXAMPLES
  # Listen on port 1234, exit after first connection
  lldb-server platform --listen tcp://0.0.0.0:1234

  # Listen on port 5555, accept multiple connections
  lldb-server platform --server --listen tcp://localhost:5555

  # Listen on Unix domain socket
  lldb-server platform --listen unix:///tmp/lldb-server.sock

```

For comparison, here is the **gdbserver** help text:
```
lldb-server g -h
OVERVIEW: lldb-server

USAGE: lldb-server g[dbserver] [options] [[host]:port] [[--] program args...]

CONNECTION:
  --fd <fd>           Communicate over the given file descriptor.
  --named-pipe <name> Write port lldb-server will listen on to the given named pipe.
  --pipe <fd>         Write port lldb-server will listen on to the given file descriptor.
  --reverse-connect   Connect to the client instead of passively waiting for a connection. In this case [host]:port denotes the remote address to connect to.

GENERAL OPTIONS:
  --help            Prints out the usage information for lldb-server.
  --log-channels <channel1 categories...:channel2 categories...>
                    Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories.
  --log-file <file> Destination file to log to. If empty, log to stderr.
  --setsid          Run lldb-server in a new session.

TARGET SELECTION:
  --attach <pid-or-name> Attach to the process given by a (numeric) process id or a name.
  -- program args        Launch program for debugging.

DESCRIPTION
  lldb-server connects to the LLDB client, which drives the debugging session.
  If no connection options are given, the [host]:port argument must be present
  and will denote the address that lldb-server will listen on. [host] defaults
  to "localhost" if empty. Port can be zero, in which case the port number will
  be chosen dynamically and written to destinations given by --named-pipe and
  --pipe arguments.

  If no target is selected at startup, lldb-server can be directed by the LLDB
  client to launch or attach to a process.
```
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
Fix windows test failures from
llvm#162730 by including and
optional .exe on the lldb-server name. Still passes on linux, but should
pass on windows now.

```
> bin/llvm-lit -v tools/lldb/test/Shell/lldb-server/
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using clang: llvm-project/build/bin/clang
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld.lld: /usr/bin/ld.lld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using lld-link: /usr/bin/lld-link
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using ld64.lld: /usr/bin/ld64.lld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/config.py:531: note: using wasm-ld: /usr/bin/wasm-ld
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/subst.py:126: note: Did not find obj2yaml in llvm-project/build/./bin:llvm-project/build/./bin
llvm-lit: llvm-project/llvm/utils/lit/lit/llvm/subst.py:126: note: Did not find llvm-objdump in llvm-project/build/./bin:llvm-project/build/./bin
llvm-lit: llvm-project/lldb/test/Shell/lit.cfg.py:125: warning: Could not set a default per-test timeout. Requires the Python psutil module but it could not be found. Try installing it via pip or via your operating system's package manager.
-- Testing: 4 tests, 4 workers --
PASS: lldb-shell :: lldb-server/TestGdbserverErrorMessages.test (1 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformHelp.test (2 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformErrorMessages.test (3 of 4)
PASS: lldb-shell :: lldb-server/TestPlatformSuccessfulStartup.test (4 of 4)

Testing Time: 1.10s

Total Discovered Tests: 4
  Passed: 4 (100.00%)

1 warning(s) in tests
```
aokblast pushed a commit to aokblast/llvm-project that referenced this pull request Oct 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants