JDevlieghere updated this revision to Diff 175377.
JDevlieghere added a comment.

Will land this tomorrow once we've figured out how to integrate tablegen with 
the Xcode project.

In the meantime I found some issues due to ordering of command options. Their 
relative order matters and we had tests relying on this. For example consider 
what happens when you say

  lldb -o 'do one thing' -s 'source/some/file'

You'd expect that the one-line is executed before sourcing the file. This 
wasn't the case with the previous version of this patch and is now fixed.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D54692/new/

https://reviews.llvm.org/D54692

Files:
  tools/driver/CMakeLists.txt
  tools/driver/Driver.cpp
  tools/driver/Driver.h
  tools/driver/Options.td

Index: tools/driver/Options.td
===================================================================
--- /dev/null
+++ tools/driver/Options.td
@@ -0,0 +1,218 @@
+include "llvm/Option/OptParser.td"
+
+class F<string name>: Flag<["--", "-"], name>;
+class S<string name>: Separate<["--", "-"], name>;
+class R<list<string> prefixes, string name>
+  : Option<prefixes, name, KIND_REMAINING_ARGS>;
+
+// Attaching options.
+def grp_attach : OptionGroup<"attaching">, HelpText<"ATTACHING">;
+
+def attach_name: Separate<["--", "-"], "attach-name">,
+  MetaVarName<"<name>">,
+  HelpText<"Tells the debugger to attach to a process with the given name.">,
+  Group<grp_attach>;
+def: Separate<["-"], "n">,
+  Alias<attach_name>,
+  HelpText<"Alias for --attach-name">,
+  Group<grp_attach>;
+
+def wait_for: F<"wait-for">,
+  HelpText<"Tells the debugger to wait for a process with the given pid or name to launch before attaching.">,
+  Group<grp_attach>;
+def: Flag<["-"], "w">,
+  Alias<wait_for>,
+  HelpText<"Alias for --wait-for">,
+  Group<grp_attach>;
+
+def attach_pid: Separate<["--", "-"], "attach-pid">,
+  MetaVarName<"<pid>">,
+  HelpText<"Tells the debugger to attach to a process with the given pid.">,
+  Group<grp_attach>;
+def: Separate<["-"], "p">,
+  Alias<attach_pid>,
+  HelpText<"Alias for --attach-pid">,
+  Group<grp_attach>;
+
+
+// Scripting options.
+def grp_scripting : OptionGroup<"scripting">, HelpText<"SCRIPTING">;
+
+def python_path: F<"python-path">,
+  HelpText<"Prints out the path to the lldb.py file for this version of lldb.">,
+  Group<grp_scripting>;
+def: Flag<["-"], "P">,
+  Alias<python_path>,
+  HelpText<"Alias for --python-path">,
+  Group<grp_scripting>;
+
+def script_language: Separate<["--", "-"], "script-language">, MetaVarName<"<language>">,
+  HelpText<"Tells the debugger to use the specified scripting language for user-defined scripts.">,
+  Group<grp_scripting>;
+def: Separate<["-"], "l">,
+  Alias<script_language>,
+  HelpText<"Alias for --script-language">,
+  Group<grp_scripting>;
+
+// Repl options.
+def grp_repl : OptionGroup<"repl">, HelpText<"REPL">;
+
+def repl: Separate<["--", "-"], "repl">,
+  HelpText<"Runs lldb in REPL mode with a stub process.">,
+  Group<grp_repl>;
+def: Separate<["-"], "r">,
+  Alias<repl>,
+  HelpText<"Alias for --repl">,
+  Group<grp_repl>;
+
+def repl_language: Separate<["--", "-"], "repl-language">,
+  MetaVarName<"<language>">,
+  HelpText<"Chooses the language for the REPL.">,
+  Group<grp_repl>;
+def: Separate<["-"], "R">,
+  Alias<repl_language>,
+  HelpText<"Alias for --repl-language">,
+  Group<grp_repl>;
+
+
+// Command options.
+def grp_command : OptionGroup<"command">, HelpText<"COMMANDS">;
+
+def no_lldbinit: F<"no-lldbinit">,
+  HelpText<"Do not automatically parse any '.lldbinit' files.">,
+  Group<grp_command>;
+def: Flag<["-"], "x">,
+  Alias<no_lldbinit>,
+  HelpText<"Alias for --no-lldbinit">,
+  Group<grp_command>;
+
+def batch: F<"batch">,
+  HelpText<"Tells the debugger to run the commands from -s, -S, -o & -O, and then quit.">,
+  Group<grp_command>;
+def: Flag<["-"], "b">,
+  Alias<batch>,
+  HelpText<"Alias for --batch">,
+  Group<grp_command>;
+
+def source_quietly: F<"source-quietly">,
+  HelpText<"Tells the debugger to execute this one-line lldb command before any file has been loaded.">,
+  Group<grp_command>;
+def: Flag<["-"], "Q">,
+  Alias<source_quietly>,
+  HelpText<"Alias for --source-quietly">,
+  Group<grp_command>;
+
+def one_line_on_crash: Separate<["--", "-"], "one-line-on-crash">,
+  MetaVarName<"<command>">,
+  HelpText<"When in batch mode, tells the debugger to source this file of lldb commands if the target crashes.">,
+  Group<grp_command>;
+def: Separate<["-"], "k">,
+  Alias<one_line_on_crash>,
+  HelpText<"Alias for --one-line-on-crash">,
+  Group<grp_command>;
+
+def source_on_crash: Separate<["--", "-"], "source-on-crash">,
+  MetaVarName<"<file>">,
+  HelpText<"When in batch mode, tells the debugger to source this file of lldb commands if the target crashes.">,
+  Group<grp_command>;
+def: Separate<["-"], "K">,
+  Alias<source_on_crash>,
+  HelpText<"Alias for --source-on-crash">,
+  Group<grp_command>;
+
+def source: Separate<["--", "-"], "source">,
+  MetaVarName<"<file>">,
+  HelpText<"Tells the debugger to read in and execute the lldb commands in the given file, after any file has been loaded.">,
+  Group<grp_command>;
+def: Separate<["-"], "s">,
+  Alias<source>,
+  HelpText<"Alias for --source">,
+  Group<grp_command>;
+
+def source_before_file: Separate<["--", "-"], "source-before-file">,
+  MetaVarName<"<file>">,
+  HelpText<"Tells the debugger to read in and execute the lldb commands in the given file, before any file has been loaded.">,
+  Group<grp_command>;
+def: Separate<["-"], "S">,
+  Alias<source_before_file>,
+  HelpText<"Alias for --source-before-file">,
+  Group<grp_command>;
+
+def one_line: Separate<["--", "-"], "one-line">,
+  MetaVarName<"<command>">,
+  HelpText<"Tells the debugger to execute this one-line lldb command after any file provided on the command line has been loaded.">,
+  Group<grp_command>;
+def: Separate<["-"], "o">,
+  Alias<one_line>,
+  HelpText<"Alias for --one-line">,
+  Group<grp_command>;
+
+def one_line_before_file: Separate<["--", "-"], "one-line-before-file">,
+  MetaVarName<"<command>">,
+  HelpText<"Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded.">,
+  Group<grp_command>;
+def: Separate<["-"], "O">,
+  Alias<one_line_before_file>,
+  HelpText<"Alias for --one-line-before-file">,
+  Group<grp_command>;
+
+
+// General options.
+def version: F<"version">,
+  HelpText<"Prints out the current version number of the LLDB debugger.">;
+def: Flag<["-"], "v">,
+  Alias<version>,
+  HelpText<"Alias for --version">;
+
+def help: F<"help">,
+  HelpText<"Prints out the usage information for the LLDB debugger.">;
+def: Flag<["-"], "h">,
+  Alias<help>,
+  HelpText<"Alias for --help">;
+
+def core: F<"core">,
+  HelpText<"Tells the debugger to use the full path to <core> as the core file.">;
+def: Flag<["-"], "c">,
+  Alias<core>,
+  HelpText<"Alias for --core">;
+
+def editor: F<"editor">,
+  HelpText<"Tells the debugger to open source files using the host's \"external editor\" mechanism.">;
+def: Flag<["-"], "e">,
+  Alias<editor>,
+  HelpText<"Alias for --editor">;
+
+def no_use_colors: F<"no-use-colors">,
+  HelpText<"Do not use colors.">;
+def: Flag<["-"], "X">,
+  Alias<no_use_colors>,
+  HelpText<"Alias for --no-use-color">;
+
+def file: Separate<["--", "-"], "file">,
+  MetaVarName<"<filename>">,
+  HelpText<"Tells the debugger to use the file <filename> as the program to be debugged.">;
+def: Separate<["-"], "f">,
+  Alias<file>,
+  HelpText<"Alias for --file">;
+
+def arch: Separate<["--", "-"], "arch">,
+  MetaVarName<"<architecture>">,
+  HelpText<"Tells the debugger to use the specified architecture when starting and running the program.">;
+def: Separate<["-"], "a">,
+  Alias<arch>,
+  HelpText<"Alias for --arch">;
+
+def debug: F<"debug">,
+  HelpText<"Tells the debugger to print out extra information for debugging itself.">;
+def: Flag<["-"], "d">,
+  Alias<debug>,
+  HelpText<"Alias for --debug">;
+
+def reproducer: Separate<["--", "-"], "reproducer">,
+  MetaVarName<"<filename>">,
+  HelpText<"Tells the debugger to use the fullpath to <filename> as a reproducer.">;
+def: Separate<["-"], "z">,
+  Alias<file>,
+  HelpText<"Alias for --reproducer">;
+
+def REM : R<["--"], "">;
Index: tools/driver/Driver.h
===================================================================
--- tools/driver/Driver.h
+++ tools/driver/Driver.h
@@ -12,15 +12,19 @@
 
 #include "Platform.h"
 
