Wrapped up the work I am going to do for now for the "add-dsym" or "target symfile add" command.

We can now do:

Specify a path to a debug symbols file:
(lldb) add-dsym <path-to-dsym>

Go and download the dSYM file for the "libunc.dylib" module in your target:
(lldb) add-dsym --shlib libunc.dylib

Go and download the dSYM given a UUID:
(lldb) add-dsym --uuid <UUID>

Go and download the dSYM file for the current frame:
(lldb) add-dsym --frame



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@164806 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Commands/CommandObjectTarget.cpp b/source/Commands/CommandObjectTarget.cpp
index c1e6486..226c00f 100644
--- a/source/Commands/CommandObjectTarget.cpp
+++ b/source/Commands/CommandObjectTarget.cpp
@@ -451,7 +451,7 @@
                              NULL,
                              0),
         m_option_group (interpreter),
-        m_cleanup_option (LLDB_OPT_SET_1, false, "clean", 'c', 0, eArgTypeNone, "Perform extra cleanup to minimize memory consumption after deleting the target.", false)
+        m_cleanup_option (LLDB_OPT_SET_1, false, "clean", 'c', "Perform extra cleanup to minimize memory consumption after deleting the target.", false, false)
     {
         m_option_group.Append (&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
         m_option_group.Finalize();
@@ -3984,9 +3984,17 @@
     CommandObjectTargetSymbolsAdd (CommandInterpreter &interpreter) :
         CommandObjectParsed (interpreter,
                              "target symbols add",
-                             "Add a debug symbol file to one of the target's current modules.",
-                             "target symbols add [<symfile>]")
+                             "Add a debug symbol file to one of the target's current modules by specifying a path to a debug symbols file, or using the options to specify a module to download symbols for.",
+                             "target symbols add [<symfile>]"),
+        m_option_group (interpreter),
+        m_file_option (LLDB_OPT_SET_1, false, "shlib", 's', CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Fullpath or basename for module to find debug symbols for."),
+        m_current_frame_option (LLDB_OPT_SET_2, false, "frame", 'F', "Locate the debug symbols the currently selected frame.", false, true)
+
     {
+        m_option_group.Append (&m_uuid_option_group, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+        m_option_group.Append (&m_file_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+        m_option_group.Append (&m_current_frame_option, LLDB_OPT_SET_2, LLDB_OPT_SET_2);
+        m_option_group.Finalize();
     }
     
     virtual
@@ -4018,152 +4026,260 @@
         return matches.GetSize();
     }
     
+    virtual Options *
+    GetOptions ()
+    {
+        return &m_option_group;
+    }
+    
+
 protected:
+    
+    bool
+    AddModuleSymbols (Target *target,
+                      const FileSpec &symfile_spec,
+                      bool &flush,
+                      CommandReturnObject &result)
+    {
+        ModuleSP symfile_module_sp (new Module (symfile_spec, target->GetArchitecture()));
+        const UUID &symfile_uuid = symfile_module_sp->GetUUID();
+        StreamString ss_symfile_uuid;
+        symfile_uuid.Dump(&ss_symfile_uuid);
+        
+        if (symfile_module_sp)
+        {
+            char symfile_path[PATH_MAX];
+            symfile_spec.GetPath (symfile_path, sizeof(symfile_path));
+            // We now have a module that represents a symbol file
+            // that can be used for a module that might exist in the
+            // current target, so we need to find that module in the
+            // target
+            
+            ModuleSP old_module_sp (target->GetImages().FindModule (symfile_uuid));
+            if (old_module_sp)
+            {
+                // The module has not yet created its symbol vendor, we can just
+                // give the existing target module the symfile path to use for
+                // when it decides to create it!
+                old_module_sp->SetSymbolFileFileSpec (symfile_module_sp->GetFileSpec());
+                
+                // Provide feedback that the symfile has been successfully added.
+                const FileSpec &module_fs = old_module_sp->GetFileSpec();
+                result.AppendMessageWithFormat("symbol file '%s' with UUID %s has been successfully added to the '%s/%s' module\n",
+                                               symfile_path, ss_symfile_uuid.GetData(),
+                                               module_fs.GetDirectory().AsCString(), module_fs.GetFilename().AsCString());
+                
+                // Let clients know something changed in the module
+                // if it is currently loaded
+                ModuleList module_list;
+                module_list.Append (old_module_sp);
+                target->ModulesDidLoad (module_list);
+                flush = true;
+            }
+            else
+            {
+                result.AppendErrorWithFormat ("symbol file '%s' with UUID %s does not match any existing module%s\n",
+                                              symfile_path, ss_symfile_uuid.GetData(),
+                                              (symfile_spec.GetFileType() != FileSpec::eFileTypeRegular)
+                                              ? "\n       please specify the full path to the symbol file"
+                                              : "");
+                return false;
+            }
+        }
+        else
+        {
+            result.AppendError ("one or more executable image paths must be specified");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+        result.SetStatus (eReturnStatusSuccessFinishResult);
+        return true;
+    }
+
     virtual bool
     DoExecute (Args& args,
              CommandReturnObject &result)
     {
         ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
         Target *target = exe_ctx.GetTargetPtr();
+        result.SetStatus (eReturnStatusFailed);
         if (target == NULL)
         {
             result.AppendError ("invalid target, create a debug target using the 'target create' command");
-            result.SetStatus (eReturnStatusFailed);
         }
         else
         {
             bool flush = false;
+            ModuleSpec sym_spec;
+            const bool uuid_option_set = m_uuid_option_group.GetOptionValue().OptionWasSet();
+            const bool file_option_set = m_file_option.GetOptionValue().OptionWasSet();
+            const bool frame_option_set = m_current_frame_option.GetOptionValue().OptionWasSet();
+
             const size_t argc = args.GetArgumentCount();
             if (argc == 0)
             {
-                result.AppendError ("one or more symbol file paths must be specified");
-                result.SetStatus (eReturnStatusFailed);
-            }
-            else
-            {
-                PlatformSP platform_sp (target->GetPlatform());
-
-                for (size_t i=0; i<argc; ++i)
+                if (uuid_option_set || file_option_set || frame_option_set)
                 {
-                    const char *symfile_path = args.GetArgumentAtIndex(i);
-                    if (symfile_path)
+                    bool success = false;
+                    bool error_set = false;
+                    if (frame_option_set)
                     {
-                        ModuleSpec sym_spec;
-                        FileSpec symfile_spec;
-                        sym_spec.GetSymbolFileSpec().SetFile(symfile_path, true);
-                        if (platform_sp)
-                            platform_sp->ResolveSymbolFile(*target, sym_spec, symfile_spec);
-                        else
-                            symfile_spec.SetFile(symfile_path, true);
-                        
-                        ArchSpec arch;
-                        bool symfile_exists = symfile_spec.Exists();
-                        // The code below was testing the new "Symbols::DownloadObjectAndSymbolFile"
-                        // functionality. Now that it works on MacOSX, it will be enabled soon with
-                        // option values (like "--uuid <UUID>" or "--file <module>", or "--frame"
-                        // for the current stack frame's module). So it is commented out for now.
-//                        if (!symfile_exists)
-//                        {
-//                            if (sym_spec.GetUUID().SetfromCString(symfile_path))
-//                            {
-//                                // A UUID was specified, look it up via UUID
-//                                if (Symbols::DownloadObjectAndSymbolFile (sym_spec))
-//                                {
-////                                    printf ("UUID: %s\n", symfile_path);
-////                                    printf ("objfile_spec: %s/%s\n",
-////                                            sym_spec.GetFileSpec().GetDirectory().GetCString(),
-////                                            sym_spec.GetFileSpec().GetFilename().GetCString());
-////                                    printf ("symfile_spec: %s/%s\n",
-////                                            sym_spec.GetSymbolFileSpec().GetDirectory().GetCString(),
-////                                            sym_spec.GetSymbolFileSpec().GetFilename().GetCString());
-//                                    symfile_spec = sym_spec.GetSymbolFileSpec();
-//                                    symfile_exists = symfile_spec.Exists();
-//                                }
-//                            }
-//                        }
-
-                        if (symfile_exists)
+                        Process *process = exe_ctx.GetProcessPtr();
+                        if (process)
                         {
-                            ModuleSP symfile_module_sp (new Module (symfile_spec, target->GetArchitecture()));
-                            const UUID &symfile_uuid = symfile_module_sp->GetUUID();
-                            StreamString ss_symfile_uuid;
-                            symfile_uuid.Dump(&ss_symfile_uuid);
-
-                            if (symfile_module_sp)
+                            const StateType process_state = process->GetState();
+                            if (StateIsStoppedState (process_state, true))
                             {
-                                // We now have a module that represents a symbol file
-                                // that can be used for a module that might exist in the
-                                // current target, so we need to find that module in the
-                                // target
-                                
-                                ModuleSP old_module_sp (target->GetImages().FindModule (symfile_uuid));
-                                if (old_module_sp)
+                                StackFrame *frame = exe_ctx.GetFramePtr();
+                                if (frame)
                                 {
-                                    // The module has not yet created its symbol vendor, we can just
-                                    // give the existing target module the symfile path to use for
-                                    // when it decides to create it!
-                                    old_module_sp->SetSymbolFileFileSpec (symfile_module_sp->GetFileSpec());
-
-                                    // Provide feedback that the symfile has been successfully added.
-                                    const FileSpec &module_fs = old_module_sp->GetFileSpec();
-                                    result.AppendMessageWithFormat("symbol file '%s' with UUID %s has been successfully added to the '%s/%s' module\n",
-                                                                   symfile_path, ss_symfile_uuid.GetData(),
-                                                                   module_fs.GetDirectory().AsCString(), module_fs.GetFilename().AsCString());
-
-                                    // Let clients know something changed in the module
-                                    // if it is currently loaded
-                                    ModuleList module_list;
-                                    module_list.Append (old_module_sp);
-                                    target->ModulesDidLoad (module_list);
-                                    flush = true;
+                                    ModuleSP frame_module_sp (frame->GetSymbolContext(eSymbolContextModule).module_sp);
+                                    if (frame_module_sp)
+                                    {
+                                        if (frame_module_sp->GetPlatformFileSpec().Exists())
+                                        {
+                                            sym_spec.GetArchitecture() = frame_module_sp->GetArchitecture();
+                                            sym_spec.GetFileSpec() = frame_module_sp->GetPlatformFileSpec();
+                                        }
+                                        sym_spec.GetUUID() = frame_module_sp->GetUUID();
+                                        success = sym_spec.GetUUID().IsValid() || sym_spec.GetFileSpec();
+                                    }
+                                    else
+                                    {
+                                        result.AppendError ("frame has no module");
+                                        error_set = true;
+                                    }
                                 }
                                 else
                                 {
-                                    result.AppendErrorWithFormat ("symbol file '%s' with UUID %s does not match any existing module%s\n",
-                                                                  symfile_path, ss_symfile_uuid.GetData(),
-                                                                  (symfile_spec.GetFileType() != FileSpec::eFileTypeRegular)
-                                                                      ? "\n       please specify the full path to the symbol file"
-                                                                      : "");
-                                    break;
+                                    result.AppendError ("invalid current frame");
+                                    error_set = true;
                                 }
                             }
                             else
                             {
-                                result.AppendError ("one or more executable image paths must be specified");
-                                result.SetStatus (eReturnStatusFailed);
-                                break;
+                                result.AppendErrorWithFormat ("process is not stopped: %s", StateAsCString(process_state));
+                                error_set = true;
                             }
-                            result.SetStatus (eReturnStatusSuccessFinishResult);
                         }
                         else
                         {
-//                            sym_spec.GetSymbolFileSpec().Clear();
-//                            if (sym_spec.GetUUID().SetfromCString(symfile_path))
-//                            {
-//                                if (Symbols::DownloadObjectAndSymbolFile (sym_spec))
-//                                {
-//                                    printf ("UUID: %s\n", symfile_path);
-//                                    printf ("objfile_spec: %s/%s\n",
-//                                            sym_spec.GetFileSpec().GetDirectory().GetCString(),
-//                                            sym_spec.GetFileSpec().GetFilename().GetCString());
-//                                    printf ("symfile_spec: %s/%s\n",
-//                                            sym_spec.GetSymbolFileSpec().GetDirectory().GetCString(),
-//                                            sym_spec.GetSymbolFileSpec().GetFilename().GetCString());
-//                                }
-//                            }
-                            
-                            char resolved_symfile_path[PATH_MAX];
-                            result.SetStatus (eReturnStatusFailed);
-                            if (symfile_spec.GetPath (resolved_symfile_path, sizeof(resolved_symfile_path)))
+                            result.AppendError ("a process must exist in order to use the --frame option");
+                            error_set = true;
+                        }
+                    }
+                    else
+                    {
+                        if (uuid_option_set)
+                        {
+                            sym_spec.GetUUID() = m_uuid_option_group.GetOptionValue().GetCurrentValue();
+                            success |= sym_spec.GetUUID().IsValid();
+                        }
+                        else if (file_option_set)
+                        {
+                            sym_spec.GetFileSpec() = m_file_option.GetOptionValue().GetCurrentValue();
+                            ModuleSP module_sp (target->GetImages().FindFirstModule(sym_spec));
+                            if (module_sp)
                             {
-                                if (strcmp (resolved_symfile_path, symfile_path) != 0)
-                                {
-                                    result.AppendErrorWithFormat ("invalid module path '%s' with resolved path '%s'\n", symfile_path, resolved_symfile_path);
-                                    break;
-                                }
+                                sym_spec.GetFileSpec() = module_sp->GetFileSpec();
+                                sym_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec();
+                                sym_spec.GetUUID() = module_sp->GetUUID();
+                                sym_spec.GetArchitecture() = module_sp->GetArchitecture();
                             }
-                            result.AppendErrorWithFormat ("invalid module path '%s'\n", symfile_path);
-                            break;
+                            else
+                            {
+                                sym_spec.GetArchitecture() = target->GetArchitecture();
+                            }
+                            success |= sym_spec.GetFileSpec().Exists();
+                        }
+                    }
+
+                    if (success)
+                    {
+                        if (Symbols::DownloadObjectAndSymbolFile (sym_spec))
+                        {
+                            if (sym_spec.GetSymbolFileSpec())
+                                success = AddModuleSymbols (target, sym_spec.GetSymbolFileSpec(), flush, result);
+                        }
+                    }
+
+                    if (!success && !error_set)
+                    {
+                        StreamString error_strm;
+                        if (uuid_option_set)
+                        {
+                            error_strm.PutCString("unable to find debug symbols for UUID ");
+                            sym_spec.GetUUID().Dump (&error_strm);
+                        }
+                        else if (file_option_set)
+                        {
+                            error_strm.PutCString("unable to find debug symbols for the executable file ");
+                            error_strm << sym_spec.GetFileSpec();
+                        }
+                        else if (frame_option_set)
+                        {
+                            error_strm.PutCString("unable to find debug symbols for the current frame");                            
+                        }
+                        result.AppendError (error_strm.GetData());
+                    }
+                }
+                else
+                {
+                    result.AppendError ("one or more symbol file paths must be specified, or options must be specified");
+                }
+            }
+            else
+            {
+                if (uuid_option_set)
+                {
+                    result.AppendError ("specify either one or more paths to symbol files or use the --uuid option without arguments");
+                }
+                else if (file_option_set)
+                {
+                    result.AppendError ("specify either one or more paths to symbol files or use the --file option without arguments");
+                }
+                else if (frame_option_set)
+                {
+                    result.AppendError ("specify either one or more paths to symbol files or use the --frame option without arguments");
+                }
+                else
+                {
+                    PlatformSP platform_sp (target->GetPlatform());
+
+                    for (size_t i=0; i<argc; ++i)
+                    {
+                        const char *symfile_path = args.GetArgumentAtIndex(i);
+                        if (symfile_path)
+                        {
+                            FileSpec symfile_spec;
+                            sym_spec.GetSymbolFileSpec().SetFile(symfile_path, true);
+                            if (platform_sp)
+                                platform_sp->ResolveSymbolFile(*target, sym_spec, symfile_spec);
+                            else
+                                symfile_spec.SetFile(symfile_path, true);
+                            
+                            ArchSpec arch;
+                            bool symfile_exists = symfile_spec.Exists();
+
+                            if (symfile_exists)
+                            {
+                                if (!AddModuleSymbols (target, symfile_spec, flush, result))
+                                    break;
+                            }
+                            else
+                            {
+                                char resolved_symfile_path[PATH_MAX];
+                                if (symfile_spec.GetPath (resolved_symfile_path, sizeof(resolved_symfile_path)))
+                                {
+                                    if (strcmp (resolved_symfile_path, symfile_path) != 0)
+                                    {
+                                        result.AppendErrorWithFormat ("invalid module path '%s' with resolved path '%s'\n", symfile_path, resolved_symfile_path);
+                                        break;
+                                    }
+                                }
+                                result.AppendErrorWithFormat ("invalid module path '%s'\n", symfile_path);
+                                break;
+                            }
                         }
                     }
                 }
@@ -4179,6 +4295,12 @@
         return result.Succeeded();
     }
     
+    OptionGroupOptions m_option_group;
+    OptionGroupUUID m_uuid_option_group;
+    OptionGroupFile m_file_option;
+    OptionGroupBoolean m_current_frame_option;
+
+    
 };