Adding "-n", "-p" and "-w" flags to the lldb command-line tool to
allow attaching from the command line.


git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@139665 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/driver/Driver.cpp b/tools/driver/Driver.cpp
index 7929390..1e0630e 100644
--- a/tools/driver/Driver.cpp
+++ b/tools/driver/Driver.cpp
@@ -64,21 +64,27 @@
                                              // pass it.
 } OptionDefinition;
 
-#define LLDB_2_TO_4 LLDB_OPT_SET_2|LLDB_OPT_SET_3|LLDB_OPT_SET_4
+#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 OptionDefinition g_options[] =
 {
-    { LLDB_OPT_SET_1,                   true , "help"           , 'h', no_argument      , NULL,  eArgTypeNone, "Prints out the usage information for the LLDB debugger." },
-    { LLDB_OPT_SET_2,                   true , "version"        , 'v', no_argument      , NULL,  eArgTypeNone, "Prints out the current version number of the LLDB debugger." },
-    { LLDB_OPT_SET_3,                   true , "arch"           , 'a', required_argument, NULL,  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 | LLDB_OPT_SET_4,  false, "script-language", 'l', required_argument, NULL,  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_OPT_SET_3 | LLDB_OPT_SET_4,  false, "debug"          , 'd', no_argument      , NULL,  eArgTypeNone,"Tells the debugger to print out extra information for debugging itself." },
-    { LLDB_OPT_SET_3 | LLDB_OPT_SET_4,  false, "source"         , 's', required_argument, NULL,  eArgTypeFilename, "Tells the debugger to read in and execute the file <file>, which should contain lldb commands." },
-    { LLDB_OPT_SET_3,                   true , "file"           , 'f', required_argument, NULL,  eArgTypeFilename, "Tells the debugger to use the file <filename> as the program to be debugged." },
-    { LLDB_2_TO_4,                      false, "editor"         , 'e', no_argument      , NULL,  eArgTypeNone, "Tells the debugger to open source files using the host's \"external editor\" mechanism." },
-    { LLDB_2_TO_4,                      false, "no-lldbinit"    , 'n', no_argument      , NULL,  eArgTypeNone, "Do not automatically parse any '.lldbinit' files." },
-    { 0,                                false, NULL             , 0  , 0                , NULL,  eArgTypeNone, NULL }
+    { LLDB_OPT_SET_1,    true , "help"           , 'h', no_argument      , NULL,  eArgTypeNone,         "Prints out the usage information for the LLDB debugger." },
+    { LLDB_OPT_SET_2,    true , "version"        , 'v', no_argument      , NULL,  eArgTypeNone,         "Prints out the current version number of the LLDB debugger." },
+    { LLDB_OPT_SET_3,    true , "arch"           , 'a', required_argument, NULL,  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, NULL,  eArgTypeFilename,     "Tells the debugger to use the file <filename> as the program to be debugged." },
+    { LLDB_OPT_SET_4,    true , "attach-name"    , 'n', required_argument, NULL,  eArgTypeProcessName,  "Tells the debugger to attach to a process with the given name." },
+    { LLDB_OPT_SET_4,    true , "wait-for"       , 'w', no_argument      , NULL,  eArgTypeNone,         "Tells the debugger to wait for a process with the given pid or name to launch before attaching." },
+    { LLDB_OPT_SET_5,    true , "attach-pid"     , 'p', required_argument, NULL,  eArgTypePid,          "Tells the debugger to attach to a process with the given pid." },
+    { LLDB_3_TO_5,       false, "script-language", 'l', required_argument, NULL,  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      , NULL,  eArgTypeNone,         "Tells the debugger to print out extra information for debugging itself." },
+    { LLDB_3_TO_5,       false, "source"         , 's', required_argument, NULL,  eArgTypeFilename,     "Tells the debugger to read in and execute the file <file>, which should contain lldb commands." },
+    { LLDB_3_TO_5,       false, "editor"         , 'e', no_argument      , NULL,  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      , NULL,  eArgTypeNone,         "Do not automatically parse any '.lldbinit' files." },
+    { 0,                 false, NULL             , 0  , 0                , NULL,  eArgTypeNone,         NULL }
 };
 