-#include <set>
-#include <string>
-#include <vector>
-
 #include "lldb/API/SBBroadcaster.h"
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBDefines.h"
 #include "lldb/API/SBError.h"
 
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
 class Driver : public lldb::SBBroadcaster {
 public:
   typedef enum CommandPlacement {
@@ -38,8 +42,8 @@
   /// @return The exit code that the process should return.
   int MainLoop();
 
-  lldb::SBError ParseArgs(int argc, const char *argv[], FILE *out_fh,
-                          bool &do_exit);
+  lldb::SBError ProcessArgs(const llvm::opt::InputArgList &args, FILE *out_fh,
+                            bool &do_exit);
 
   const char *GetFilename() const;
 
@@ -61,13 +65,13 @@
 
     void Clear();
 
-    void AddInitialCommand(const char *command, CommandPlacement placement,
+    void AddInitialCommand(std::string command, CommandPlacement placement,
                            bool is_file, lldb::SBError &error);
 
     struct InitialCmdEntry {
-      InitialCmdEntry(const char *in_contents, bool in_is_file,
+      InitialCmdEntry(std::string contents, bool in_is_file,
                       bool is_cwd_lldbinit_file_read, bool in_quiet = false)
-          : contents(in_contents), is_file(in_is_file),
+          : contents(std::move(contents)), is_file(in_is_file),
             is_cwd_lldbinit_file_read(is_cwd_lldbinit_file_read),
             source_quietly(in_quiet) {}
 
@@ -89,7 +93,6 @@
     bool m_source_quietly;
     bool m_print_version;
     bool m_print_python_path;
-    bool m_print_help;
     bool m_wait_for;
     bool m_repl;
     lldb::LanguageType m_repl_lang;
Index: tools/driver/Driver.cpp
===================================================================
--- tools/driver/Driver.cpp
+++ tools/driver/Driver.cpp
@@ -9,26 +9,6 @@
 
 #include "Driver.h"
 
-#include <algorithm>
-#include <atomic>
-#include <bitset>
-#include <csignal>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-// Includes for pipe()
-#if defined(_WIN32)
-#include <fcntl.h>
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
-#include <string>
-
 #include "lldb/API/SBBreakpoint.h"
 #include "lldb/API/SBCommandInterpreter.h"
 #include "lldb/API/SBCommandReturnObject.h"
@@ -43,18 +23,74 @@
 #include "lldb/API/SBStringList.h"
 #include "lldb/API/SBTarget.h"
 #include "lldb/API/SBThread.h"
+
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/PrettyStackTrace.h"
 #include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
+#include <atomic>
+#include <bitset>
+#include <csignal>
+#include <string>
 #include <thread>
 #include <utility>
 
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Includes for pipe()
+#if defined(_WIN32)
+#include <fcntl.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
 #if !defined(__APPLE__)
 #include "llvm/Support/DataTypes.h"
 #endif
 
 using namespace lldb;
+using namespace llvm;
+
+namespace {
+enum ID {
+  OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
+               HELPTEXT, METAVAR, VALUES)                                      \
+  OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+static const opt::OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
+               HELPTEXT, METAVAR, VALUES)                                      \
+  {                                                                            \
+      PREFIX,      NAME,      HELPTEXT,                                        \
+      METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
+      PARAM,       FLAGS,     OPT_##GROUP,                                     \
+      OPT_##ALIAS, ALIASARGS, VALUES},
+#include "Options.inc"
+#undef OPTION
+};
+
+class LLDBOptTable : public opt::OptTable {
+public:
+  LLDBOptTable() : OptTable(InfoTable) {}
+};
+} // namespace
 
 static void reset_stdin_termios();
 static bool g_old_stdin_termios_is_valid = false;
@@ -71,110 +107,6 @@
   }
 }
 
-typedef struct {
-  uint32_t usage_mask; // Used to mark options that can be used together.  If (1
-                       // << n & usage_mask) != 0
-                       // then this option belongs to option set n.
-  bool required;       // This option is required (in the current usage level)
-  const char *long_option; // Full name for this option.
-  int short_option;        // Single character for this option.
-  int option_has_arg; // no_argument, required_argument or optional_argument
-  uint32_t completion_type; // Cookie the option class can use to do define the
-                            // argument completion.
-  lldb::CommandArgumentType argument_type; // Type of argument this option takes
-  const char *usage_text; // Full text explaining what this options does and
-                          // what (if any) argument to
-                          // pass it.
-} OptionDefinition;
-
-#define LLDB_3_TO_5 LLDB_OPT_SET_3 | LLDB_OPT_SET_4 | LLDB_OPT_SET_5
-#define LLDB_4_TO_5 LLDB_OPT_SET_4 | LLDB_OPT_SET_5
-
-static constexpr OptionDefinition g_options[] = {
-    {LLDB_OPT_SET_1, true, "help", 'h', no_argument, 0, eArgTypeNone,
-     "Prints out the usage information for the LLDB debugger."},
-    {LLDB_OPT_SET_2, true, "version", 'v', no_argument, 0, eArgTypeNone,
-     "Prints out the current version number of the LLDB debugger."},
-    {LLDB_OPT_SET_3, true, "arch", 'a', required_argument, 0,
-     eArgTypeArchitecture,
-     "Tells the debugger to use the specified architecture when starting and "
-     "running the program.  <architecture> must "
-     "be one of the architectures for which the program was compiled."},
-    {LLDB_OPT_SET_3, true, "file", 'f', required_argument, 0, eArgTypeFilename,
-     "Tells the debugger to use the file <filename> as the program to be "
-     "debugged."},
-    {LLDB_OPT_SET_3, false, "core", 'c', required_argument, 0, eArgTypeFilename,
-     "Tells the debugger to use the fullpath to <path> as the core file."},
-    {LLDB_OPT_SET_5, true, "attach-pid", 'p', required_argument, 0, eArgTypePid,
-     "Tells the debugger to attach to a process with the given pid."},
-    {LLDB_OPT_SET_4, true, "attach-name", 'n', required_argument, 0,
-     eArgTypeProcessName,
-     "Tells the debugger to attach to a process with the given name."},
-    {LLDB_OPT_SET_4, true, "wait-for", 'w', no_argument, 0, eArgTypeNone,
-     "Tells the debugger to wait for a process with the given pid or name to "
-     "launch before attaching."},
-    {LLDB_3_TO_5, false, "source", 's', required_argument, 0, eArgTypeFilename,
-     "Tells the debugger to read in and execute the lldb commands in the given "
-     "file, after any file provided on the command line has been loaded."},
-    {LLDB_3_TO_5, false, "one-line", 'o', required_argument, 0, eArgTypeNone,
-     "Tells the debugger to execute this one-line lldb command after any file "
-     "provided on the command line has been loaded."},
-    {LLDB_3_TO_5, false, "source-before-file", 'S', required_argument, 0,
-     eArgTypeFilename,
-     "Tells the debugger to read in and execute the lldb "
-     "commands in the given file, before any file provided "
-     "on the command line has been loaded."},
-    {LLDB_3_TO_5, false, "one-line-before-file", 'O', required_argument, 0,
-     eArgTypeNone,
-     "Tells the debugger to execute this one-line lldb command "
-     "before any file provided on the command line has been "
-     "loaded."},
-    {LLDB_3_TO_5, false, "one-line-on-crash", 'k', required_argument, 0,
-     eArgTypeNone,
-     "When in batch mode, tells the debugger to execute this "
-     "one-line lldb command if the target crashes."},
-    {LLDB_3_TO_5, false, "source-on-crash", 'K', required_argument, 0,
-     eArgTypeFilename,
-     "When in batch mode, tells the debugger to source this "
-     "file of lldb commands if the target crashes."},
-    {LLDB_3_TO_5, false, "source-quietly", 'Q', no_argument, 0, eArgTypeNone,
-     "Tells the debugger to execute this one-line lldb command before any file "
-     "provided on the command line has been loaded."},
-    {LLDB_3_TO_5, false, "batch", 'b', no_argument, 0, eArgTypeNone,
-     "Tells the debugger to run the commands from -s, -S, -o & -O, and "
-     "then quit.  However if any run command stopped due to a signal or crash, "
-     "the debugger will return to the interactive prompt at the place of the "
-     "crash."},
-    {LLDB_3_TO_5, false, "editor", 'e', no_argument, 0, eArgTypeNone,
-     "Tells the debugger to open source files using the host's \"external "
-     "editor\" mechanism."},
-    {LLDB_3_TO_5, false, "no-lldbinit", 'x', no_argument, 0, eArgTypeNone,
-     "Do not automatically parse any '.lldbinit' files."},
-    {LLDB_3_TO_5, false, "no-use-colors", 'X', no_argument, 0, eArgTypeNone,
-     "Do not use colors."},
-    {LLDB_OPT_SET_6, true, "python-path", 'P', no_argument, 0, eArgTypeNone,
-     "Prints out the path to the lldb.py file for this version of lldb."},
-    {LLDB_3_TO_5, false, "script-language", 'l', required_argument, 0,
-     eArgTypeScriptLang,
-     "Tells the debugger to use the specified scripting language for "
-     "user-defined scripts, rather than the default.  "
-     "Valid scripting languages that can be specified include Python, Perl, "
-     "Ruby and Tcl.  Currently only the Python "
-     "extensions have been implemented."},
-    {LLDB_3_TO_5, false, "debug", 'd', no_argument, 0, eArgTypeNone,
-     "Tells the debugger to print out extra information for debugging itself."},
-    {LLDB_3_TO_5, false, "reproducer", 'z', required_argument, 0,
-     eArgTypeFilename,
-     "Tells the debugger to use the fullpath to <path> as a reproducer."},
-    {LLDB_OPT_SET_7, true, "repl", 'r', optional_argument, 0, eArgTypeNone,
-     "Runs lldb in REPL mode with a stub process."},
-    {LLDB_OPT_SET_7, true, "repl-language", 'R', required_argument, 0,
-     eArgTypeNone, "Chooses the language for the REPL."}};
-
-static constexpr auto g_num_options = sizeof(g_options)/sizeof(OptionDefinition);
-
-static const uint32_t last_option_set_with_args = 2;
-
 Driver::Driver()
     : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)),
       m_option_data() {
@@ -186,241 +118,14 @@
 
 Driver::~Driver() { g_driver = NULL; }
 
-// This function takes INDENT, which tells how many spaces to output at the
-// front
-// of each line; TEXT, which is the text that is to be output. It outputs the
-// text, on multiple lines if necessary, to RESULT, with INDENT spaces at the
-// front of each line.  It breaks lines on spaces, tabs or newlines, shortening
-// the line if necessary to not break in the middle of a word. It assumes that
-// each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
-
-void OutputFormattedUsageText(FILE *out, int indent, const char *text,
-                              int output_max_columns) {
-  int len = strlen(text);
-  std::string text_string(text);
-
-  // Force indentation to be reasonable.
-  if (indent >= output_max_columns)
-    indent = 0;
-
-  // Will it all fit on one line?
-
-  if (len + indent < output_max_columns)
-    // Output as a single line
-    fprintf(out, "%*s%s\n", indent, "", text);
-  else {
-    // We need to break it up into multiple lines.
-    int text_width = output_max_columns - indent - 1;
-    int start = 0;
-    int end = start;
-    int final_end = len;
-    int sub_len;
-
-    while (end < final_end) {
-      // Dont start the 'text' on a space, since we're already outputting the
-      // indentation.
-      while ((start < final_end) && (text[start] == ' '))
-        start++;
-
-      end = start + text_width;
-      if (end > final_end)
-        end = final_end;
-      else {
-        // If we're not at the end of the text, make sure we break the line on
-        // white space.
-        while (end > start && text[end] != ' ' && text[end] != '\t' &&
-               text[end] != '\n')
-          end--;
-      }
-      sub_len = end - start;
-      std::string substring = text_string.substr(start, sub_len);
-      fprintf(out, "%*s%s\n", indent, "", substring.c_str());
-      start = end + 1;
-    }
-  }
-}
-
-static void ShowUsage(FILE *out, Driver::OptionData data) {
-  uint32_t screen_width = 80;
-  uint32_t indent_level = 0;
-  const char *name = "lldb";
-
-  fprintf(out, "\nUsage:\n\n");
-
-  indent_level += 2;
-
-  // First, show each usage level set of options, e.g. <cmd>
-  // [options-for-level-0]
-  //                                                   <cmd>
-  //                                                   [options-for-level-1]
-  //                                                   etc.
-
-  uint32_t num_option_sets = 0;
-
-  for (const auto &opt : g_options) {
-    uint32_t this_usage_mask = opt.usage_mask;
-    if (this_usage_mask == LLDB_OPT_SET_ALL) {
-      if (num_option_sets == 0)
-        num_option_sets = 1;
-    } else {
-      for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) {
-        if (this_usage_mask & 1 << j) {
-          if (num_option_sets <= j)
-            num_option_sets = j + 1;
-        }
-      }
-    }
-  }
-
-  for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++) {
-    uint32_t opt_set_mask;
-
-    opt_set_mask = 1 << opt_set;
-
-    if (opt_set > 0)
-      fprintf(out, "\n");
-    fprintf(out, "%*s%s", indent_level, "", name);
-    bool is_help_line = false;
-
-    for (const auto &opt : g_options) {
-      if (opt.usage_mask & opt_set_mask) {
-        CommandArgumentType arg_type = opt.argument_type;
-        const char *arg_name =
-            SBCommandInterpreter::GetArgumentTypeAsCString(arg_type);
-        // This is a bit of a hack, but there's no way to say certain options
-        // don't have arguments yet...
-        // so we do it by hand here.
-        if (opt.short_option == 'h')
-          is_help_line = true;
-
-        if (opt.required) {
-          if (opt.option_has_arg == required_argument)
-            fprintf(out, " -%c <%s>", opt.short_option, arg_name);
-          else if (opt.option_has_arg == optional_argument)
-            fprintf(out, " -%c [<%s>]", opt.short_option, arg_name);
-          else
-            fprintf(out, " -%c", opt.short_option);
-        } else {
-          if (opt.option_has_arg == required_argument)
-            fprintf(out, " [-%c <%s>]", opt.short_option, arg_name);
-          else if (opt.option_has_arg == optional_argument)
-            fprintf(out, " [-%c [<%s>]]", opt.short_option,
-                    arg_name);
-          else
-            fprintf(out, " [-%c]", opt.short_option);
-        }
-      }
-    }
-    if (!is_help_line && (opt_set <= last_option_set_with_args))
-      fprintf(out, " [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]");
-  }
-
-  fprintf(out, "\n\n");
-
-  // Now print out all the detailed information about the various options:  long
-  // form, short form and help text:
-  //   -- long_name <argument>
-  //   - short <argument>
-  //   help text
-
-  // This variable is used to keep track of which options' info we've printed
-  // out, because some options can be in
-  // more than one usage level, but we only want to print the long form of its
-  // information once.
-
-  Driver::OptionData::OptionSet options_seen;
-  Driver::OptionData::OptionSet::iterator pos;
-
-  indent_level += 5;
-
-  for (const auto &opt : g_options) {
-    // Only print this option if we haven't already seen it.
-    pos = options_seen.find(opt.short_option);
-    if (pos == options_seen.end()) {
-      CommandArgumentType arg_type = opt.argument_type;
-      const char *arg_name =
-          SBCommandInterpreter::GetArgumentTypeAsCString(arg_type);
-
-      options_seen.insert(opt.short_option);
-      fprintf(out, "%*s-%c ", indent_level, "", opt.short_option);
-      if (arg_type != eArgTypeNone)
-        fprintf(out, "<%s>", arg_name);
-      fprintf(out, "\n");
-      fprintf(out, "%*s--%s ", indent_level, "", opt.long_option);
-      if (arg_type != eArgTypeNone)
-        fprintf(out, "<%s>", arg_name);
-      fprintf(out, "\n");
-      indent_level += 5;
-      OutputFormattedUsageText(out, indent_level, opt.usage_text,
-                               screen_width);
-      indent_level -= 5;
-      fprintf(out, "\n");
-    }
-  }
-
-  indent_level -= 5;
-
-  fprintf(out, "\n%*sNotes:\n", indent_level, "");
-  indent_level += 5;
-
-  fprintf(out,
-          "\n%*sMultiple \"-s\" and \"-o\" options can be provided.  They will "
-          "be processed"
-          "\n%*sfrom left to right in order, with the source files and commands"
-          "\n%*sinterleaved.  The same is true of the \"-S\" and \"-O\" "
-          "options.  The before"
-          "\n%*sfile and after file sets can intermixed freely, the command "
-          "parser will"
-          "\n%*ssort them out.  The order of the file specifiers (\"-c\", "
-          "\"-f\", etc.) is"
-          "\n%*snot significant in this regard.\n\n",
-          indent_level, "", indent_level, "", indent_level, "", indent_level,
-          "", indent_level, "", indent_level, "");
-
-  fprintf(
-      out,
-      "\n%*sIf you don't provide -f then the first argument will be the file "
-      "to be"
-      "\n%*sdebugged which means that '%s -- <filename> [<ARG1> [<ARG2>]]' also"
-      "\n%*sworks.  But remember to end the options with \"--\" if any of your"
-      "\n%*sarguments have a \"-\" in them.\n\n",
-      indent_level, "", indent_level, "", name, indent_level, "", indent_level,
-      "");
-}
-
- static void BuildGetOptTable(std::vector<option> &getopt_table) {
-  getopt_table.resize(g_num_options + 1);
-
-  std::bitset<256> option_seen;
-  uint32_t j = 0;
-  for (const auto &opt : g_options) {
-    char short_opt = opt.short_option;
-
-    if (option_seen.test(short_opt) == false) {
-      getopt_table[j].name = opt.long_option;
-      getopt_table[j].has_arg = opt.option_has_arg;
-      getopt_table[j].flag = NULL;
-      getopt_table[j].val = opt.short_option;
-      option_seen.set(short_opt);
-      ++j;
-    }
-  }
-
-  getopt_table[j].name = NULL;
-  getopt_table[j].has_arg = 0;
-  getopt_table[j].flag = NULL;
-  getopt_table[j].val = 0;
-}
-
 Driver::OptionData::OptionData()
     : m_args(), m_script_lang(lldb::eScriptLanguageDefault), m_core_file(),
       m_crash_log(), m_initial_commands(), m_after_file_commands(),
       m_after_crash_commands(), m_debug_mode(false), m_source_quietly(false),