+static const uint32_t last_option_set_with_args = 2;
 
 Driver::Driver () :
     SBBroadcaster ("Driver"),
@@ -259,7 +265,7 @@
                 }
             }
         }
-        if (!is_help_line)
+        if (!is_help_line && (opt_set <= last_option_set_with_args))
             fprintf (out, " [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]");
     }
 
@@ -358,6 +364,9 @@
     m_print_version (false),
     m_print_help (false),
     m_use_external_editor(false),
+    m_wait_for(false),
+    m_process_name(),
+    m_process_pid(LLDB_INVALID_PROCESS_ID),
     m_seen_options()
 {
 }
@@ -376,6 +385,9 @@
     m_print_help = false;
     m_print_version = false;
     m_use_external_editor = false;
+    m_wait_for = false;
+    m_process_name.erase();
+    m_process_pid = LLDB_INVALID_PROCESS_ID;
 }
 
 void
@@ -561,7 +573,7 @@
                         m_option_data.m_use_external_editor = true;
                         break;
 
-                    case 'n':
+                    case 'x':
                         m_debugger.SkipLLDBInitFiles (true);
                         m_debugger.SkipAppInitFiles (true);
                         break;
@@ -597,6 +609,23 @@
                         m_option_data.m_debug_mode = true;
                         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 's':
                         {
                             SBFileSpec file(optarg);
@@ -645,7 +674,7 @@
     {
         // Handle crash log stuff here.
     }
-    else
+    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
@@ -668,6 +697,15 @@
         }
         
     }
+    else
+    {
+        // Skip any options we consumed with getopt_long
+        argc -= optind;
+        argv += optind;
+
+        if (argc > 0)
+            ::fprintf (out_fh, "Warning: program arguments are ignored when attaching.\n");
+    }
 
     return error;
 }
@@ -1202,7 +1240,10 @@
                     char arg_cstr[1024];
                     for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
                     {
-                        ::snprintf (arg_cstr, sizeof(arg_cstr), "settings append target.process.run-args \"%s\"", m_option_data.m_args[arg_idx].c_str());
+                        ::snprintf (arg_cstr, 
+                                    sizeof(arg_cstr), 
+                                    "settings append target.process.run-args \"%s\"", 
+                                    m_option_data.m_args[arg_idx].c_str());
                         m_debugger.HandleCommand (arg_cstr);
                     }
                 }
@@ -1225,7 +1266,42 @@
                                                          *m_io_channel_ap,
                                                          IOChannel::eBroadcastBitThreadDidStart, 
                                                          event);
-            
+            // If we were asked to attach, then do that here:
+            // I'm going to use the command string rather than directly
+            // calling the API's because then I don't have to recode the
+            // event handling here.
+            if (!m_option_data.m_process_name.empty()
+                || m_option_data.m_process_pid != LLDB_INVALID_PROCESS_ID)
+            {
+                std::string command_str("process attach ");
+                if (m_option_data.m_process_pid != LLDB_INVALID_PROCESS_ID)
+                {
+                    command_str.append("-p ");
+                    char pid_buffer[32];
+                    ::snprintf (pid_buffer, sizeof(pid_buffer), "%d", m_option_data.m_process_pid);
+                    command_str.append(pid_buffer);
+                }
+                else 
+                {
+                    command_str.append("-n \"");
+                    command_str.append(m_option_data.m_process_name);
+                    command_str.push_back('\"');
+                    if (m_option_data.m_wait_for)
+                        command_str.append(" -w");
+                }
+                
+                if (m_debugger.GetOutputFileHandle())
+                    ::fprintf (m_debugger.GetOutputFileHandle(), 
+                               "Attaching to process with:\n    %s\n", 
+                               command_str.c_str());
+                                               
+                // Force the attach to be synchronous:
+                bool orig_async = m_debugger.GetAsync();
+                m_debugger.SetAsync(true);
+                m_debugger.HandleCommand(command_str.c_str());
+                m_debugger.SetAsync(orig_async);                
+            }
+                        
             ReadyForCommand ();
 
             bool done = false;