-      m_print_version(false), m_print_python_path(false), m_print_help(false),
-      m_wait_for(false), m_repl(false), m_repl_lang(eLanguageTypeUnknown),
-      m_repl_options(), m_process_name(),
-      m_process_pid(LLDB_INVALID_PROCESS_ID), m_use_external_editor(false),
-      m_batch(false), m_seen_options() {}
+      m_print_version(false), m_print_python_path(false), m_wait_for(false),
+      m_repl(false), m_repl_lang(eLanguageTypeUnknown), m_repl_options(),
+      m_process_name(), m_process_pid(LLDB_INVALID_PROCESS_ID),
+      m_use_external_editor(false), m_batch(false), m_seen_options() {}
 
 Driver::OptionData::~OptionData() {}
 
@@ -441,9 +146,8 @@
   // Only read .lldbinit in the current working directory
   // if it's not the same as the .lldbinit in the home
   // directory (which is already being read in).
-  if (local_lldbinit.Exists() &&
-      strcmp(local_lldbinit.GetDirectory(), homedir_dot_lldb.GetDirectory()) !=
-          0) {
+  if (local_lldbinit.Exists() && strcmp(local_lldbinit.GetDirectory(),
+                                        homedir_dot_lldb.GetDirectory()) != 0) {
     char path[2048];
     local_lldbinit.GetPath(path, 2047);
     InitialCmdEntry entry(path, true, true, true);
@@ -452,7 +156,6 @@
 
   m_debug_mode = false;
   m_source_quietly = false;
-  m_print_help = false;
   m_print_version = false;
   m_print_python_path = false;
   m_use_external_editor = false;
@@ -464,7 +167,7 @@
   m_process_pid = LLDB_INVALID_PROCESS_ID;
 }
 
-void Driver::OptionData::AddInitialCommand(const char *command,
+void Driver::OptionData::AddInitialCommand(std::string command,
                                            CommandPlacement placement,
                                            bool is_file, SBError &error) {
   std::vector<InitialCmdEntry> *command_set;
@@ -481,7 +184,7 @@
   }
 
   if (is_file) {
-    SBFileSpec file(command);
+    SBFileSpec file(command.c_str());
     if (file.Exists())
       command_set->push_back(InitialCmdEntry(command, is_file, false));
     else if (file.ResolveExecutableLocation()) {
@@ -490,7 +193,8 @@
       command_set->push_back(InitialCmdEntry(final_path, is_file, false));
     } else
       error.SetErrorStringWithFormat(
-          "file specified in --source (-s) option doesn't exist: '%s'", optarg);
+          "file specified in --source (-s) option doesn't exist: '%s'",
+          command.c_str());
   } else
     command_set->push_back(InitialCmdEntry(command, is_file, false));
 }
@@ -572,259 +276,239 @@
 bool Driver::GetDebugMode() const { return m_option_data.m_debug_mode; }
 
 // Check the arguments that were passed to this program to make sure they are
-// valid and to get their
-// argument values (if any).  Return a boolean value indicating whether or not
-// to start up the full
-// debugger (i.e. the Command Interpreter) or not.  Return FALSE if the
-// arguments were invalid OR
-// if the user only wanted help or version information.
+// valid and to get their argument values (if any).  Return a boolean value
+// indicating whether or not to start up the full debugger (i.e. the Command
+// Interpreter) or not.  Return FALSE if the arguments were invalid OR if the
+// user only wanted help or version information.
+SBError Driver::ProcessArgs(const opt::InputArgList &args, FILE *out_fh,
+                            bool &exiting) {
+  SBError error;
+  ResetOptionValues();
+
+  // This is kind of a pain, but since we make the debugger in the Driver's
+  // constructor, we can't know at that point whether we should read in init
+  // files yet.  So we don't read them in in the Driver constructor, then set
+  // the flags back to "read them in" here, and then if we see the "-n" flag,
+  // we'll turn it off again.  Finally we have to read them in by hand later in
+  // the main loop.
+  m_debugger.SkipLLDBInitFiles(false);
+  m_debugger.SkipAppInitFiles(false);
 
-SBError Driver::ParseArgs(int argc, const char *argv[], FILE *out_fh,
-                          bool &exiting) {
-  static_assert(g_num_options > 0, "cannot handle arguments");
+  if (args.hasArg(OPT_version)) {
+    m_option_data.m_print_version = true;
+  }
 
-  ResetOptionValues();
+  if (args.hasArg(OPT_python_path)) {
+    m_option_data.m_print_python_path = true;
+  }
 
-  SBError error;
-  std::vector<option> long_options_vector;
-  BuildGetOptTable(long_options_vector);
-  if (long_options_vector.empty()) {
-    error.SetErrorStringWithFormat("invalid long options");
-    return error;
+  if (args.hasArg(OPT_batch)) {
+    m_option_data.m_batch = true;
   }
 
-  // Build the option_string argument for call to getopt_long_only.
-  std::string option_string;
-  auto sentinel_it = std::prev(std::end(long_options_vector));
-  for (auto long_opt_it = std::begin(long_options_vector);
-            long_opt_it != sentinel_it; ++long_opt_it) {
-    if (long_opt_it->flag == nullptr) {
-      option_string.push_back(static_cast<char>(long_opt_it->val));
-      switch (long_opt_it->has_arg) {
-      default:
-      case no_argument:
-        break;
-      case required_argument:
-        option_string.push_back(':');
-        break;
-      case optional_argument:
-        option_string.append("::");
-        break;
-      }
+  if (args.hasArg(OPT_core)) {
+    SBFileSpec file(optarg);
+    if (file.Exists()) {
+      m_option_data.m_core_file = optarg;
+    } else {
+      error.SetErrorStringWithFormat(
+          "file specified in --core (-c) option doesn't exist: '%s'", optarg);
+      return error;
     }
   }
 
-  // This is kind of a pain, but since we make the debugger in the Driver's
-  // constructor, we can't
-  // know at that point whether we should read in init files yet.  So we don't
-  // read them in in the
-  // Driver constructor, then set the flags back to "read them in" here, and
-  // then if we see the
-  // "-n" flag, we'll turn it off again.  Finally we have to read them in by
-  // hand later in the
-  // main loop.
+  if (args.hasArg(OPT_editor)) {
+    m_option_data.m_use_external_editor = true;
+  }
 
-  m_debugger.SkipLLDBInitFiles(false);
-  m_debugger.SkipAppInitFiles(false);
+  if (args.hasArg(OPT_no_lldbinit)) {
+    m_debugger.SkipLLDBInitFiles(true);
+    m_debugger.SkipAppInitFiles(true);
+  }
 
-// Prepare for & make calls to getopt_long_only.
-#if __GLIBC__
-  optind = 0;
-#else
-  optreset = 1;
-  optind = 1;
-#endif
-  int val;
-  while (1) {
-    int long_options_index = -1;
-    val = ::getopt_long_only(argc, const_cast<char **>(argv),
-                             option_string.c_str(), long_options_vector.data(),
-                             &long_options_index);
-
-    if (val == -1)
-      break;
-    else if (val == '?') {
-      m_option_data.m_print_help = true;
-      error.SetErrorStringWithFormat("unknown or ambiguous option");
-      break;
-    } else if (val == 0)
-      continue;
-    else {
-      m_option_data.m_seen_options.insert((char)val);
-      if (long_options_index == -1) {
-        auto long_opt_it = std::find_if(std::begin(long_options_vector), sentinel_it,
-            [val](const option &long_option) { return long_option.val == val; });
-        if (std::end(long_options_vector) != long_opt_it)
-          long_options_index =
-              std::distance(std::begin(long_options_vector), long_opt_it);
-      }
+  if (args.hasArg(OPT_no_use_colors)) {
+    m_debugger.SetUseColor(false);
+  }
 
-      if (long_options_index >= 0) {
-        const int short_option = g_options[long_options_index].short_option;
-
-        switch (short_option) {
-        case 'h':
-          m_option_data.m_print_help = true;
-          break;
-
-        case 'v':
-          m_option_data.m_print_version = true;
-          break;
-
-        case 'P':
-          m_option_data.m_print_python_path = true;
-          break;
-
-        case 'b':
-          m_option_data.m_batch = true;
-          break;
-
-        case 'c': {
-          SBFileSpec file(optarg);
-          if (file.Exists()) {
-            m_option_data.m_core_file = optarg;
-          } else
-            error.SetErrorStringWithFormat(
-                "file specified in --core (-c) option doesn't exist: '%s'",
-                optarg);
-        } break;
-
-        case 'e':
-          m_option_data.m_use_external_editor = true;
-          break;
-
-        case 'x':
-          m_debugger.SkipLLDBInitFiles(true);
-          m_debugger.SkipAppInitFiles(true);
-          break;
-
-        case 'X':
-          m_debugger.SetUseColor(false);
-          break;
-
-        case 'f': {
-          SBFileSpec file(optarg);
-          if (file.Exists()) {
-            m_option_data.m_args.push_back(optarg);
-          } else if (file.ResolveExecutableLocation()) {
-            char path[PATH_MAX];
-            file.GetPath(path, sizeof(path));
-            m_option_data.m_args.push_back(path);
-          } else
-            error.SetErrorStringWithFormat(
-                "file specified in --file (-f) option doesn't exist: '%s'",
-                optarg);
-        } break;
-
-        case 'a':
-          if (!m_debugger.SetDefaultArchitecture(optarg))
-            error.SetErrorStringWithFormat(
-                "invalid architecture in the -a or --arch option: '%s'",
-                optarg);
-          break;
-
-        case 'l':
-          m_option_data.m_script_lang = m_debugger.GetScriptingLanguage(optarg);
-          break;
-
-        case 'd':
-          m_option_data.m_debug_mode = true;
-          break;
-
-        case 'z': {
-          SBFileSpec file(optarg);
-          if (file.Exists()) {
-            m_debugger.SetReproducerPath(optarg);
-          } else
-            error.SetErrorStringWithFormat("file specified in --reproducer "
-                                           "(-z) option doesn't exist: '%s'",
-                                           optarg);
-        } break;
-
-        case 'Q':
-          m_option_data.m_source_quietly = true;
-          break;
-
-        case 'K':
-          m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash,
-                                          true, error);
-          break;
-        case 'k':
-          m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash,
-                                          false, error);
-          break;
-
-        case 'n':
-          m_option_data.m_process_name = optarg;
-          break;
-
-        case 'w':
-          m_option_data.m_wait_for = true;
-          break;
-
-        case 'p': {
-          char *remainder;
-          m_option_data.m_process_pid = strtol(optarg, &remainder, 0);
-          if (remainder == optarg || *remainder != '\0')
-            error.SetErrorStringWithFormat(
-                "Could not convert process PID: \"%s\" into a pid.", optarg);
-        } break;
-
-        case 'r':
-          m_option_data.m_repl = true;
-          if (optarg && optarg[0])
-            m_option_data.m_repl_options = optarg;
-          else
-            m_option_data.m_repl_options.clear();
-          break;
-
-        case 'R':
-          m_option_data.m_repl_lang =
-              SBLanguageRuntime::GetLanguageTypeFromString(optarg);
-          if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
-            error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
-                                           optarg);
-          }
-          break;
-
-        case 's':
-          m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile,
-                                          true, error);
-          break;
-        case 'o':
-          m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile,
-                                          false, error);
-          break;
-        case 'S':
-          m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile,
-                                          true, error);
-          break;
-        case 'O':
-          m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile,
-                                          false, error);
-          break;
-        default:
-          m_option_data.m_print_help = true;
-          error.SetErrorStringWithFormat("unrecognized option %c",
-                                         short_option);
-          break;
-        }
-      } else {
-        error.SetErrorStringWithFormat("invalid option with value %i", val);
-      }
-      if (error.Fail()) {
+  if (auto *arg = args.getLastArg(OPT_file)) {
+    auto optarg = arg->getValue();
+    SBFileSpec file(optarg);
+    if (file.Exists()) {
+      m_option_data.m_args.push_back(optarg);
+    } else if (file.ResolveExecutableLocation()) {
+      char path[PATH_MAX];
+      file.GetPath(path, sizeof(path));
+      m_option_data.m_args.push_back(path);
+    } else {
+      error.SetErrorStringWithFormat(
+          "file specified in --file (-f) option doesn't exist: '%s'", optarg);
+      return error;
+    }
+  }
+
+  if (auto *arg = args.getLastArg(OPT_arch)) {
+    auto optarg = arg->getValue();
+    if (!m_debugger.SetDefaultArchitecture(optarg)) {
+      error.SetErrorStringWithFormat(
+          "invalid architecture in the -a or --arch option: '%s'", optarg);
+      return error;
+    }
+  }
+
+  if (auto *arg = args.getLastArg(OPT_script_language)) {
+    auto optarg = arg->getValue();
+    m_option_data.m_script_lang = m_debugger.GetScriptingLanguage(optarg);
+  }
+
+  if (args.hasArg(OPT_no_use_colors)) {
+    m_option_data.m_debug_mode = true;
+  }
+
+  if (auto *arg = args.getLastArg(OPT_reproducer)) {
+    auto optarg = arg->getValue();
+    SBFileSpec file(optarg);
+    if (file.Exists()) {
+      m_debugger.SetReproducerPath(optarg);
+    } else {
+      error.SetErrorStringWithFormat("file specified in --reproducer "
+                                     "(-z) option doesn't exist: '%s'",
+                                     optarg);
+      return error;
+    }
+  }
+
+  if (args.hasArg(OPT_no_use_colors)) {
+    m_debugger.SetUseColor(false);
+  }
+
+  if (args.hasArg(OPT_source_quietly)) {
+    m_option_data.m_source_quietly = true;
+  }
+
+  if (auto *arg = args.getLastArg(OPT_attach_name)) {
+    auto optarg = arg->getValue();
+    m_option_data.m_process_name = optarg;
+  }
+
+  if (args.hasArg(OPT_wait_for)) {
+    m_option_data.m_wait_for = true;
+  }
+
+  if (auto *arg = args.getLastArg(OPT_attach_pid)) {
+    auto optarg = arg->getValue();
+    char *remainder;
+    m_option_data.m_process_pid = strtol(optarg, &remainder, 0);
+    if (remainder == optarg || *remainder != '\0') {
+      error.SetErrorStringWithFormat(
+          "Could not convert process PID: \"%s\" into a pid.", optarg);
+      return error;
+    }
+  }
+
+  if (auto *arg = args.getLastArg(OPT_repl_language)) {
+    auto optarg = arg->getValue();
+    m_option_data.m_repl_lang =
+        SBLanguageRuntime::GetLanguageTypeFromString(optarg);
+    if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
+      error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
+                                     optarg);
+      return error;
+    }
+  }
+
+  if (auto *arg = args.getLastArg(OPT_repl)) {
+    auto optarg = arg->getValue();
+    m_option_data.m_repl = true;
+    if (optarg && optarg[0])
+      m_option_data.m_repl_options = optarg;
+    else
+      m_option_data.m_repl_options.clear();
+  }
+
+  // We need to process the options below together as their relative order
+  // matters.
+  for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,
+                                 OPT_source, OPT_source_before_file,
+                                 OPT_one_line, OPT_one_line_before_file)) {
+    if (arg->getOption().matches(OPT_source_on_crash)) {
+      auto optarg = arg->getValue();
+      m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash, true,
+                                      error);
+      if (error.Fail())
+        return error;
+    }
+
+    if (arg->getOption().matches(OPT_one_line_on_crash)) {
+      auto optarg = arg->getValue();
+      m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash,
+                                      false, error);
+      if (error.Fail())
+        return error;
+    }
+
+    if (arg->getOption().matches(OPT_source)) {
+      auto optarg = arg->getValue();
+      m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, true,
+                                      error);
+      if (error.Fail())
+        return error;
+    }
+
+    if (arg->getOption().matches(OPT_source_before_file)) {
+      auto optarg = arg->getValue();
+      m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile, true,
+                                      error);
+      if (error.Fail())
+        return error;
+    }
+
+    if (arg->getOption().matches(OPT_one_line)) {
+      auto optarg = arg->getValue();
+      m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, false,
+                                      error);
+      if (error.Fail())
+        return error;
+    }
+
+    if (arg->getOption().matches(OPT_one_line_before_file)) {
+      auto optarg = arg->getValue();
+      m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile,
+                                      false, error);
+      if (error.Fail())
         return error;
+    }
+  }
+
+  if (m_option_data.m_process_name.empty() &&
+      m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
+
+    // If the option data args array is empty that means the file was not
+    // specified with -f and we need to get it from the input args.
+    if (m_option_data.m_args.empty()) {
+      if (auto *arg = args.getLastArgNoClaim(OPT_INPUT)) {
+        m_option_data.m_args.push_back(arg->getAsString((args)));
       }
     }
+
+    // Any argument following -- is an argument for the inferior.
+    if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {
+      for (auto value : arg->getValues())
+        m_option_data.m_args.push_back(value);
+    }
+  } else {
+    if (args.getLastArgNoClaim()) {
+      ::fprintf(out_fh,
+                "Warning: program arguments are ignored when attaching.\n");
+    }
   }
 
-  if (error.Fail() || m_option_data.m_print_help) {
-    ShowUsage(out_fh, m_option_data);
-    exiting = true;
-  } else if (m_option_data.m_print_version) {
+  if (m_option_data.m_print_version) {
     ::fprintf(out_fh, "%s\n", m_debugger.GetVersionString());
     exiting = true;
-  } else if (m_option_data.m_print_python_path) {
+    return error;
+  }
+
+  if (m_option_data.m_print_python_path) {
     SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
     if (python_file_spec.IsValid()) {
       char python_path[PATH_MAX];
@@ -836,33 +520,7 @@
     } else
       ::fprintf(out_fh, "<COULD NOT FIND PATH>\n");
     exiting = true;
-  } else if (m_option_data.m_process_name.empty() &&
-             m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
-    // Any arguments that are left over after option parsing are for
-    // the program. If a file was specified with -f then the filename
-    // is already in the m_option_data.m_args array, and any remaining args
-    // are arguments for the inferior program. If no file was specified with
-    // -f, then what is left is the program name followed by any arguments.
-
-    // Skip any options we consumed with getopt_long_only
-    argc -= optind;
-    argv += optind;
-
-    if (argc > 0) {
-      for (int arg_idx = 0; arg_idx < argc; ++arg_idx) {
-        const char *arg = argv[arg_idx];
-        if (arg)
-          m_option_data.m_args.push_back(arg);
-      }
-    }
-
-  } else {
-    // Skip any options we consumed with getopt_long_only
-    argc -= optind;
-
-    if (argc > 0)
-      ::fprintf(out_fh,
-                "Warning: program arguments are ignored when attaching.\n");
+    return error;
   }
 
   return error;
@@ -884,8 +542,9 @@
   if (err == 0) {
     ssize_t nrwr = write(fds[WRITE], commands_data, commands_size);
     if (nrwr < 0) {
-      fprintf(stderr, "error: write(%i, %p, %" PRIu64 ") failed (errno = %i) "
-                      "when trying to open LLDB commands pipe\n",
+      fprintf(stderr,
+              "error: write(%i, %p, %" PRIu64 ") failed (errno = %i) "
+              "when trying to open LLDB commands pipe\n",
               fds[WRITE], static_cast<const void *>(commands_data),
               static_cast<uint64_t>(commands_size), errno);
     } else if (static_cast<size_t>(nrwr) == commands_size) {
@@ -903,13 +562,13 @@
       // the debugger as an input handle
       commands_file = fdopen(fds[READ], "r");
       if (commands_file) {
-        fds[READ] =
-            -1; // The FILE * 'commands_file' now owns the read descriptor
-                // Hand ownership if the FILE * over to the debugger for
-                // "commands_file".
+        fds[READ] = -1; // The FILE * 'commands_file' now owns the read
+                        // descriptor Hand ownership if the FILE * over to the
+                        // debugger for "commands_file".
       } else {
-        fprintf(stderr, "error: fdopen(%i, \"r\") failed (errno = %i) when "
-                        "trying to open LLDB commands pipe\n",
+        fprintf(stderr,
+                "error: fdopen(%i, \"r\") failed (errno = %i) when "
+                "trying to open LLDB commands pipe\n",
                 fds[READ], errno);
       }
     }
@@ -1206,6 +865,33 @@
   signal(signo, sigcont_handler);
 }
 
+static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
+  std::string usage_str;
+  llvm::StringRef indent = "  ";
+  llvm::raw_string_ostream usage(usage_str);
+  usage << '\n';
+  usage << indent << tool_name << " -h" << '\n';
+  usage << indent << tool_name
+        << " -v [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]\n";
+  usage << indent << tool_name
+        << " -a <arch> -f <filename> [-c <filename>] [-s <filename>] [-o "
+           "<none>] [-S <filename>] [-O <none>] [-k <none>] [-K <filename>] "
+           "[-Q] [-b] [-e] [-x] [-X] [-l <script-language>] [-d] [-z "
+           "<filename>] [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]\n";
+  usage << indent << tool_name
+        << " -n <process-name> -w [-s <filename>] [-o <none>] [-S "
+           "<filename>] [-O <none>] [-k <none>] [-K <filename>] [-Q] [-b] "
+           "[-e] [-x] [-X] [-l <script-language>] [-d] [-z <filename>]\n";
+  usage << indent << tool_name
+        << " -p <pid> [-s <filename>] [-o <none>] [-S <filename>] [-O "
+           "<none>] [-k <none>] [-K <filename>] [-Q] [-b] [-e] [-x] [-X] [-l "
+           "<script-language>] [-d] [-z <filename>]\n";
+  usage << indent << tool_name << " -P\n";
+  usage << indent << tool_name << " -r [<none>] -R <none>\n";
+  usage.flush();
+  table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
+}
+
 int
 #ifdef _MSC_VER
 wmain(int argc, wchar_t const *wargv[])
@@ -1224,12 +910,23 @@
   const char **argv = argvPointers.data();
 #endif
 
-  llvm::StringRef ToolName = argv[0];
+  // Print stack trace on crash.
+  llvm::StringRef ToolName = llvm::sys::path::filename(argv[0]);
   llvm::sys::PrintStackTraceOnErrorSignal(ToolName);
   llvm::PrettyStackTraceProgram X(argc, argv);
 
-  SBDebugger::Initialize();
+  // Parse arguments.
+  LLDBOptTable T;
+  unsigned MAI, MAC;
+  ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1);
+  opt::InputArgList input_args = T.ParseArgs(arg_arr, MAI, MAC);
 
+  if (input_args.hasArg(OPT_help)) {
+    printHelp(T, ToolName);
+    return 0;
+  }
+
+  SBDebugger::Initialize();
   SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
 
   signal(SIGINT, sigint_handler);
@@ -1247,7 +944,7 @@
     Driver driver;
 
     bool exiting = false;
-    SBError error(driver.ParseArgs(argc, argv, stdout, exiting));
+    SBError error(driver.ProcessArgs(input_args, stdout, exiting));
     if (error.Fail()) {
       exit_code = 1;
       const char *error_cstr = error.GetCString();
Index: tools/driver/CMakeLists.txt
===================================================================
--- tools/driver/CMakeLists.txt
+++ tools/driver/CMakeLists.txt
@@ -1,3 +1,7 @@
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(LLDBOptionsTableGen)
+
 if ((CMAKE_SYSTEM_NAME MATCHES "Windows") OR
     (CMAKE_SYSTEM_NAME MATCHES "NetBSD" ))
   # These targets do not have getopt support, so they rely on the one provided by
@@ -17,6 +21,7 @@
     ${host_lib}
 
   LINK_COMPONENTS
+    Option
     Support
   )
 
@@ -24,4 +29,8 @@
   add_definitions( -DIMPORT_LIBLLDB )
 endif()
 
-add_dependencies(lldb ${LLDB_SUITE_TARGET})
+add_dependencies(lldb
+  ${LLDB_SUITE_TARGET}
+  LLDBOptionsTableGen
+  ${tablegen_deps}
+)
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to