diff options
Diffstat (limited to 'lldb/source/Commands/CommandObjectTarget.cpp')
| -rw-r--r-- | lldb/source/Commands/CommandObjectTarget.cpp | 4902 | 
1 files changed, 4902 insertions, 0 deletions
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp new file mode 100644 index 0000000000000..abf7895a73849 --- /dev/null +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -0,0 +1,4902 @@ +//===-- CommandObjectTarget.cpp ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectTarget.h" + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/IOHandler.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/ValueObjectVariable.h" +#include "lldb/DataFormatters/ValueObjectPrinter.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Host/StringConvert.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionGroupArchitecture.h" +#include "lldb/Interpreter/OptionGroupBoolean.h" +#include "lldb/Interpreter/OptionGroupFile.h" +#include "lldb/Interpreter/OptionGroupFormat.h" +#include "lldb/Interpreter/OptionGroupPlatform.h" +#include "lldb/Interpreter/OptionGroupString.h" +#include "lldb/Interpreter/OptionGroupUInt64.h" +#include "lldb/Interpreter/OptionGroupUUID.h" +#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" +#include "lldb/Interpreter/OptionGroupVariable.h" +#include "lldb/Interpreter/Options.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/FuncUnwinders.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/LocateSymbolFile.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadSpec.h" +#include "lldb/Utility/Args.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Timer.h" + +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatAdapters.h" + +#include <cerrno> + +using namespace lldb; +using namespace lldb_private; + +static void DumpTargetInfo(uint32_t target_idx, Target *target, +                           const char *prefix_cstr, +                           bool show_stopped_process_status, Stream &strm) { +  const ArchSpec &target_arch = target->GetArchitecture(); + +  Module *exe_module = target->GetExecutableModulePointer(); +  char exe_path[PATH_MAX]; +  bool exe_valid = false; +  if (exe_module) +    exe_valid = exe_module->GetFileSpec().GetPath(exe_path, sizeof(exe_path)); + +  if (!exe_valid) +    ::strcpy(exe_path, "<none>"); + +  strm.Printf("%starget #%u: %s", prefix_cstr ? prefix_cstr : "", target_idx, +              exe_path); + +  uint32_t properties = 0; +  if (target_arch.IsValid()) { +    strm.Printf("%sarch=", properties++ > 0 ? ", " : " ( "); +    target_arch.DumpTriple(strm); +    properties++; +  } +  PlatformSP platform_sp(target->GetPlatform()); +  if (platform_sp) +    strm.Printf("%splatform=%s", properties++ > 0 ? ", " : " ( ", +                platform_sp->GetName().GetCString()); + +  ProcessSP process_sp(target->GetProcessSP()); +  bool show_process_status = false; +  if (process_sp) { +    lldb::pid_t pid = process_sp->GetID(); +    StateType state = process_sp->GetState(); +    if (show_stopped_process_status) +      show_process_status = StateIsStoppedState(state, true); +    const char *state_cstr = StateAsCString(state); +    if (pid != LLDB_INVALID_PROCESS_ID) +      strm.Printf("%spid=%" PRIu64, properties++ > 0 ? ", " : " ( ", pid); +    strm.Printf("%sstate=%s", properties++ > 0 ? ", " : " ( ", state_cstr); +  } +  if (properties > 0) +    strm.PutCString(" )\n"); +  else +    strm.EOL(); +  if (show_process_status) { +    const bool only_threads_with_stop_reason = true; +    const uint32_t start_frame = 0; +    const uint32_t num_frames = 1; +    const uint32_t num_frames_with_source = 1; +    const bool     stop_format = false; +    process_sp->GetStatus(strm); +    process_sp->GetThreadStatus(strm, only_threads_with_stop_reason, +                                start_frame, num_frames, +                                num_frames_with_source, stop_format); +  } +} + +static uint32_t DumpTargetList(TargetList &target_list, +                               bool show_stopped_process_status, Stream &strm) { +  const uint32_t num_targets = target_list.GetNumTargets(); +  if (num_targets) { +    TargetSP selected_target_sp(target_list.GetSelectedTarget()); +    strm.PutCString("Current targets:\n"); +    for (uint32_t i = 0; i < num_targets; ++i) { +      TargetSP target_sp(target_list.GetTargetAtIndex(i)); +      if (target_sp) { +        bool is_selected = target_sp.get() == selected_target_sp.get(); +        DumpTargetInfo(i, target_sp.get(), is_selected ? "* " : "  ", +                       show_stopped_process_status, strm); +      } +    } +  } +  return num_targets; +} + +// Note that the negation in the argument name causes a slightly confusing +// mapping of the enum values. +static constexpr OptionEnumValueElement g_dependents_enumaration[] = { +    { +        eLoadDependentsDefault, +        "default", +        "Only load dependents when the target is an executable.", +    }, +    { +        eLoadDependentsNo, +        "true", +        "Don't load dependents, even if the target is an executable.", +    }, +    { +        eLoadDependentsYes, +        "false", +        "Load dependents, even if the target is not an executable.", +    }, +}; + +#define LLDB_OPTIONS_target_dependents +#include "CommandOptions.inc" + +class OptionGroupDependents : public OptionGroup { +public: +  OptionGroupDependents() {} + +  ~OptionGroupDependents() override {} + +  llvm::ArrayRef<OptionDefinition> GetDefinitions() override { +    return llvm::makeArrayRef(g_target_dependents_options); +  } + +  Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, +                        ExecutionContext *execution_context) override { +    Status error; + +    // For compatibility no value means don't load dependents. +    if (option_value.empty()) { +      m_load_dependent_files = eLoadDependentsNo; +      return error; +    } + +    const char short_option = +        g_target_dependents_options[option_idx].short_option; +    if (short_option == 'd') { +      LoadDependentFiles tmp_load_dependents; +      tmp_load_dependents = (LoadDependentFiles)OptionArgParser::ToOptionEnum( +          option_value, g_target_dependents_options[option_idx].enum_values, 0, +          error); +      if (error.Success()) +        m_load_dependent_files = tmp_load_dependents; +    } else { +      error.SetErrorStringWithFormat("unrecognized short option '%c'", +                                     short_option); +    } + +    return error; +  } + +  Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; + +  void OptionParsingStarting(ExecutionContext *execution_context) override { +    m_load_dependent_files = eLoadDependentsDefault; +  } + +  LoadDependentFiles m_load_dependent_files; + +private: +  DISALLOW_COPY_AND_ASSIGN(OptionGroupDependents); +}; + +#pragma mark CommandObjectTargetCreate + +// "target create" + +class CommandObjectTargetCreate : public CommandObjectParsed { +public: +  CommandObjectTargetCreate(CommandInterpreter &interpreter) +      : CommandObjectParsed( +            interpreter, "target create", +            "Create a target using the argument as the main executable.", +            nullptr), +        m_option_group(), m_arch_option(), +        m_core_file(LLDB_OPT_SET_1, false, "core", 'c', 0, eArgTypeFilename, +                    "Fullpath to a core file to use for this target."), +        m_platform_path(LLDB_OPT_SET_1, false, "platform-path", 'P', 0, +                        eArgTypePath, +                        "Path to the remote file to use for this target."), +        m_symbol_file(LLDB_OPT_SET_1, false, "symfile", 's', 0, +                      eArgTypeFilename, +                      "Fullpath to a stand alone debug " +                      "symbols file for when debug symbols " +                      "are not in the executable."), +        m_remote_file( +            LLDB_OPT_SET_1, false, "remote-file", 'r', 0, eArgTypeFilename, +            "Fullpath to the file on the remote host if debugging remotely."), +        m_add_dependents() { +    CommandArgumentEntry arg; +    CommandArgumentData file_arg; + +    // Define the first (and only) variant of this arg. +    file_arg.arg_type = eArgTypeFilename; +    file_arg.arg_repetition = eArgRepeatPlain; + +    // There is only one variant this argument could be; put it into the +    // argument entry. +    arg.push_back(file_arg); + +    // Push the data for the first argument into the m_arguments vector. +    m_arguments.push_back(arg); + +    m_option_group.Append(&m_arch_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Append(&m_core_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Append(&m_platform_path, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Append(&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Append(&m_remote_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Append(&m_add_dependents, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Finalize(); +  } + +  ~CommandObjectTargetCreate() override = default; + +  Options *GetOptions() override { return &m_option_group; } + +  void +  HandleArgumentCompletion(CompletionRequest &request, +                           OptionElementVector &opt_element_vector) override { +    CommandCompletions::InvokeCommonCompletionCallbacks( +        GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, +        request, nullptr); +  } + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    const size_t argc = command.GetArgumentCount(); +    FileSpec core_file(m_core_file.GetOptionValue().GetCurrentValue()); +    FileSpec remote_file(m_remote_file.GetOptionValue().GetCurrentValue()); + +    if (core_file) { +      if (!FileSystem::Instance().Exists(core_file)) { +        result.AppendErrorWithFormat("core file '%s' doesn't exist", +                                     core_file.GetPath().c_str()); +        result.SetStatus(eReturnStatusFailed); +        return false; +      } +      if (!FileSystem::Instance().Readable(core_file)) { +        result.AppendErrorWithFormat("core file '%s' is not readable", +                                     core_file.GetPath().c_str()); +        result.SetStatus(eReturnStatusFailed); +        return false; +      } +    } + +    if (argc == 1 || core_file || remote_file) { +      FileSpec symfile(m_symbol_file.GetOptionValue().GetCurrentValue()); +      if (symfile) { +        if (FileSystem::Instance().Exists(symfile)) { +          if (!FileSystem::Instance().Readable(symfile)) { +            result.AppendErrorWithFormat("symbol file '%s' is not readable", +                                         symfile.GetPath().c_str()); +            result.SetStatus(eReturnStatusFailed); +            return false; +          } +        } else { +          char symfile_path[PATH_MAX]; +          symfile.GetPath(symfile_path, sizeof(symfile_path)); +          result.AppendErrorWithFormat("invalid symbol file path '%s'", +                                       symfile_path); +          result.SetStatus(eReturnStatusFailed); +          return false; +        } +      } + +      const char *file_path = command.GetArgumentAtIndex(0); +      static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); +      Timer scoped_timer(func_cat, "(lldb) target create '%s'", file_path); +      FileSpec file_spec; + +      if (file_path) { +        file_spec.SetFile(file_path, FileSpec::Style::native); +        FileSystem::Instance().Resolve(file_spec); +      } + +      bool must_set_platform_path = false; + +      Debugger &debugger = GetDebugger(); + +      TargetSP target_sp; +      llvm::StringRef arch_cstr = m_arch_option.GetArchitectureName(); +      Status error(debugger.GetTargetList().CreateTarget( +          debugger, file_path, arch_cstr, +          m_add_dependents.m_load_dependent_files, nullptr, target_sp)); + +      if (target_sp) { +        // Only get the platform after we create the target because we might +        // have switched platforms depending on what the arguments were to +        // CreateTarget() we can't rely on the selected platform. + +        PlatformSP platform_sp = target_sp->GetPlatform(); + +        if (remote_file) { +          if (platform_sp) { +            // I have a remote file.. two possible cases +            if (file_spec && FileSystem::Instance().Exists(file_spec)) { +              // if the remote file does not exist, push it there +              if (!platform_sp->GetFileExists(remote_file)) { +                Status err = platform_sp->PutFile(file_spec, remote_file); +                if (err.Fail()) { +                  result.AppendError(err.AsCString()); +                  result.SetStatus(eReturnStatusFailed); +                  return false; +                } +              } +            } else { +              // there is no local file and we need one +              // in order to make the remote ---> local transfer we need a +              // platform +              // TODO: if the user has passed in a --platform argument, use it +              // to fetch the right platform +              if (!platform_sp) { +                result.AppendError( +                    "unable to perform remote debugging without a platform"); +                result.SetStatus(eReturnStatusFailed); +                return false; +              } +              if (file_path) { +                // copy the remote file to the local file +                Status err = platform_sp->GetFile(remote_file, file_spec); +                if (err.Fail()) { +                  result.AppendError(err.AsCString()); +                  result.SetStatus(eReturnStatusFailed); +                  return false; +                } +              } else { +                // make up a local file +                result.AppendError("remote --> local transfer without local " +                                   "path is not implemented yet"); +                result.SetStatus(eReturnStatusFailed); +                return false; +              } +            } +          } else { +            result.AppendError("no platform found for target"); +            result.SetStatus(eReturnStatusFailed); +            return false; +          } +        } + +        if (symfile || remote_file) { +          ModuleSP module_sp(target_sp->GetExecutableModule()); +          if (module_sp) { +            if (symfile) +              module_sp->SetSymbolFileFileSpec(symfile); +            if (remote_file) { +              std::string remote_path = remote_file.GetPath(); +              target_sp->SetArg0(remote_path.c_str()); +              module_sp->SetPlatformFileSpec(remote_file); +            } +          } +        } + +        debugger.GetTargetList().SetSelectedTarget(target_sp.get()); +        if (must_set_platform_path) { +          ModuleSpec main_module_spec(file_spec); +          ModuleSP module_sp = target_sp->GetOrCreateModule(main_module_spec, +                                                          true /* notify */); +          if (module_sp) +            module_sp->SetPlatformFileSpec(remote_file); +        } +        if (core_file) { +          char core_path[PATH_MAX]; +          core_file.GetPath(core_path, sizeof(core_path)); +          if (FileSystem::Instance().Exists(core_file)) { +            if (!FileSystem::Instance().Readable(core_file)) { +              result.AppendMessageWithFormat( +                  "Core file '%s' is not readable.\n", core_path); +              result.SetStatus(eReturnStatusFailed); +              return false; +            } +            FileSpec core_file_dir; +            core_file_dir.GetDirectory() = core_file.GetDirectory(); +            target_sp->AppendExecutableSearchPaths(core_file_dir); + +            ProcessSP process_sp(target_sp->CreateProcess( +                GetDebugger().GetListener(), llvm::StringRef(), &core_file)); + +            if (process_sp) { +              // Seems weird that we Launch a core file, but that is what we +              // do! +              error = process_sp->LoadCore(); + +              if (error.Fail()) { +                result.AppendError( +                    error.AsCString("can't find plug-in for core file")); +                result.SetStatus(eReturnStatusFailed); +                return false; +              } else { +                result.AppendMessageWithFormat( +                    "Core file '%s' (%s) was loaded.\n", core_path, +                    target_sp->GetArchitecture().GetArchitectureName()); +                result.SetStatus(eReturnStatusSuccessFinishNoResult); +              } +            } else { +              result.AppendErrorWithFormat( +                  "Unable to find process plug-in for core file '%s'\n", +                  core_path); +              result.SetStatus(eReturnStatusFailed); +            } +          } else { +            result.AppendErrorWithFormat("Core file '%s' does not exist\n", +                                         core_path); +            result.SetStatus(eReturnStatusFailed); +          } +        } else { +          result.AppendMessageWithFormat( +              "Current executable set to '%s' (%s).\n", +              file_spec.GetPath().c_str(), +              target_sp->GetArchitecture().GetArchitectureName()); +          result.SetStatus(eReturnStatusSuccessFinishNoResult); +        } +      } else { +        result.AppendError(error.AsCString()); +        result.SetStatus(eReturnStatusFailed); +      } +    } else { +      result.AppendErrorWithFormat("'%s' takes exactly one executable path " +                                   "argument, or use the --core option.\n", +                                   m_cmd_name.c_str()); +      result.SetStatus(eReturnStatusFailed); +    } +    return result.Succeeded(); +  } + +private: +  OptionGroupOptions m_option_group; +  OptionGroupArchitecture m_arch_option; +  OptionGroupFile m_core_file; +  OptionGroupFile m_platform_path; +  OptionGroupFile m_symbol_file; +  OptionGroupFile m_remote_file; +  OptionGroupDependents m_add_dependents; +}; + +#pragma mark CommandObjectTargetList + +// "target list" + +class CommandObjectTargetList : public CommandObjectParsed { +public: +  CommandObjectTargetList(CommandInterpreter &interpreter) +      : CommandObjectParsed( +            interpreter, "target list", +            "List all current targets in the current debug session.", nullptr) { +  } + +  ~CommandObjectTargetList() override = default; + +protected: +  bool DoExecute(Args &args, CommandReturnObject &result) override { +    if (args.GetArgumentCount() == 0) { +      Stream &strm = result.GetOutputStream(); + +      bool show_stopped_process_status = false; +      if (DumpTargetList(GetDebugger().GetTargetList(), +                         show_stopped_process_status, strm) == 0) { +        strm.PutCString("No targets.\n"); +      } +      result.SetStatus(eReturnStatusSuccessFinishResult); +    } else { +      result.AppendError("the 'target list' command takes no arguments\n"); +      result.SetStatus(eReturnStatusFailed); +    } +    return result.Succeeded(); +  } +}; + +#pragma mark CommandObjectTargetSelect + +// "target select" + +class CommandObjectTargetSelect : public CommandObjectParsed { +public: +  CommandObjectTargetSelect(CommandInterpreter &interpreter) +      : CommandObjectParsed( +            interpreter, "target select", +            "Select a target as the current target by target index.", nullptr) { +  } + +  ~CommandObjectTargetSelect() override = default; + +protected: +  bool DoExecute(Args &args, CommandReturnObject &result) override { +    if (args.GetArgumentCount() == 1) { +      bool success = false; +      const char *target_idx_arg = args.GetArgumentAtIndex(0); +      uint32_t target_idx = +          StringConvert::ToUInt32(target_idx_arg, UINT32_MAX, 0, &success); +      if (success) { +        TargetList &target_list = GetDebugger().GetTargetList(); +        const uint32_t num_targets = target_list.GetNumTargets(); +        if (target_idx < num_targets) { +          TargetSP target_sp(target_list.GetTargetAtIndex(target_idx)); +          if (target_sp) { +            Stream &strm = result.GetOutputStream(); +            target_list.SetSelectedTarget(target_sp.get()); +            bool show_stopped_process_status = false; +            DumpTargetList(target_list, show_stopped_process_status, strm); +            result.SetStatus(eReturnStatusSuccessFinishResult); +          } else { +            result.AppendErrorWithFormat("target #%u is NULL in target list\n", +                                         target_idx); +            result.SetStatus(eReturnStatusFailed); +          } +        } else { +          if (num_targets > 0) { +            result.AppendErrorWithFormat( +                "index %u is out of range, valid target indexes are 0 - %u\n", +                target_idx, num_targets - 1); +          } else { +            result.AppendErrorWithFormat( +                "index %u is out of range since there are no active targets\n", +                target_idx); +          } +          result.SetStatus(eReturnStatusFailed); +        } +      } else { +        result.AppendErrorWithFormat("invalid index string value '%s'\n", +                                     target_idx_arg); +        result.SetStatus(eReturnStatusFailed); +      } +    } else { +      result.AppendError( +          "'target select' takes a single argument: a target index\n"); +      result.SetStatus(eReturnStatusFailed); +    } +    return result.Succeeded(); +  } +}; + +#pragma mark CommandObjectTargetSelect + +// "target delete" + +class CommandObjectTargetDelete : public CommandObjectParsed { +public: +  CommandObjectTargetDelete(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "target delete", +                            "Delete one or more targets by target index.", +                            nullptr), +        m_option_group(), m_all_option(LLDB_OPT_SET_1, false, "all", 'a', +                                       "Delete all targets.", false, true), +        m_cleanup_option( +            LLDB_OPT_SET_1, false, "clean", 'c', +            "Perform extra cleanup to minimize memory consumption after " +            "deleting the target.  " +            "By default, LLDB will keep in memory any modules previously " +            "loaded by the target as well " +            "as all of its debug info.  Specifying --clean will unload all of " +            "these shared modules and " +            "cause them to be reparsed again the next time the target is run", +            false, true) { +    m_option_group.Append(&m_all_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Append(&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Finalize(); +  } + +  ~CommandObjectTargetDelete() override = default; + +  Options *GetOptions() override { return &m_option_group; } + +protected: +  bool DoExecute(Args &args, CommandReturnObject &result) override { +    const size_t argc = args.GetArgumentCount(); +    std::vector<TargetSP> delete_target_list; +    TargetList &target_list = GetDebugger().GetTargetList(); +    TargetSP target_sp; + +    if (m_all_option.GetOptionValue()) { +      for (int i = 0; i < target_list.GetNumTargets(); ++i) +        delete_target_list.push_back(target_list.GetTargetAtIndex(i)); +    } else if (argc > 0) { +      const uint32_t num_targets = target_list.GetNumTargets(); +      // Bail out if don't have any targets. +      if (num_targets == 0) { +        result.AppendError("no targets to delete"); +        result.SetStatus(eReturnStatusFailed); +        return false; +      } + +      for (auto &entry : args.entries()) { +        uint32_t target_idx; +        if (entry.ref().getAsInteger(0, target_idx)) { +          result.AppendErrorWithFormat("invalid target index '%s'\n", +                                       entry.c_str()); +          result.SetStatus(eReturnStatusFailed); +          return false; +        } +        if (target_idx < num_targets) { +          target_sp = target_list.GetTargetAtIndex(target_idx); +          if (target_sp) { +            delete_target_list.push_back(target_sp); +            continue; +          } +        } +        if (num_targets > 1) +          result.AppendErrorWithFormat("target index %u is out of range, valid " +                                       "target indexes are 0 - %u\n", +                                       target_idx, num_targets - 1); +        else +          result.AppendErrorWithFormat( +              "target index %u is out of range, the only valid index is 0\n", +              target_idx); + +        result.SetStatus(eReturnStatusFailed); +        return false; +      } +    } else { +      target_sp = target_list.GetSelectedTarget(); +      if (!target_sp) { +        result.AppendErrorWithFormat("no target is currently selected\n"); +        result.SetStatus(eReturnStatusFailed); +        return false; +      } +      delete_target_list.push_back(target_sp); +    } + +    const size_t num_targets_to_delete = delete_target_list.size(); +    for (size_t idx = 0; idx < num_targets_to_delete; ++idx) { +      target_sp = delete_target_list[idx]; +      target_list.DeleteTarget(target_sp); +      target_sp->Destroy(); +    } +    // If "--clean" was specified, prune any orphaned shared modules from the +    // global shared module list +    if (m_cleanup_option.GetOptionValue()) { +      const bool mandatory = true; +      ModuleList::RemoveOrphanSharedModules(mandatory); +    } +    result.GetOutputStream().Printf("%u targets deleted.\n", +                                    (uint32_t)num_targets_to_delete); +    result.SetStatus(eReturnStatusSuccessFinishResult); + +    return true; +  } + +  OptionGroupOptions m_option_group; +  OptionGroupBoolean m_all_option; +  OptionGroupBoolean m_cleanup_option; +}; + +#pragma mark CommandObjectTargetVariable + +// "target variable" + +class CommandObjectTargetVariable : public CommandObjectParsed { +  static const uint32_t SHORT_OPTION_FILE = 0x66696c65; // 'file' +  static const uint32_t SHORT_OPTION_SHLB = 0x73686c62; // 'shlb' + +public: +  CommandObjectTargetVariable(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "target variable", +                            "Read global variables for the current target, " +                            "before or while running a process.", +                            nullptr, eCommandRequiresTarget), +        m_option_group(), +        m_option_variable(false), // Don't include frame options +        m_option_format(eFormatDefault), +        m_option_compile_units(LLDB_OPT_SET_1, false, "file", SHORT_OPTION_FILE, +                               0, eArgTypeFilename, +                               "A basename or fullpath to a file that contains " +                               "global variables. This option can be " +                               "specified multiple times."), +        m_option_shared_libraries( +            LLDB_OPT_SET_1, false, "shlib", SHORT_OPTION_SHLB, 0, +            eArgTypeFilename, +            "A basename or fullpath to a shared library to use in the search " +            "for global " +            "variables. This option can be specified multiple times."), +        m_varobj_options() { +    CommandArgumentEntry arg; +    CommandArgumentData var_name_arg; + +    // Define the first (and only) variant of this arg. +    var_name_arg.arg_type = eArgTypeVarName; +    var_name_arg.arg_repetition = eArgRepeatPlus; + +    // There is only one variant this argument could be; put it into the +    // argument entry. +    arg.push_back(var_name_arg); + +    // Push the data for the first argument into the m_arguments vector. +    m_arguments.push_back(arg); + +    m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Append(&m_option_format, +                          OptionGroupFormat::OPTION_GROUP_FORMAT | +                              OptionGroupFormat::OPTION_GROUP_GDB_FMT, +                          LLDB_OPT_SET_1); +    m_option_group.Append(&m_option_compile_units, LLDB_OPT_SET_ALL, +                          LLDB_OPT_SET_1); +    m_option_group.Append(&m_option_shared_libraries, LLDB_OPT_SET_ALL, +                          LLDB_OPT_SET_1); +    m_option_group.Finalize(); +  } + +  ~CommandObjectTargetVariable() override = default; + +  void DumpValueObject(Stream &s, VariableSP &var_sp, ValueObjectSP &valobj_sp, +                       const char *root_name) { +    DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions()); + +    if (!valobj_sp->GetTargetSP()->GetDisplayRuntimeSupportValues() && +        valobj_sp->IsRuntimeSupportValue()) +      return; + +    switch (var_sp->GetScope()) { +    case eValueTypeVariableGlobal: +      if (m_option_variable.show_scope) +        s.PutCString("GLOBAL: "); +      break; + +    case eValueTypeVariableStatic: +      if (m_option_variable.show_scope) +        s.PutCString("STATIC: "); +      break; + +    case eValueTypeVariableArgument: +      if (m_option_variable.show_scope) +        s.PutCString("   ARG: "); +      break; + +    case eValueTypeVariableLocal: +      if (m_option_variable.show_scope) +        s.PutCString(" LOCAL: "); +      break; + +    case eValueTypeVariableThreadLocal: +      if (m_option_variable.show_scope) +        s.PutCString("THREAD: "); +      break; + +    default: +      break; +    } + +    if (m_option_variable.show_decl) { +      bool show_fullpaths = false; +      bool show_module = true; +      if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module)) +        s.PutCString(": "); +    } + +    const Format format = m_option_format.GetFormat(); +    if (format != eFormatDefault) +      options.SetFormat(format); + +    options.SetRootValueObjectName(root_name); + +    valobj_sp->Dump(s, options); +  } + +  static size_t GetVariableCallback(void *baton, const char *name, +                                    VariableList &variable_list) { +    size_t old_size = variable_list.GetSize(); +    Target *target = static_cast<Target *>(baton); +    if (target) +      target->GetImages().FindGlobalVariables(ConstString(name), UINT32_MAX, +                                              variable_list); +    return variable_list.GetSize() - old_size; +  } + +  Options *GetOptions() override { return &m_option_group; } + +protected: +  void DumpGlobalVariableList(const ExecutionContext &exe_ctx, +                              const SymbolContext &sc, +                              const VariableList &variable_list, Stream &s) { +    size_t count = variable_list.GetSize(); +    if (count > 0) { +      if (sc.module_sp) { +        if (sc.comp_unit) { +          s.Printf("Global variables for %s in %s:\n", +                   sc.comp_unit->GetPath().c_str(), +                   sc.module_sp->GetFileSpec().GetPath().c_str()); +        } else { +          s.Printf("Global variables for %s\n", +                   sc.module_sp->GetFileSpec().GetPath().c_str()); +        } +      } else if (sc.comp_unit) { +        s.Printf("Global variables for %s\n", sc.comp_unit->GetPath().c_str()); +      } + +      for (uint32_t i = 0; i < count; ++i) { +        VariableSP var_sp(variable_list.GetVariableAtIndex(i)); +        if (var_sp) { +          ValueObjectSP valobj_sp(ValueObjectVariable::Create( +              exe_ctx.GetBestExecutionContextScope(), var_sp)); + +          if (valobj_sp) +            DumpValueObject(s, var_sp, valobj_sp, +                            var_sp->GetName().GetCString()); +        } +      } +    } +  } + +  bool DoExecute(Args &args, CommandReturnObject &result) override { +    Target *target = m_exe_ctx.GetTargetPtr(); +    const size_t argc = args.GetArgumentCount(); +    Stream &s = result.GetOutputStream(); + +    if (argc > 0) { + +      // TODO: Convert to entry-based iteration.  Requires converting +      // DumpValueObject. +      for (size_t idx = 0; idx < argc; ++idx) { +        VariableList variable_list; +        ValueObjectList valobj_list; + +        const char *arg = args.GetArgumentAtIndex(idx); +        size_t matches = 0; +        bool use_var_name = false; +        if (m_option_variable.use_regex) { +          RegularExpression regex(llvm::StringRef::withNullAsEmpty(arg)); +          if (!regex.IsValid()) { +            result.GetErrorStream().Printf( +                "error: invalid regular expression: '%s'\n", arg); +            result.SetStatus(eReturnStatusFailed); +            return false; +          } +          use_var_name = true; +          target->GetImages().FindGlobalVariables(regex, UINT32_MAX, +                                                  variable_list); +          matches = variable_list.GetSize(); +        } else { +          Status error(Variable::GetValuesForVariableExpressionPath( +              arg, m_exe_ctx.GetBestExecutionContextScope(), +              GetVariableCallback, target, variable_list, valobj_list)); +          matches = variable_list.GetSize(); +        } + +        if (matches == 0) { +          result.GetErrorStream().Printf( +              "error: can't find global variable '%s'\n", arg); +          result.SetStatus(eReturnStatusFailed); +          return false; +        } else { +          for (uint32_t global_idx = 0; global_idx < matches; ++global_idx) { +            VariableSP var_sp(variable_list.GetVariableAtIndex(global_idx)); +            if (var_sp) { +              ValueObjectSP valobj_sp( +                  valobj_list.GetValueObjectAtIndex(global_idx)); +              if (!valobj_sp) +                valobj_sp = ValueObjectVariable::Create( +                    m_exe_ctx.GetBestExecutionContextScope(), var_sp); + +              if (valobj_sp) +                DumpValueObject(s, var_sp, valobj_sp, +                                use_var_name ? var_sp->GetName().GetCString() +                                             : arg); +            } +          } +        } +      } +    } else { +      const FileSpecList &compile_units = +          m_option_compile_units.GetOptionValue().GetCurrentValue(); +      const FileSpecList &shlibs = +          m_option_shared_libraries.GetOptionValue().GetCurrentValue(); +      SymbolContextList sc_list; +      const size_t num_compile_units = compile_units.GetSize(); +      const size_t num_shlibs = shlibs.GetSize(); +      if (num_compile_units == 0 && num_shlibs == 0) { +        bool success = false; +        StackFrame *frame = m_exe_ctx.GetFramePtr(); +        CompileUnit *comp_unit = nullptr; +        if (frame) { +          SymbolContext sc = frame->GetSymbolContext(eSymbolContextCompUnit); +          if (sc.comp_unit) { +            const bool can_create = true; +            VariableListSP comp_unit_varlist_sp( +                sc.comp_unit->GetVariableList(can_create)); +            if (comp_unit_varlist_sp) { +              size_t count = comp_unit_varlist_sp->GetSize(); +              if (count > 0) { +                DumpGlobalVariableList(m_exe_ctx, sc, *comp_unit_varlist_sp, s); +                success = true; +              } +            } +          } +        } +        if (!success) { +          if (frame) { +            if (comp_unit) +              result.AppendErrorWithFormat( +                  "no global variables in current compile unit: %s\n", +                  comp_unit->GetPath().c_str()); +            else +              result.AppendErrorWithFormat( +                  "no debug information for frame %u\n", +                  frame->GetFrameIndex()); +          } else +            result.AppendError("'target variable' takes one or more global " +                               "variable names as arguments\n"); +          result.SetStatus(eReturnStatusFailed); +        } +      } else { +        SymbolContextList sc_list; +        // We have one or more compile unit or shlib +        if (num_shlibs > 0) { +          for (size_t shlib_idx = 0; shlib_idx < num_shlibs; ++shlib_idx) { +            const FileSpec module_file(shlibs.GetFileSpecAtIndex(shlib_idx)); +            ModuleSpec module_spec(module_file); + +            ModuleSP module_sp( +                target->GetImages().FindFirstModule(module_spec)); +            if (module_sp) { +              if (num_compile_units > 0) { +                for (size_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) +                  module_sp->FindCompileUnits( +                      compile_units.GetFileSpecAtIndex(cu_idx), sc_list); +              } else { +                SymbolContext sc; +                sc.module_sp = module_sp; +                sc_list.Append(sc); +              } +            } else { +              // Didn't find matching shlib/module in target... +              result.AppendErrorWithFormat( +                  "target doesn't contain the specified shared library: %s\n", +                  module_file.GetPath().c_str()); +            } +          } +        } else { +          // No shared libraries, we just want to find globals for the compile +          // units files that were specified +          for (size_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) +            target->GetImages().FindCompileUnits( +                compile_units.GetFileSpecAtIndex(cu_idx), sc_list); +        } + +        const uint32_t num_scs = sc_list.GetSize(); +        if (num_scs > 0) { +          SymbolContext sc; +          for (uint32_t sc_idx = 0; sc_idx < num_scs; ++sc_idx) { +            if (sc_list.GetContextAtIndex(sc_idx, sc)) { +              if (sc.comp_unit) { +                const bool can_create = true; +                VariableListSP comp_unit_varlist_sp( +                    sc.comp_unit->GetVariableList(can_create)); +                if (comp_unit_varlist_sp) +                  DumpGlobalVariableList(m_exe_ctx, sc, *comp_unit_varlist_sp, +                                         s); +              } else if (sc.module_sp) { +                // Get all global variables for this module +                lldb_private::RegularExpression all_globals_regex( +                    llvm::StringRef( +                        ".")); // Any global with at least one character +                VariableList variable_list; +                sc.module_sp->FindGlobalVariables(all_globals_regex, UINT32_MAX, +                                                  variable_list); +                DumpGlobalVariableList(m_exe_ctx, sc, variable_list, s); +              } +            } +          } +        } +      } +    } + +    if (m_interpreter.TruncationWarningNecessary()) { +      result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), +                                      m_cmd_name.c_str()); +      m_interpreter.TruncationWarningGiven(); +    } + +    return result.Succeeded(); +  } + +  OptionGroupOptions m_option_group; +  OptionGroupVariable m_option_variable; +  OptionGroupFormat m_option_format; +  OptionGroupFileList m_option_compile_units; +  OptionGroupFileList m_option_shared_libraries; +  OptionGroupValueObjectDisplay m_varobj_options; +}; + +#pragma mark CommandObjectTargetModulesSearchPathsAdd + +class CommandObjectTargetModulesSearchPathsAdd : public CommandObjectParsed { +public: +  CommandObjectTargetModulesSearchPathsAdd(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "target modules search-paths add", +                            "Add new image search paths substitution pairs to " +                            "the current target.", +                            nullptr, eCommandRequiresTarget) { +    CommandArgumentEntry arg; +    CommandArgumentData old_prefix_arg; +    CommandArgumentData new_prefix_arg; + +    // Define the first variant of this arg pair. +    old_prefix_arg.arg_type = eArgTypeOldPathPrefix; +    old_prefix_arg.arg_repetition = eArgRepeatPairPlus; + +    // Define the first variant of this arg pair. +    new_prefix_arg.arg_type = eArgTypeNewPathPrefix; +    new_prefix_arg.arg_repetition = eArgRepeatPairPlus; + +    // There are two required arguments that must always occur together, i.e. +    // an argument "pair".  Because they must always occur together, they are +    // treated as two variants of one argument rather than two independent +    // arguments.  Push them both into the first argument position for +    // m_arguments... + +    arg.push_back(old_prefix_arg); +    arg.push_back(new_prefix_arg); + +    m_arguments.push_back(arg); +  } + +  ~CommandObjectTargetModulesSearchPathsAdd() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    const size_t argc = command.GetArgumentCount(); +    if (argc & 1) { +      result.AppendError("add requires an even number of arguments\n"); +      result.SetStatus(eReturnStatusFailed); +    } else { +      for (size_t i = 0; i < argc; i += 2) { +        const char *from = command.GetArgumentAtIndex(i); +        const char *to = command.GetArgumentAtIndex(i + 1); + +        if (from[0] && to[0]) { +          Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); +          if (log) { +            LLDB_LOGF(log, +                      "target modules search path adding ImageSearchPath " +                      "pair: '%s' -> '%s'", +                      from, to); +          } +          bool last_pair = ((argc - i) == 2); +          target->GetImageSearchPathList().Append( +              ConstString(from), ConstString(to), +              last_pair); // Notify if this is the last pair +          result.SetStatus(eReturnStatusSuccessFinishNoResult); +        } else { +          if (from[0]) +            result.AppendError("<path-prefix> can't be empty\n"); +          else +            result.AppendError("<new-path-prefix> can't be empty\n"); +          result.SetStatus(eReturnStatusFailed); +        } +      } +    } +    return result.Succeeded(); +  } +}; + +#pragma mark CommandObjectTargetModulesSearchPathsClear + +class CommandObjectTargetModulesSearchPathsClear : public CommandObjectParsed { +public: +  CommandObjectTargetModulesSearchPathsClear(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "target modules search-paths clear", +                            "Clear all current image search path substitution " +                            "pairs from the current target.", +                            "target modules search-paths clear", +                            eCommandRequiresTarget) {} + +  ~CommandObjectTargetModulesSearchPathsClear() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    bool notify = true; +    target->GetImageSearchPathList().Clear(notify); +    result.SetStatus(eReturnStatusSuccessFinishNoResult); +    return result.Succeeded(); +  } +}; + +#pragma mark CommandObjectTargetModulesSearchPathsInsert + +class CommandObjectTargetModulesSearchPathsInsert : public CommandObjectParsed { +public: +  CommandObjectTargetModulesSearchPathsInsert(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "target modules search-paths insert", +                            "Insert a new image search path substitution pair " +                            "into the current target at the specified index.", +                            nullptr, eCommandRequiresTarget) { +    CommandArgumentEntry arg1; +    CommandArgumentEntry arg2; +    CommandArgumentData index_arg; +    CommandArgumentData old_prefix_arg; +    CommandArgumentData new_prefix_arg; + +    // Define the first and only variant of this arg. +    index_arg.arg_type = eArgTypeIndex; +    index_arg.arg_repetition = eArgRepeatPlain; + +    // Put the one and only variant into the first arg for m_arguments: +    arg1.push_back(index_arg); + +    // Define the first variant of this arg pair. +    old_prefix_arg.arg_type = eArgTypeOldPathPrefix; +    old_prefix_arg.arg_repetition = eArgRepeatPairPlus; + +    // Define the first variant of this arg pair. +    new_prefix_arg.arg_type = eArgTypeNewPathPrefix; +    new_prefix_arg.arg_repetition = eArgRepeatPairPlus; + +    // There are two required arguments that must always occur together, i.e. +    // an argument "pair".  Because they must always occur together, they are +    // treated as two variants of one argument rather than two independent +    // arguments.  Push them both into the same argument position for +    // m_arguments... + +    arg2.push_back(old_prefix_arg); +    arg2.push_back(new_prefix_arg); + +    // Add arguments to m_arguments. +    m_arguments.push_back(arg1); +    m_arguments.push_back(arg2); +  } + +  ~CommandObjectTargetModulesSearchPathsInsert() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    size_t argc = command.GetArgumentCount(); +    // check for at least 3 arguments and an odd number of parameters +    if (argc >= 3 && argc & 1) { +      bool success = false; + +      uint32_t insert_idx = StringConvert::ToUInt32( +          command.GetArgumentAtIndex(0), UINT32_MAX, 0, &success); + +      if (!success) { +        result.AppendErrorWithFormat( +            "<index> parameter is not an integer: '%s'.\n", +            command.GetArgumentAtIndex(0)); +        result.SetStatus(eReturnStatusFailed); +        return result.Succeeded(); +      } + +      // shift off the index +      command.Shift(); +      argc = command.GetArgumentCount(); + +      for (uint32_t i = 0; i < argc; i += 2, ++insert_idx) { +        const char *from = command.GetArgumentAtIndex(i); +        const char *to = command.GetArgumentAtIndex(i + 1); + +        if (from[0] && to[0]) { +          bool last_pair = ((argc - i) == 2); +          target->GetImageSearchPathList().Insert( +              ConstString(from), ConstString(to), insert_idx, last_pair); +          result.SetStatus(eReturnStatusSuccessFinishNoResult); +        } else { +          if (from[0]) +            result.AppendError("<path-prefix> can't be empty\n"); +          else +            result.AppendError("<new-path-prefix> can't be empty\n"); +          result.SetStatus(eReturnStatusFailed); +          return false; +        } +      } +    } else { +      result.AppendError("insert requires at least three arguments\n"); +      result.SetStatus(eReturnStatusFailed); +      return result.Succeeded(); +    } +    return result.Succeeded(); +  } +}; + +#pragma mark CommandObjectTargetModulesSearchPathsList + +class CommandObjectTargetModulesSearchPathsList : public CommandObjectParsed { +public: +  CommandObjectTargetModulesSearchPathsList(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "target modules search-paths list", +                            "List all current image search path substitution " +                            "pairs in the current target.", +                            "target modules search-paths list", +                            eCommandRequiresTarget) {} + +  ~CommandObjectTargetModulesSearchPathsList() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    if (command.GetArgumentCount() != 0) { +      result.AppendError("list takes no arguments\n"); +      result.SetStatus(eReturnStatusFailed); +      return result.Succeeded(); +    } + +    target->GetImageSearchPathList().Dump(&result.GetOutputStream()); +    result.SetStatus(eReturnStatusSuccessFinishResult); +    return result.Succeeded(); +  } +}; + +#pragma mark CommandObjectTargetModulesSearchPathsQuery + +class CommandObjectTargetModulesSearchPathsQuery : public CommandObjectParsed { +public: +  CommandObjectTargetModulesSearchPathsQuery(CommandInterpreter &interpreter) +      : CommandObjectParsed( +            interpreter, "target modules search-paths query", +            "Transform a path using the first applicable image search path.", +            nullptr, eCommandRequiresTarget) { +    CommandArgumentEntry arg; +    CommandArgumentData path_arg; + +    // Define the first (and only) variant of this arg. +    path_arg.arg_type = eArgTypeDirectoryName; +    path_arg.arg_repetition = eArgRepeatPlain; + +    // There is only one variant this argument could be; put it into the +    // argument entry. +    arg.push_back(path_arg); + +    // Push the data for the first argument into the m_arguments vector. +    m_arguments.push_back(arg); +  } + +  ~CommandObjectTargetModulesSearchPathsQuery() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    if (command.GetArgumentCount() != 1) { +      result.AppendError("query requires one argument\n"); +      result.SetStatus(eReturnStatusFailed); +      return result.Succeeded(); +    } + +    ConstString orig(command.GetArgumentAtIndex(0)); +    ConstString transformed; +    if (target->GetImageSearchPathList().RemapPath(orig, transformed)) +      result.GetOutputStream().Printf("%s\n", transformed.GetCString()); +    else +      result.GetOutputStream().Printf("%s\n", orig.GetCString()); + +    result.SetStatus(eReturnStatusSuccessFinishResult); +    return result.Succeeded(); +  } +}; + +// Static Helper functions +static void DumpModuleArchitecture(Stream &strm, Module *module, +                                   bool full_triple, uint32_t width) { +  if (module) { +    StreamString arch_strm; + +    if (full_triple) +      module->GetArchitecture().DumpTriple(arch_strm); +    else +      arch_strm.PutCString(module->GetArchitecture().GetArchitectureName()); +    std::string arch_str = arch_strm.GetString(); + +    if (width) +      strm.Printf("%-*s", width, arch_str.c_str()); +    else +      strm.PutCString(arch_str); +  } +} + +static void DumpModuleUUID(Stream &strm, Module *module) { +  if (module && module->GetUUID().IsValid()) +    module->GetUUID().Dump(&strm); +  else +    strm.PutCString("                                    "); +} + +static uint32_t DumpCompileUnitLineTable(CommandInterpreter &interpreter, +                                         Stream &strm, Module *module, +                                         const FileSpec &file_spec, +                                         lldb::DescriptionLevel desc_level) { +  uint32_t num_matches = 0; +  if (module) { +    SymbolContextList sc_list; +    num_matches = module->ResolveSymbolContextsForFileSpec( +        file_spec, 0, false, eSymbolContextCompUnit, sc_list); + +    for (uint32_t i = 0; i < num_matches; ++i) { +      SymbolContext sc; +      if (sc_list.GetContextAtIndex(i, sc)) { +        if (i > 0) +          strm << "\n\n"; + +        strm << "Line table for " << *static_cast<FileSpec *>(sc.comp_unit) +             << " in `" << module->GetFileSpec().GetFilename() << "\n"; +        LineTable *line_table = sc.comp_unit->GetLineTable(); +        if (line_table) +          line_table->GetDescription( +              &strm, interpreter.GetExecutionContext().GetTargetPtr(), +              desc_level); +        else +          strm << "No line table"; +      } +    } +  } +  return num_matches; +} + +static void DumpFullpath(Stream &strm, const FileSpec *file_spec_ptr, +                         uint32_t width) { +  if (file_spec_ptr) { +    if (width > 0) { +      std::string fullpath = file_spec_ptr->GetPath(); +      strm.Printf("%-*s", width, fullpath.c_str()); +      return; +    } else { +      file_spec_ptr->Dump(&strm); +      return; +    } +  } +  // Keep the width spacing correct if things go wrong... +  if (width > 0) +    strm.Printf("%-*s", width, ""); +} + +static void DumpDirectory(Stream &strm, const FileSpec *file_spec_ptr, +                          uint32_t width) { +  if (file_spec_ptr) { +    if (width > 0) +      strm.Printf("%-*s", width, file_spec_ptr->GetDirectory().AsCString("")); +    else +      file_spec_ptr->GetDirectory().Dump(&strm); +    return; +  } +  // Keep the width spacing correct if things go wrong... +  if (width > 0) +    strm.Printf("%-*s", width, ""); +} + +static void DumpBasename(Stream &strm, const FileSpec *file_spec_ptr, +                         uint32_t width) { +  if (file_spec_ptr) { +    if (width > 0) +      strm.Printf("%-*s", width, file_spec_ptr->GetFilename().AsCString("")); +    else +      file_spec_ptr->GetFilename().Dump(&strm); +    return; +  } +  // Keep the width spacing correct if things go wrong... +  if (width > 0) +    strm.Printf("%-*s", width, ""); +} + +static size_t DumpModuleObjfileHeaders(Stream &strm, ModuleList &module_list) { +  size_t num_dumped = 0; +  std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); +  const size_t num_modules = module_list.GetSize(); +  if (num_modules > 0) { +    strm.Printf("Dumping headers for %" PRIu64 " module(s).\n", +                static_cast<uint64_t>(num_modules)); +    strm.IndentMore(); +    for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { +      Module *module = module_list.GetModulePointerAtIndexUnlocked(image_idx); +      if (module) { +        if (num_dumped++ > 0) { +          strm.EOL(); +          strm.EOL(); +        } +        ObjectFile *objfile = module->GetObjectFile(); +        if (objfile) +          objfile->Dump(&strm); +        else { +          strm.Format("No object file for module: {0:F}\n", +                      module->GetFileSpec()); +        } +      } +    } +    strm.IndentLess(); +  } +  return num_dumped; +} + +static void DumpModuleSymtab(CommandInterpreter &interpreter, Stream &strm, +                             Module *module, SortOrder sort_order) { +  if (!module) +    return; +  if (Symtab *symtab = module->GetSymtab()) +    symtab->Dump(&strm, interpreter.GetExecutionContext().GetTargetPtr(), +                 sort_order); +} + +static void DumpModuleSections(CommandInterpreter &interpreter, Stream &strm, +                               Module *module) { +  if (module) { +    SectionList *section_list = module->GetSectionList(); +    if (section_list) { +      strm.Printf("Sections for '%s' (%s):\n", +                  module->GetSpecificationDescription().c_str(), +                  module->GetArchitecture().GetArchitectureName()); +      strm.IndentMore(); +      section_list->Dump(&strm, +                         interpreter.GetExecutionContext().GetTargetPtr(), true, +                         UINT32_MAX); +      strm.IndentLess(); +    } +  } +} + +static bool DumpModuleSymbolFile(Stream &strm, Module *module) { +  if (module) { +    if (SymbolFile *symbol_file = module->GetSymbolFile(true)) { +      symbol_file->Dump(strm); +      return true; +    } +  } +  return false; +} + +static void DumpAddress(ExecutionContextScope *exe_scope, +                        const Address &so_addr, bool verbose, Stream &strm) { +  strm.IndentMore(); +  strm.Indent("    Address: "); +  so_addr.Dump(&strm, exe_scope, Address::DumpStyleModuleWithFileAddress); +  strm.PutCString(" ("); +  so_addr.Dump(&strm, exe_scope, Address::DumpStyleSectionNameOffset); +  strm.PutCString(")\n"); +  strm.Indent("    Summary: "); +  const uint32_t save_indent = strm.GetIndentLevel(); +  strm.SetIndentLevel(save_indent + 13); +  so_addr.Dump(&strm, exe_scope, Address::DumpStyleResolvedDescription); +  strm.SetIndentLevel(save_indent); +  // Print out detailed address information when verbose is enabled +  if (verbose) { +    strm.EOL(); +    so_addr.Dump(&strm, exe_scope, Address::DumpStyleDetailedSymbolContext); +  } +  strm.IndentLess(); +} + +static bool LookupAddressInModule(CommandInterpreter &interpreter, Stream &strm, +                                  Module *module, uint32_t resolve_mask, +                                  lldb::addr_t raw_addr, lldb::addr_t offset, +                                  bool verbose) { +  if (module) { +    lldb::addr_t addr = raw_addr - offset; +    Address so_addr; +    SymbolContext sc; +    Target *target = interpreter.GetExecutionContext().GetTargetPtr(); +    if (target && !target->GetSectionLoadList().IsEmpty()) { +      if (!target->GetSectionLoadList().ResolveLoadAddress(addr, so_addr)) +        return false; +      else if (so_addr.GetModule().get() != module) +        return false; +    } else { +      if (!module->ResolveFileAddress(addr, so_addr)) +        return false; +    } + +    ExecutionContextScope *exe_scope = +        interpreter.GetExecutionContext().GetBestExecutionContextScope(); +    DumpAddress(exe_scope, so_addr, verbose, strm); +    //        strm.IndentMore(); +    //        strm.Indent ("    Address: "); +    //        so_addr.Dump (&strm, exe_scope, +    //        Address::DumpStyleModuleWithFileAddress); +    //        strm.PutCString (" ("); +    //        so_addr.Dump (&strm, exe_scope, +    //        Address::DumpStyleSectionNameOffset); +    //        strm.PutCString (")\n"); +    //        strm.Indent ("    Summary: "); +    //        const uint32_t save_indent = strm.GetIndentLevel (); +    //        strm.SetIndentLevel (save_indent + 13); +    //        so_addr.Dump (&strm, exe_scope, +    //        Address::DumpStyleResolvedDescription); +    //        strm.SetIndentLevel (save_indent); +    //        // Print out detailed address information when verbose is enabled +    //        if (verbose) +    //        { +    //            strm.EOL(); +    //            so_addr.Dump (&strm, exe_scope, +    //            Address::DumpStyleDetailedSymbolContext); +    //        } +    //        strm.IndentLess(); +    return true; +  } + +  return false; +} + +static uint32_t LookupSymbolInModule(CommandInterpreter &interpreter, +                                     Stream &strm, Module *module, +                                     const char *name, bool name_is_regex, +                                     bool verbose) { +  if (!module) +    return 0; + +  Symtab *symtab = module->GetSymtab(); +  if (!symtab) +    return 0; + +  SymbolContext sc; +  std::vector<uint32_t> match_indexes; +  ConstString symbol_name(name); +  uint32_t num_matches = 0; +  if (name_is_regex) { +    RegularExpression name_regexp(symbol_name.GetStringRef()); +    num_matches = symtab->AppendSymbolIndexesMatchingRegExAndType( +        name_regexp, eSymbolTypeAny, match_indexes); +  } else { +    num_matches = +        symtab->AppendSymbolIndexesWithName(symbol_name, match_indexes); +  } + +  if (num_matches > 0) { +    strm.Indent(); +    strm.Printf("%u symbols match %s'%s' in ", num_matches, +                name_is_regex ? "the regular expression " : "", name); +    DumpFullpath(strm, &module->GetFileSpec(), 0); +    strm.PutCString(":\n"); +    strm.IndentMore(); +    for (uint32_t i = 0; i < num_matches; ++i) { +      Symbol *symbol = symtab->SymbolAtIndex(match_indexes[i]); +      if (symbol && symbol->ValueIsAddress()) { +        DumpAddress( +            interpreter.GetExecutionContext().GetBestExecutionContextScope(), +            symbol->GetAddressRef(), verbose, strm); +      } +    } +    strm.IndentLess(); +  } +  return num_matches; +} + +static void DumpSymbolContextList(ExecutionContextScope *exe_scope, +                                  Stream &strm, SymbolContextList &sc_list, +                                  bool verbose) { +  strm.IndentMore(); + +  const uint32_t num_matches = sc_list.GetSize(); + +  for (uint32_t i = 0; i < num_matches; ++i) { +    SymbolContext sc; +    if (sc_list.GetContextAtIndex(i, sc)) { +      AddressRange range; + +      sc.GetAddressRange(eSymbolContextEverything, 0, true, range); + +      DumpAddress(exe_scope, range.GetBaseAddress(), verbose, strm); +    } +  } +  strm.IndentLess(); +} + +static size_t LookupFunctionInModule(CommandInterpreter &interpreter, +                                     Stream &strm, Module *module, +                                     const char *name, bool name_is_regex, +                                     bool include_inlines, bool include_symbols, +                                     bool verbose) { +  if (module && name && name[0]) { +    SymbolContextList sc_list; +    size_t num_matches = 0; +    if (name_is_regex) { +      RegularExpression function_name_regex((llvm::StringRef(name))); +      module->FindFunctions(function_name_regex, include_symbols, +                            include_inlines, sc_list); +    } else { +      ConstString function_name(name); +      module->FindFunctions(function_name, nullptr, eFunctionNameTypeAuto, +                            include_symbols, include_inlines, sc_list); +    } +    num_matches = sc_list.GetSize(); +    if (num_matches) { +      strm.Indent(); +      strm.Printf("%" PRIu64 " match%s found in ", (uint64_t)num_matches, +                  num_matches > 1 ? "es" : ""); +      DumpFullpath(strm, &module->GetFileSpec(), 0); +      strm.PutCString(":\n"); +      DumpSymbolContextList( +          interpreter.GetExecutionContext().GetBestExecutionContextScope(), +          strm, sc_list, verbose); +    } +    return num_matches; +  } +  return 0; +} + +static size_t LookupTypeInModule(CommandInterpreter &interpreter, Stream &strm, +                                 Module *module, const char *name_cstr, +                                 bool name_is_regex) { +  TypeList type_list; +  if (module && name_cstr && name_cstr[0]) { +    const uint32_t max_num_matches = UINT32_MAX; +    size_t num_matches = 0; +    bool name_is_fully_qualified = false; + +    ConstString name(name_cstr); +    llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files; +    module->FindTypes(name, name_is_fully_qualified, max_num_matches, +                      searched_symbol_files, type_list); + +    if (type_list.Empty()) +      return 0; + +    strm.Indent(); +    strm.Printf("%" PRIu64 " match%s found in ", (uint64_t)num_matches, +                num_matches > 1 ? "es" : ""); +    DumpFullpath(strm, &module->GetFileSpec(), 0); +    strm.PutCString(":\n"); +    for (TypeSP type_sp : type_list.Types()) { +      if (!type_sp) +        continue; +      // Resolve the clang type so that any forward references to types +      // that haven't yet been parsed will get parsed. +      type_sp->GetFullCompilerType(); +      type_sp->GetDescription(&strm, eDescriptionLevelFull, true); +      // Print all typedef chains +      TypeSP typedef_type_sp(type_sp); +      TypeSP typedefed_type_sp(typedef_type_sp->GetTypedefType()); +      while (typedefed_type_sp) { +        strm.EOL(); +        strm.Printf("     typedef '%s': ", +                    typedef_type_sp->GetName().GetCString()); +        typedefed_type_sp->GetFullCompilerType(); +        typedefed_type_sp->GetDescription(&strm, eDescriptionLevelFull, true); +        typedef_type_sp = typedefed_type_sp; +        typedefed_type_sp = typedef_type_sp->GetTypedefType(); +      } +    } +    strm.EOL(); +  } +  return type_list.GetSize(); +} + +static size_t LookupTypeHere(CommandInterpreter &interpreter, Stream &strm, +                             Module &module, const char *name_cstr, +                             bool name_is_regex) { +  TypeList type_list; +  const uint32_t max_num_matches = UINT32_MAX; +  bool name_is_fully_qualified = false; + +  ConstString name(name_cstr); +  llvm::DenseSet<SymbolFile *> searched_symbol_files; +  module.FindTypes(name, name_is_fully_qualified, max_num_matches, +                   searched_symbol_files, type_list); + +  if (type_list.Empty()) +    return 0; + +  strm.Indent(); +  strm.PutCString("Best match found in "); +  DumpFullpath(strm, &module.GetFileSpec(), 0); +  strm.PutCString(":\n"); + +  TypeSP type_sp(type_list.GetTypeAtIndex(0)); +  if (type_sp) { +    // Resolve the clang type so that any forward references to types that +    // haven't yet been parsed will get parsed. +    type_sp->GetFullCompilerType(); +    type_sp->GetDescription(&strm, eDescriptionLevelFull, true); +    // Print all typedef chains +    TypeSP typedef_type_sp(type_sp); +    TypeSP typedefed_type_sp(typedef_type_sp->GetTypedefType()); +    while (typedefed_type_sp) { +      strm.EOL(); +      strm.Printf("     typedef '%s': ", +                  typedef_type_sp->GetName().GetCString()); +      typedefed_type_sp->GetFullCompilerType(); +      typedefed_type_sp->GetDescription(&strm, eDescriptionLevelFull, true); +      typedef_type_sp = typedefed_type_sp; +      typedefed_type_sp = typedef_type_sp->GetTypedefType(); +    } +  } +  strm.EOL(); +  return type_list.GetSize(); +} + +static uint32_t LookupFileAndLineInModule(CommandInterpreter &interpreter, +                                          Stream &strm, Module *module, +                                          const FileSpec &file_spec, +                                          uint32_t line, bool check_inlines, +                                          bool verbose) { +  if (module && file_spec) { +    SymbolContextList sc_list; +    const uint32_t num_matches = module->ResolveSymbolContextsForFileSpec( +        file_spec, line, check_inlines, eSymbolContextEverything, sc_list); +    if (num_matches > 0) { +      strm.Indent(); +      strm.Printf("%u match%s found in ", num_matches, +                  num_matches > 1 ? "es" : ""); +      strm << file_spec; +      if (line > 0) +        strm.Printf(":%u", line); +      strm << " in "; +      DumpFullpath(strm, &module->GetFileSpec(), 0); +      strm.PutCString(":\n"); +      DumpSymbolContextList( +          interpreter.GetExecutionContext().GetBestExecutionContextScope(), +          strm, sc_list, verbose); +      return num_matches; +    } +  } +  return 0; +} + +static size_t FindModulesByName(Target *target, const char *module_name, +                                ModuleList &module_list, +                                bool check_global_list) { +  FileSpec module_file_spec(module_name); +  ModuleSpec module_spec(module_file_spec); + +  const size_t initial_size = module_list.GetSize(); + +  if (check_global_list) { +    // Check the global list +    std::lock_guard<std::recursive_mutex> guard( +        Module::GetAllocationModuleCollectionMutex()); +    const size_t num_modules = Module::GetNumberAllocatedModules(); +    ModuleSP module_sp; +    for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { +      Module *module = Module::GetAllocatedModuleAtIndex(image_idx); + +      if (module) { +        if (module->MatchesModuleSpec(module_spec)) { +          module_sp = module->shared_from_this(); +          module_list.AppendIfNeeded(module_sp); +        } +      } +    } +  } else { +    if (target) { +      target->GetImages().FindModules(module_spec, module_list); +      const size_t num_matches = module_list.GetSize(); + +      // Not found in our module list for our target, check the main shared +      // module list in case it is a extra file used somewhere else +      if (num_matches == 0) { +        module_spec.GetArchitecture() = target->GetArchitecture(); +        ModuleList::FindSharedModules(module_spec, module_list); +      } +    } else { +      ModuleList::FindSharedModules(module_spec, module_list); +    } +  } + +  return module_list.GetSize() - initial_size; +} + +#pragma mark CommandObjectTargetModulesModuleAutoComplete + +// A base command object class that can auto complete with module file +// paths + +class CommandObjectTargetModulesModuleAutoComplete +    : public CommandObjectParsed { +public: +  CommandObjectTargetModulesModuleAutoComplete(CommandInterpreter &interpreter, +                                               const char *name, +                                               const char *help, +                                               const char *syntax, +                                               uint32_t flags = 0) +      : CommandObjectParsed(interpreter, name, help, syntax, flags) { +    CommandArgumentEntry arg; +    CommandArgumentData file_arg; + +    // Define the first (and only) variant of this arg. +    file_arg.arg_type = eArgTypeFilename; +    file_arg.arg_repetition = eArgRepeatStar; + +    // There is only one variant this argument could be; put it into the +    // argument entry. +    arg.push_back(file_arg); + +    // Push the data for the first argument into the m_arguments vector. +    m_arguments.push_back(arg); +  } + +  ~CommandObjectTargetModulesModuleAutoComplete() override = default; + +  void +  HandleArgumentCompletion(CompletionRequest &request, +                           OptionElementVector &opt_element_vector) override { +    CommandCompletions::InvokeCommonCompletionCallbacks( +        GetCommandInterpreter(), CommandCompletions::eModuleCompletion, request, +        nullptr); +  } +}; + +#pragma mark CommandObjectTargetModulesSourceFileAutoComplete + +// A base command object class that can auto complete with module source +// file paths + +class CommandObjectTargetModulesSourceFileAutoComplete +    : public CommandObjectParsed { +public: +  CommandObjectTargetModulesSourceFileAutoComplete( +      CommandInterpreter &interpreter, const char *name, const char *help, +      const char *syntax, uint32_t flags) +      : CommandObjectParsed(interpreter, name, help, syntax, flags) { +    CommandArgumentEntry arg; +    CommandArgumentData source_file_arg; + +    // Define the first (and only) variant of this arg. +    source_file_arg.arg_type = eArgTypeSourceFile; +    source_file_arg.arg_repetition = eArgRepeatPlus; + +    // There is only one variant this argument could be; put it into the +    // argument entry. +    arg.push_back(source_file_arg); + +    // Push the data for the first argument into the m_arguments vector. +    m_arguments.push_back(arg); +  } + +  ~CommandObjectTargetModulesSourceFileAutoComplete() override = default; + +  void +  HandleArgumentCompletion(CompletionRequest &request, +                           OptionElementVector &opt_element_vector) override { +    CommandCompletions::InvokeCommonCompletionCallbacks( +        GetCommandInterpreter(), CommandCompletions::eSourceFileCompletion, +        request, nullptr); +  } +}; + +#pragma mark CommandObjectTargetModulesDumpObjfile + +class CommandObjectTargetModulesDumpObjfile +    : public CommandObjectTargetModulesModuleAutoComplete { +public: +  CommandObjectTargetModulesDumpObjfile(CommandInterpreter &interpreter) +      : CommandObjectTargetModulesModuleAutoComplete( +            interpreter, "target modules dump objfile", +            "Dump the object file headers from one or more target modules.", +            nullptr, eCommandRequiresTarget) {} + +  ~CommandObjectTargetModulesDumpObjfile() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); + +    uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); +    result.GetOutputStream().SetAddressByteSize(addr_byte_size); +    result.GetErrorStream().SetAddressByteSize(addr_byte_size); + +    size_t num_dumped = 0; +    if (command.GetArgumentCount() == 0) { +      // Dump all headers for all modules images +      num_dumped = DumpModuleObjfileHeaders(result.GetOutputStream(), +                                            target->GetImages()); +      if (num_dumped == 0) { +        result.AppendError("the target has no associated executable images"); +        result.SetStatus(eReturnStatusFailed); +      } +    } else { +      // Find the modules that match the basename or full path. +      ModuleList module_list; +      const char *arg_cstr; +      for (int arg_idx = 0; +           (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != nullptr; +           ++arg_idx) { +        size_t num_matched = +            FindModulesByName(target, arg_cstr, module_list, true); +        if (num_matched == 0) { +          result.AppendWarningWithFormat( +              "Unable to find an image that matches '%s'.\n", arg_cstr); +        } +      } +      // Dump all the modules we found. +      num_dumped = +          DumpModuleObjfileHeaders(result.GetOutputStream(), module_list); +    } + +    if (num_dumped > 0) { +      result.SetStatus(eReturnStatusSuccessFinishResult); +    } else { +      result.AppendError("no matching executable images found"); +      result.SetStatus(eReturnStatusFailed); +    } +    return result.Succeeded(); +  } +}; + +#pragma mark CommandObjectTargetModulesDumpSymtab + +static constexpr OptionEnumValueElement g_sort_option_enumeration[] = { +    { +        eSortOrderNone, +        "none", +        "No sorting, use the original symbol table order.", +    }, +    { +        eSortOrderByAddress, +        "address", +        "Sort output by symbol address.", +    }, +    { +        eSortOrderByName, +        "name", +        "Sort output by symbol name.", +    }, +}; + +#define LLDB_OPTIONS_target_modules_dump_symtab +#include "CommandOptions.inc" + +class CommandObjectTargetModulesDumpSymtab +    : public CommandObjectTargetModulesModuleAutoComplete { +public: +  CommandObjectTargetModulesDumpSymtab(CommandInterpreter &interpreter) +      : CommandObjectTargetModulesModuleAutoComplete( +            interpreter, "target modules dump symtab", +            "Dump the symbol table from one or more target modules.", nullptr, +            eCommandRequiresTarget), +        m_options() {} + +  ~CommandObjectTargetModulesDumpSymtab() override = default; + +  Options *GetOptions() override { return &m_options; } + +  class CommandOptions : public Options { +  public: +    CommandOptions() : Options(), m_sort_order(eSortOrderNone) {} + +    ~CommandOptions() override = default; + +    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, +                          ExecutionContext *execution_context) override { +      Status error; +      const int short_option = m_getopt_table[option_idx].val; + +      switch (short_option) { +      case 's': +        m_sort_order = (SortOrder)OptionArgParser::ToOptionEnum( +            option_arg, GetDefinitions()[option_idx].enum_values, +            eSortOrderNone, error); +        break; + +      default: +        llvm_unreachable("Unimplemented option"); +      } +      return error; +    } + +    void OptionParsingStarting(ExecutionContext *execution_context) override { +      m_sort_order = eSortOrderNone; +    } + +    llvm::ArrayRef<OptionDefinition> GetDefinitions() override { +      return llvm::makeArrayRef(g_target_modules_dump_symtab_options); +    } + +    SortOrder m_sort_order; +  }; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    uint32_t num_dumped = 0; + +    uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); +    result.GetOutputStream().SetAddressByteSize(addr_byte_size); +    result.GetErrorStream().SetAddressByteSize(addr_byte_size); + +    if (command.GetArgumentCount() == 0) { +      // Dump all sections for all modules images +      std::lock_guard<std::recursive_mutex> guard( +          target->GetImages().GetMutex()); +      const size_t num_modules = target->GetImages().GetSize(); +      if (num_modules > 0) { +        result.GetOutputStream().Printf("Dumping symbol table for %" PRIu64 +                                        " modules.\n", +                                        (uint64_t)num_modules); +        for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { +          if (num_dumped > 0) { +            result.GetOutputStream().EOL(); +            result.GetOutputStream().EOL(); +          } +          if (m_interpreter.WasInterrupted()) +            break; +          num_dumped++; +          DumpModuleSymtab( +              m_interpreter, result.GetOutputStream(), +              target->GetImages().GetModulePointerAtIndexUnlocked(image_idx), +              m_options.m_sort_order); +        } +      } else { +        result.AppendError("the target has no associated executable images"); +        result.SetStatus(eReturnStatusFailed); +        return false; +      } +    } else { +      // Dump specified images (by basename or fullpath) +      const char *arg_cstr; +      for (int arg_idx = 0; +           (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != nullptr; +           ++arg_idx) { +        ModuleList module_list; +        const size_t num_matches = +            FindModulesByName(target, arg_cstr, module_list, true); +        if (num_matches > 0) { +          for (size_t i = 0; i < num_matches; ++i) { +            Module *module = module_list.GetModulePointerAtIndex(i); +            if (module) { +              if (num_dumped > 0) { +                result.GetOutputStream().EOL(); +                result.GetOutputStream().EOL(); +              } +              if (m_interpreter.WasInterrupted()) +                break; +              num_dumped++; +              DumpModuleSymtab(m_interpreter, result.GetOutputStream(), module, +                               m_options.m_sort_order); +            } +          } +        } else +          result.AppendWarningWithFormat( +              "Unable to find an image that matches '%s'.\n", arg_cstr); +      } +    } + +    if (num_dumped > 0) +      result.SetStatus(eReturnStatusSuccessFinishResult); +    else { +      result.AppendError("no matching executable images found"); +      result.SetStatus(eReturnStatusFailed); +    } +    return result.Succeeded(); +  } + +  CommandOptions m_options; +}; + +#pragma mark CommandObjectTargetModulesDumpSections + +// Image section dumping command + +class CommandObjectTargetModulesDumpSections +    : public CommandObjectTargetModulesModuleAutoComplete { +public: +  CommandObjectTargetModulesDumpSections(CommandInterpreter &interpreter) +      : CommandObjectTargetModulesModuleAutoComplete( +            interpreter, "target modules dump sections", +            "Dump the sections from one or more target modules.", +            //"target modules dump sections [<file1> ...]") +            nullptr, eCommandRequiresTarget) {} + +  ~CommandObjectTargetModulesDumpSections() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    uint32_t num_dumped = 0; + +    uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); +    result.GetOutputStream().SetAddressByteSize(addr_byte_size); +    result.GetErrorStream().SetAddressByteSize(addr_byte_size); + +    if (command.GetArgumentCount() == 0) { +      // Dump all sections for all modules images +      const size_t num_modules = target->GetImages().GetSize(); +      if (num_modules > 0) { +        result.GetOutputStream().Printf("Dumping sections for %" PRIu64 +                                        " modules.\n", +                                        (uint64_t)num_modules); +        for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { +          if (m_interpreter.WasInterrupted()) +            break; +          num_dumped++; +          DumpModuleSections( +              m_interpreter, result.GetOutputStream(), +              target->GetImages().GetModulePointerAtIndex(image_idx)); +        } +      } else { +        result.AppendError("the target has no associated executable images"); +        result.SetStatus(eReturnStatusFailed); +        return false; +      } +    } else { +      // Dump specified images (by basename or fullpath) +      const char *arg_cstr; +      for (int arg_idx = 0; +           (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != nullptr; +           ++arg_idx) { +        ModuleList module_list; +        const size_t num_matches = +            FindModulesByName(target, arg_cstr, module_list, true); +        if (num_matches > 0) { +          for (size_t i = 0; i < num_matches; ++i) { +            if (m_interpreter.WasInterrupted()) +              break; +            Module *module = module_list.GetModulePointerAtIndex(i); +            if (module) { +              num_dumped++; +              DumpModuleSections(m_interpreter, result.GetOutputStream(), +                                 module); +            } +          } +        } else { +          // Check the global list +          std::lock_guard<std::recursive_mutex> guard( +              Module::GetAllocationModuleCollectionMutex()); + +          result.AppendWarningWithFormat( +              "Unable to find an image that matches '%s'.\n", arg_cstr); +        } +      } +    } + +    if (num_dumped > 0) +      result.SetStatus(eReturnStatusSuccessFinishResult); +    else { +      result.AppendError("no matching executable images found"); +      result.SetStatus(eReturnStatusFailed); +    } +    return result.Succeeded(); +  } +}; + +#pragma mark CommandObjectTargetModulesDumpSections + +// Clang AST dumping command + +class CommandObjectTargetModulesDumpClangAST +    : public CommandObjectTargetModulesModuleAutoComplete { +public: +  CommandObjectTargetModulesDumpClangAST(CommandInterpreter &interpreter) +      : CommandObjectTargetModulesModuleAutoComplete( +            interpreter, "target modules dump ast", +            "Dump the clang ast for a given module's symbol file.", +            //"target modules dump ast [<file1> ...]") +            nullptr, eCommandRequiresTarget) {} + +  ~CommandObjectTargetModulesDumpClangAST() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); + +    const size_t num_modules = target->GetImages().GetSize(); +    if (num_modules == 0) { +      result.AppendError("the target has no associated executable images"); +      result.SetStatus(eReturnStatusFailed); +      return false; +    } + +    if (command.GetArgumentCount() == 0) { +      // Dump all ASTs for all modules images +      result.GetOutputStream().Printf("Dumping clang ast for %" PRIu64 +                                      " modules.\n", +                                      (uint64_t)num_modules); +      for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { +        if (m_interpreter.WasInterrupted()) +          break; +        Module *m = target->GetImages().GetModulePointerAtIndex(image_idx); +        if (SymbolFile *sf = m->GetSymbolFile()) +          sf->DumpClangAST(result.GetOutputStream()); +      } +      result.SetStatus(eReturnStatusSuccessFinishResult); +      return true; +    } + +    // Dump specified ASTs (by basename or fullpath) +    for (const Args::ArgEntry &arg : command.entries()) { +      ModuleList module_list; +      const size_t num_matches = +          FindModulesByName(target, arg.c_str(), module_list, true); +      if (num_matches == 0) { +        // Check the global list +        std::lock_guard<std::recursive_mutex> guard( +            Module::GetAllocationModuleCollectionMutex()); + +        result.AppendWarningWithFormat( +            "Unable to find an image that matches '%s'.\n", arg.c_str()); +        continue; +      } + +      for (size_t i = 0; i < num_matches; ++i) { +        if (m_interpreter.WasInterrupted()) +          break; +        Module *m = module_list.GetModulePointerAtIndex(i); +        if (SymbolFile *sf = m->GetSymbolFile()) +          sf->DumpClangAST(result.GetOutputStream()); +      } +    } +    result.SetStatus(eReturnStatusSuccessFinishResult); +    return true; +  } +}; + +#pragma mark CommandObjectTargetModulesDumpSymfile + +// Image debug symbol dumping command + +class CommandObjectTargetModulesDumpSymfile +    : public CommandObjectTargetModulesModuleAutoComplete { +public: +  CommandObjectTargetModulesDumpSymfile(CommandInterpreter &interpreter) +      : CommandObjectTargetModulesModuleAutoComplete( +            interpreter, "target modules dump symfile", +            "Dump the debug symbol file for one or more target modules.", +            //"target modules dump symfile [<file1> ...]") +            nullptr, eCommandRequiresTarget) {} + +  ~CommandObjectTargetModulesDumpSymfile() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    uint32_t num_dumped = 0; + +    uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); +    result.GetOutputStream().SetAddressByteSize(addr_byte_size); +    result.GetErrorStream().SetAddressByteSize(addr_byte_size); + +    if (command.GetArgumentCount() == 0) { +      // Dump all sections for all modules images +      const ModuleList &target_modules = target->GetImages(); +      std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); +      const size_t num_modules = target_modules.GetSize(); +      if (num_modules > 0) { +        result.GetOutputStream().Printf("Dumping debug symbols for %" PRIu64 +                                        " modules.\n", +                                        (uint64_t)num_modules); +        for (uint32_t image_idx = 0; image_idx < num_modules; ++image_idx) { +          if (m_interpreter.WasInterrupted()) +            break; +          if (DumpModuleSymbolFile( +                  result.GetOutputStream(), +                  target_modules.GetModulePointerAtIndexUnlocked(image_idx))) +            num_dumped++; +        } +      } else { +        result.AppendError("the target has no associated executable images"); +        result.SetStatus(eReturnStatusFailed); +        return false; +      } +    } else { +      // Dump specified images (by basename or fullpath) +      const char *arg_cstr; +      for (int arg_idx = 0; +           (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != nullptr; +           ++arg_idx) { +        ModuleList module_list; +        const size_t num_matches = +            FindModulesByName(target, arg_cstr, module_list, true); +        if (num_matches > 0) { +          for (size_t i = 0; i < num_matches; ++i) { +            if (m_interpreter.WasInterrupted()) +              break; +            Module *module = module_list.GetModulePointerAtIndex(i); +            if (module) { +              if (DumpModuleSymbolFile(result.GetOutputStream(), module)) +                num_dumped++; +            } +          } +        } else +          result.AppendWarningWithFormat( +              "Unable to find an image that matches '%s'.\n", arg_cstr); +      } +    } + +    if (num_dumped > 0) +      result.SetStatus(eReturnStatusSuccessFinishResult); +    else { +      result.AppendError("no matching executable images found"); +      result.SetStatus(eReturnStatusFailed); +    } +    return result.Succeeded(); +  } +}; + +#pragma mark CommandObjectTargetModulesDumpLineTable +#define LLDB_OPTIONS_target_modules_dump +#include "CommandOptions.inc" + +// Image debug line table dumping command + +class CommandObjectTargetModulesDumpLineTable +    : public CommandObjectTargetModulesSourceFileAutoComplete { +public: +  CommandObjectTargetModulesDumpLineTable(CommandInterpreter &interpreter) +      : CommandObjectTargetModulesSourceFileAutoComplete( +            interpreter, "target modules dump line-table", +            "Dump the line table for one or more compilation units.", nullptr, +            eCommandRequiresTarget) {} + +  ~CommandObjectTargetModulesDumpLineTable() override = default; + +  Options *GetOptions() override { return &m_options; } + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = m_exe_ctx.GetTargetPtr(); +    uint32_t total_num_dumped = 0; + +    uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); +    result.GetOutputStream().SetAddressByteSize(addr_byte_size); +    result.GetErrorStream().SetAddressByteSize(addr_byte_size); + +    if (command.GetArgumentCount() == 0) { +      result.AppendError("file option must be specified."); +      result.SetStatus(eReturnStatusFailed); +      return result.Succeeded(); +    } else { +      // Dump specified images (by basename or fullpath) +      const char *arg_cstr; +      for (int arg_idx = 0; +           (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != nullptr; +           ++arg_idx) { +        FileSpec file_spec(arg_cstr); + +        const ModuleList &target_modules = target->GetImages(); +        std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); +        const size_t num_modules = target_modules.GetSize(); +        if (num_modules > 0) { +          uint32_t num_dumped = 0; +          for (uint32_t i = 0; i < num_modules; ++i) { +            if (m_interpreter.WasInterrupted()) +              break; +            if (DumpCompileUnitLineTable( +                    m_interpreter, result.GetOutputStream(), +                    target_modules.GetModulePointerAtIndexUnlocked(i), +                    file_spec, +                    m_options.m_verbose ? eDescriptionLevelFull +                                        : eDescriptionLevelBrief)) +              num_dumped++; +          } +          if (num_dumped == 0) +            result.AppendWarningWithFormat( +                "No source filenames matched '%s'.\n", arg_cstr); +          else +            total_num_dumped += num_dumped; +        } +      } +    } + +    if (total_num_dumped > 0) +      result.SetStatus(eReturnStatusSuccessFinishResult); +    else { +      result.AppendError("no source filenames matched any command arguments"); +      result.SetStatus(eReturnStatusFailed); +    } +    return result.Succeeded(); +  } + +  class CommandOptions : public Options { +  public: +    CommandOptions() : Options() { OptionParsingStarting(nullptr); } + +    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, +                          ExecutionContext *execution_context) override { +      assert(option_idx == 0 && "We only have one option."); +      m_verbose = true; + +      return Status(); +    } + +    void OptionParsingStarting(ExecutionContext *execution_context) override { +      m_verbose = false; +    } + +    llvm::ArrayRef<OptionDefinition> GetDefinitions() override { +      return llvm::makeArrayRef(g_target_modules_dump_options); +    } + +    bool m_verbose; +  }; + +  CommandOptions m_options; +}; + +#pragma mark CommandObjectTargetModulesDump + +// Dump multi-word command for target modules + +class CommandObjectTargetModulesDump : public CommandObjectMultiword { +public: +  // Constructors and Destructors +  CommandObjectTargetModulesDump(CommandInterpreter &interpreter) +      : CommandObjectMultiword( +            interpreter, "target modules dump", +            "Commands for dumping information about one or " +            "more target modules.", +            "target modules dump " +            "[headers|symtab|sections|ast|symfile|line-table] " +            "[<file1> <file2> ...]") { +    LoadSubCommand("objfile", +                   CommandObjectSP( +                       new CommandObjectTargetModulesDumpObjfile(interpreter))); +    LoadSubCommand( +        "symtab", +        CommandObjectSP(new CommandObjectTargetModulesDumpSymtab(interpreter))); +    LoadSubCommand("sections", +                   CommandObjectSP(new CommandObjectTargetModulesDumpSections( +                       interpreter))); +    LoadSubCommand("symfile", +                   CommandObjectSP( +                       new CommandObjectTargetModulesDumpSymfile(interpreter))); +    LoadSubCommand( +        "ast", CommandObjectSP( +                   new CommandObjectTargetModulesDumpClangAST(interpreter))); +    LoadSubCommand("line-table", +                   CommandObjectSP(new CommandObjectTargetModulesDumpLineTable( +                       interpreter))); +  } + +  ~CommandObjectTargetModulesDump() override = default; +}; + +class CommandObjectTargetModulesAdd : public CommandObjectParsed { +public: +  CommandObjectTargetModulesAdd(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "target modules add", +                            "Add a new module to the current target's modules.", +                            "target modules add [<module>]", +                            eCommandRequiresTarget), +        m_option_group(), m_symbol_file(LLDB_OPT_SET_1, false, "symfile", 's', +                                        0, eArgTypeFilename, +                                        "Fullpath to a stand alone debug " +                                        "symbols file for when debug symbols " +                                        "are not in the executable.") { +    m_option_group.Append(&m_uuid_option_group, LLDB_OPT_SET_ALL, +                          LLDB_OPT_SET_1); +    m_option_group.Append(&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Finalize(); +  } + +  ~CommandObjectTargetModulesAdd() override = default; + +  Options *GetOptions() override { return &m_option_group; } + +  void +  HandleArgumentCompletion(CompletionRequest &request, +                           OptionElementVector &opt_element_vector) override { +    CommandCompletions::InvokeCommonCompletionCallbacks( +        GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, +        request, nullptr); +  } + +protected: +  OptionGroupOptions m_option_group; +  OptionGroupUUID m_uuid_option_group; +  OptionGroupFile m_symbol_file; + +  bool DoExecute(Args &args, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    bool flush = false; + +    const size_t argc = args.GetArgumentCount(); +    if (argc == 0) { +      if (m_uuid_option_group.GetOptionValue().OptionWasSet()) { +        // We are given a UUID only, go locate the file +        ModuleSpec module_spec; +        module_spec.GetUUID() = +            m_uuid_option_group.GetOptionValue().GetCurrentValue(); +        if (m_symbol_file.GetOptionValue().OptionWasSet()) +          module_spec.GetSymbolFileSpec() = +              m_symbol_file.GetOptionValue().GetCurrentValue(); +        if (Symbols::DownloadObjectAndSymbolFile(module_spec)) { +          ModuleSP module_sp( +              target->GetOrCreateModule(module_spec, true /* notify */)); +          if (module_sp) { +            result.SetStatus(eReturnStatusSuccessFinishResult); +            return true; +          } else { +            StreamString strm; +            module_spec.GetUUID().Dump(&strm); +            if (module_spec.GetFileSpec()) { +              if (module_spec.GetSymbolFileSpec()) { +                result.AppendErrorWithFormat( +                    "Unable to create the executable or symbol file with " +                    "UUID %s with path %s and symbol file %s", +                    strm.GetData(), module_spec.GetFileSpec().GetPath().c_str(), +                    module_spec.GetSymbolFileSpec().GetPath().c_str()); +              } else { +                result.AppendErrorWithFormat( +                    "Unable to create the executable or symbol file with " +                    "UUID %s with path %s", +                    strm.GetData(), +                    module_spec.GetFileSpec().GetPath().c_str()); +              } +            } else { +              result.AppendErrorWithFormat("Unable to create the executable " +                                           "or symbol file with UUID %s", +                                           strm.GetData()); +            } +            result.SetStatus(eReturnStatusFailed); +            return false; +          } +        } else { +          StreamString strm; +          module_spec.GetUUID().Dump(&strm); +          result.AppendErrorWithFormat( +              "Unable to locate the executable or symbol file with UUID %s", +              strm.GetData()); +          result.SetStatus(eReturnStatusFailed); +          return false; +        } +      } else { +        result.AppendError( +            "one or more executable image paths must be specified"); +        result.SetStatus(eReturnStatusFailed); +        return false; +      } +    } else { +      for (auto &entry : args.entries()) { +        if (entry.ref().empty()) +          continue; + +        FileSpec file_spec(entry.ref()); +        if (FileSystem::Instance().Exists(file_spec)) { +          ModuleSpec module_spec(file_spec); +          if (m_uuid_option_group.GetOptionValue().OptionWasSet()) +            module_spec.GetUUID() = +                m_uuid_option_group.GetOptionValue().GetCurrentValue(); +          if (m_symbol_file.GetOptionValue().OptionWasSet()) +            module_spec.GetSymbolFileSpec() = +                m_symbol_file.GetOptionValue().GetCurrentValue(); +          if (!module_spec.GetArchitecture().IsValid()) +            module_spec.GetArchitecture() = target->GetArchitecture(); +          Status error; +          ModuleSP module_sp(target->GetOrCreateModule( +              module_spec, true /* notify */, &error)); +          if (!module_sp) { +            const char *error_cstr = error.AsCString(); +            if (error_cstr) +              result.AppendError(error_cstr); +            else +              result.AppendErrorWithFormat("unsupported module: %s", +                                           entry.c_str()); +            result.SetStatus(eReturnStatusFailed); +            return false; +          } else { +            flush = true; +          } +          result.SetStatus(eReturnStatusSuccessFinishResult); +        } else { +          std::string resolved_path = file_spec.GetPath(); +          result.SetStatus(eReturnStatusFailed); +          if (resolved_path != entry.ref()) { +            result.AppendErrorWithFormat( +                "invalid module path '%s' with resolved path '%s'\n", +                entry.ref().str().c_str(), resolved_path.c_str()); +            break; +          } +          result.AppendErrorWithFormat("invalid module path '%s'\n", +                                       entry.c_str()); +          break; +        } +      } +    } + +    if (flush) { +      ProcessSP process = target->GetProcessSP(); +      if (process) +        process->Flush(); +    } + +    return result.Succeeded(); +  } +}; + +class CommandObjectTargetModulesLoad +    : public CommandObjectTargetModulesModuleAutoComplete { +public: +  CommandObjectTargetModulesLoad(CommandInterpreter &interpreter) +      : CommandObjectTargetModulesModuleAutoComplete( +            interpreter, "target modules load", +            "Set the load addresses for one or more sections in a target " +            "module.", +            "target modules load [--file <module> --uuid <uuid>] <sect-name> " +            "<address> [<sect-name> <address> ....]", +            eCommandRequiresTarget), +        m_option_group(), +        m_file_option(LLDB_OPT_SET_1, false, "file", 'f', 0, eArgTypeName, +                      "Fullpath or basename for module to load.", ""), +        m_load_option(LLDB_OPT_SET_1, false, "load", 'l', +                      "Write file contents to the memory.", false, true), +        m_pc_option(LLDB_OPT_SET_1, false, "set-pc-to-entry", 'p', +                    "Set PC to the entry point." +                    " Only applicable with '--load' option.", +                    false, true), +        m_slide_option(LLDB_OPT_SET_1, false, "slide", 's', 0, eArgTypeOffset, +                       "Set the load address for all sections to be the " +                       "virtual address in the file plus the offset.", +                       0) { +    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_load_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Append(&m_pc_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Append(&m_slide_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +    m_option_group.Finalize(); +  } + +  ~CommandObjectTargetModulesLoad() override = default; + +  Options *GetOptions() override { return &m_option_group; } + +protected: +  bool DoExecute(Args &args, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    const bool load = m_load_option.GetOptionValue().GetCurrentValue(); +    const bool set_pc = m_pc_option.GetOptionValue().GetCurrentValue(); + +    const size_t argc = args.GetArgumentCount(); +    ModuleSpec module_spec; +    bool search_using_module_spec = false; + +    // Allow "load" option to work without --file or --uuid option. +    if (load) { +      if (!m_file_option.GetOptionValue().OptionWasSet() && +          !m_uuid_option_group.GetOptionValue().OptionWasSet()) { +        ModuleList &module_list = target->GetImages(); +        if (module_list.GetSize() == 1) { +          search_using_module_spec = true; +          module_spec.GetFileSpec() = +              module_list.GetModuleAtIndex(0)->GetFileSpec(); +        } +      } +    } + +    if (m_file_option.GetOptionValue().OptionWasSet()) { +      search_using_module_spec = true; +      const char *arg_cstr = m_file_option.GetOptionValue().GetCurrentValue(); +      const bool use_global_module_list = true; +      ModuleList module_list; +      const size_t num_matches = FindModulesByName( +          target, arg_cstr, module_list, use_global_module_list); +      if (num_matches == 1) { +        module_spec.GetFileSpec() = +            module_list.GetModuleAtIndex(0)->GetFileSpec(); +      } else if (num_matches > 1) { +        search_using_module_spec = false; +        result.AppendErrorWithFormat( +            "more than 1 module matched by name '%s'\n", arg_cstr); +        result.SetStatus(eReturnStatusFailed); +      } else { +        search_using_module_spec = false; +        result.AppendErrorWithFormat("no object file for module '%s'\n", +                                     arg_cstr); +        result.SetStatus(eReturnStatusFailed); +      } +    } + +    if (m_uuid_option_group.GetOptionValue().OptionWasSet()) { +      search_using_module_spec = true; +      module_spec.GetUUID() = +          m_uuid_option_group.GetOptionValue().GetCurrentValue(); +    } + +    if (search_using_module_spec) { +      ModuleList matching_modules; +      target->GetImages().FindModules(module_spec, matching_modules); +      const size_t num_matches = matching_modules.GetSize(); + +      char path[PATH_MAX]; +      if (num_matches == 1) { +        Module *module = matching_modules.GetModulePointerAtIndex(0); +        if (module) { +          ObjectFile *objfile = module->GetObjectFile(); +          if (objfile) { +            SectionList *section_list = module->GetSectionList(); +            if (section_list) { +              bool changed = false; +              if (argc == 0) { +                if (m_slide_option.GetOptionValue().OptionWasSet()) { +                  const addr_t slide = +                      m_slide_option.GetOptionValue().GetCurrentValue(); +                  const bool slide_is_offset = true; +                  module->SetLoadAddress(*target, slide, slide_is_offset, +                                         changed); +                } else { +                  result.AppendError("one or more section name + load " +                                     "address pair must be specified"); +                  result.SetStatus(eReturnStatusFailed); +                  return false; +                } +              } else { +                if (m_slide_option.GetOptionValue().OptionWasSet()) { +                  result.AppendError("The \"--slide <offset>\" option can't " +                                     "be used in conjunction with setting " +                                     "section load addresses.\n"); +                  result.SetStatus(eReturnStatusFailed); +                  return false; +                } + +                for (size_t i = 0; i < argc; i += 2) { +                  const char *sect_name = args.GetArgumentAtIndex(i); +                  const char *load_addr_cstr = args.GetArgumentAtIndex(i + 1); +                  if (sect_name && load_addr_cstr) { +                    ConstString const_sect_name(sect_name); +                    bool success = false; +                    addr_t load_addr = StringConvert::ToUInt64( +                        load_addr_cstr, LLDB_INVALID_ADDRESS, 0, &success); +                    if (success) { +                      SectionSP section_sp( +                          section_list->FindSectionByName(const_sect_name)); +                      if (section_sp) { +                        if (section_sp->IsThreadSpecific()) { +                          result.AppendErrorWithFormat( +                              "thread specific sections are not yet " +                              "supported (section '%s')\n", +                              sect_name); +                          result.SetStatus(eReturnStatusFailed); +                          break; +                        } else { +                          if (target->GetSectionLoadList() +                                  .SetSectionLoadAddress(section_sp, load_addr)) +                            changed = true; +                          result.AppendMessageWithFormat( +                              "section '%s' loaded at 0x%" PRIx64 "\n", +                              sect_name, load_addr); +                        } +                      } else { +                        result.AppendErrorWithFormat("no section found that " +                                                     "matches the section " +                                                     "name '%s'\n", +                                                     sect_name); +                        result.SetStatus(eReturnStatusFailed); +                        break; +                      } +                    } else { +                      result.AppendErrorWithFormat( +                          "invalid load address string '%s'\n", load_addr_cstr); +                      result.SetStatus(eReturnStatusFailed); +                      break; +                    } +                  } else { +                    if (sect_name) +                      result.AppendError("section names must be followed by " +                                         "a load address.\n"); +                    else +                      result.AppendError("one or more section name + load " +                                         "address pair must be specified.\n"); +                    result.SetStatus(eReturnStatusFailed); +                    break; +                  } +                } +              } + +              if (changed) { +                target->ModulesDidLoad(matching_modules); +                Process *process = m_exe_ctx.GetProcessPtr(); +                if (process) +                  process->Flush(); +              } +              if (load) { +                ProcessSP process = target->CalculateProcess(); +                Address file_entry = objfile->GetEntryPointAddress(); +                if (!process) { +                  result.AppendError("No process"); +                  return false; +                } +                if (set_pc && !file_entry.IsValid()) { +                  result.AppendError("No entry address in object file"); +                  return false; +                } +                std::vector<ObjectFile::LoadableData> loadables( +                    objfile->GetLoadableData(*target)); +                if (loadables.size() == 0) { +                  result.AppendError("No loadable sections"); +                  return false; +                } +                Status error = process->WriteObjectFile(std::move(loadables)); +                if (error.Fail()) { +                  result.AppendError(error.AsCString()); +                  return false; +                } +                if (set_pc) { +                  ThreadList &thread_list = process->GetThreadList(); +                  RegisterContextSP reg_context( +                      thread_list.GetSelectedThread()->GetRegisterContext()); +                  addr_t file_entry_addr = file_entry.GetLoadAddress(target); +                  if (!reg_context->SetPC(file_entry_addr)) { +                    result.AppendErrorWithFormat("failed to set PC value to " +                                                 "0x%" PRIx64 "\n", +                                                 file_entry_addr); +                    result.SetStatus(eReturnStatusFailed); +                  } +                } +              } +            } else { +              module->GetFileSpec().GetPath(path, sizeof(path)); +              result.AppendErrorWithFormat("no sections in object file '%s'\n", +                                           path); +              result.SetStatus(eReturnStatusFailed); +            } +          } else { +            module->GetFileSpec().GetPath(path, sizeof(path)); +            result.AppendErrorWithFormat("no object file for module '%s'\n", +                                         path); +            result.SetStatus(eReturnStatusFailed); +          } +        } else { +          FileSpec *module_spec_file = module_spec.GetFileSpecPtr(); +          if (module_spec_file) { +            module_spec_file->GetPath(path, sizeof(path)); +            result.AppendErrorWithFormat("invalid module '%s'.\n", path); +          } else +            result.AppendError("no module spec"); +          result.SetStatus(eReturnStatusFailed); +        } +      } else { +        std::string uuid_str; + +        if (module_spec.GetFileSpec()) +          module_spec.GetFileSpec().GetPath(path, sizeof(path)); +        else +          path[0] = '\0'; + +        if (module_spec.GetUUIDPtr()) +          uuid_str = module_spec.GetUUID().GetAsString(); +        if (num_matches > 1) { +          result.AppendErrorWithFormat( +              "multiple modules match%s%s%s%s:\n", path[0] ? " file=" : "", +              path, !uuid_str.empty() ? " uuid=" : "", uuid_str.c_str()); +          for (size_t i = 0; i < num_matches; ++i) { +            if (matching_modules.GetModulePointerAtIndex(i) +                    ->GetFileSpec() +                    .GetPath(path, sizeof(path))) +              result.AppendMessageWithFormat("%s\n", path); +          } +        } else { +          result.AppendErrorWithFormat( +              "no modules were found  that match%s%s%s%s.\n", +              path[0] ? " file=" : "", path, !uuid_str.empty() ? " uuid=" : "", +              uuid_str.c_str()); +        } +        result.SetStatus(eReturnStatusFailed); +      } +    } else { +      result.AppendError("either the \"--file <module>\" or the \"--uuid " +                         "<uuid>\" option must be specified.\n"); +      result.SetStatus(eReturnStatusFailed); +      return false; +    } +    return result.Succeeded(); +  } + +  OptionGroupOptions m_option_group; +  OptionGroupUUID m_uuid_option_group; +  OptionGroupString m_file_option; +  OptionGroupBoolean m_load_option; +  OptionGroupBoolean m_pc_option; +  OptionGroupUInt64 m_slide_option; +}; + +// List images with associated information +#define LLDB_OPTIONS_target_modules_list +#include "CommandOptions.inc" + +class CommandObjectTargetModulesList : public CommandObjectParsed { +public: +  class CommandOptions : public Options { +  public: +    CommandOptions() +        : Options(), m_format_array(), m_use_global_module_list(false), +          m_module_addr(LLDB_INVALID_ADDRESS) {} + +    ~CommandOptions() override = default; + +    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, +                          ExecutionContext *execution_context) override { +      Status error; + +      const int short_option = m_getopt_table[option_idx].val; +      if (short_option == 'g') { +        m_use_global_module_list = true; +      } else if (short_option == 'a') { +        m_module_addr = OptionArgParser::ToAddress( +            execution_context, option_arg, LLDB_INVALID_ADDRESS, &error); +      } else { +        unsigned long width = 0; +        option_arg.getAsInteger(0, width); +        m_format_array.push_back(std::make_pair(short_option, width)); +      } +      return error; +    } + +    void OptionParsingStarting(ExecutionContext *execution_context) override { +      m_format_array.clear(); +      m_use_global_module_list = false; +      m_module_addr = LLDB_INVALID_ADDRESS; +    } + +    llvm::ArrayRef<OptionDefinition> GetDefinitions() override { +      return llvm::makeArrayRef(g_target_modules_list_options); +    } + +    // Instance variables to hold the values for command options. +    typedef std::vector<std::pair<char, uint32_t>> FormatWidthCollection; +    FormatWidthCollection m_format_array; +    bool m_use_global_module_list; +    lldb::addr_t m_module_addr; +  }; + +  CommandObjectTargetModulesList(CommandInterpreter &interpreter) +      : CommandObjectParsed( +            interpreter, "target modules list", +            "List current executable and dependent shared library images.", +            "target modules list [<cmd-options>]"), +        m_options() {} + +  ~CommandObjectTargetModulesList() override = default; + +  Options *GetOptions() override { return &m_options; } + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = GetDebugger().GetSelectedTarget().get(); +    const bool use_global_module_list = m_options.m_use_global_module_list; +    // Define a local module list here to ensure it lives longer than any +    // "locker" object which might lock its contents below (through the +    // "module_list_ptr" variable). +    ModuleList module_list; +    if (target == nullptr && !use_global_module_list) { +      result.AppendError("invalid target, create a debug target using the " +                         "'target create' command"); +      result.SetStatus(eReturnStatusFailed); +      return false; +    } else { +      if (target) { +        uint32_t addr_byte_size = +            target->GetArchitecture().GetAddressByteSize(); +        result.GetOutputStream().SetAddressByteSize(addr_byte_size); +        result.GetErrorStream().SetAddressByteSize(addr_byte_size); +      } +      // Dump all sections for all modules images +      Stream &strm = result.GetOutputStream(); + +      if (m_options.m_module_addr != LLDB_INVALID_ADDRESS) { +        if (target) { +          Address module_address; +          if (module_address.SetLoadAddress(m_options.m_module_addr, target)) { +            ModuleSP module_sp(module_address.GetModule()); +            if (module_sp) { +              PrintModule(target, module_sp.get(), 0, strm); +              result.SetStatus(eReturnStatusSuccessFinishResult); +            } else { +              result.AppendErrorWithFormat( +                  "Couldn't find module matching address: 0x%" PRIx64 ".", +                  m_options.m_module_addr); +              result.SetStatus(eReturnStatusFailed); +            } +          } else { +            result.AppendErrorWithFormat( +                "Couldn't find module containing address: 0x%" PRIx64 ".", +                m_options.m_module_addr); +            result.SetStatus(eReturnStatusFailed); +          } +        } else { +          result.AppendError( +              "Can only look up modules by address with a valid target."); +          result.SetStatus(eReturnStatusFailed); +        } +        return result.Succeeded(); +      } + +      size_t num_modules = 0; + +      // This locker will be locked on the mutex in module_list_ptr if it is +      // non-nullptr. Otherwise it will lock the +      // AllocationModuleCollectionMutex when accessing the global module list +      // directly. +      std::unique_lock<std::recursive_mutex> guard( +          Module::GetAllocationModuleCollectionMutex(), std::defer_lock); + +      const ModuleList *module_list_ptr = nullptr; +      const size_t argc = command.GetArgumentCount(); +      if (argc == 0) { +        if (use_global_module_list) { +          guard.lock(); +          num_modules = Module::GetNumberAllocatedModules(); +        } else { +          module_list_ptr = &target->GetImages(); +        } +      } else { +        // TODO: Convert to entry based iteration.  Requires converting +        // FindModulesByName. +        for (size_t i = 0; i < argc; ++i) { +          // Dump specified images (by basename or fullpath) +          const char *arg_cstr = command.GetArgumentAtIndex(i); +          const size_t num_matches = FindModulesByName( +              target, arg_cstr, module_list, use_global_module_list); +          if (num_matches == 0) { +            if (argc == 1) { +              result.AppendErrorWithFormat("no modules found that match '%s'", +                                           arg_cstr); +              result.SetStatus(eReturnStatusFailed); +              return false; +            } +          } +        } + +        module_list_ptr = &module_list; +      } + +      std::unique_lock<std::recursive_mutex> lock; +      if (module_list_ptr != nullptr) { +        lock = +            std::unique_lock<std::recursive_mutex>(module_list_ptr->GetMutex()); + +        num_modules = module_list_ptr->GetSize(); +      } + +      if (num_modules > 0) { +        for (uint32_t image_idx = 0; image_idx < num_modules; ++image_idx) { +          ModuleSP module_sp; +          Module *module; +          if (module_list_ptr) { +            module_sp = module_list_ptr->GetModuleAtIndexUnlocked(image_idx); +            module = module_sp.get(); +          } else { +            module = Module::GetAllocatedModuleAtIndex(image_idx); +            module_sp = module->shared_from_this(); +          } + +          const size_t indent = strm.Printf("[%3u] ", image_idx); +          PrintModule(target, module, indent, strm); +        } +        result.SetStatus(eReturnStatusSuccessFinishResult); +      } else { +        if (argc) { +          if (use_global_module_list) +            result.AppendError( +                "the global module list has no matching modules"); +          else +            result.AppendError("the target has no matching modules"); +        } else { +          if (use_global_module_list) +            result.AppendError("the global module list is empty"); +          else +            result.AppendError( +                "the target has no associated executable images"); +        } +        result.SetStatus(eReturnStatusFailed); +        return false; +      } +    } +    return result.Succeeded(); +  } + +  void PrintModule(Target *target, Module *module, int indent, Stream &strm) { +    if (module == nullptr) { +      strm.PutCString("Null module"); +      return; +    } + +    bool dump_object_name = false; +    if (m_options.m_format_array.empty()) { +      m_options.m_format_array.push_back(std::make_pair('u', 0)); +      m_options.m_format_array.push_back(std::make_pair('h', 0)); +      m_options.m_format_array.push_back(std::make_pair('f', 0)); +      m_options.m_format_array.push_back(std::make_pair('S', 0)); +    } +    const size_t num_entries = m_options.m_format_array.size(); +    bool print_space = false; +    for (size_t i = 0; i < num_entries; ++i) { +      if (print_space) +        strm.PutChar(' '); +      print_space = true; +      const char format_char = m_options.m_format_array[i].first; +      uint32_t width = m_options.m_format_array[i].second; +      switch (format_char) { +      case 'A': +        DumpModuleArchitecture(strm, module, false, width); +        break; + +      case 't': +        DumpModuleArchitecture(strm, module, true, width); +        break; + +      case 'f': +        DumpFullpath(strm, &module->GetFileSpec(), width); +        dump_object_name = true; +        break; + +      case 'd': +        DumpDirectory(strm, &module->GetFileSpec(), width); +        break; + +      case 'b': +        DumpBasename(strm, &module->GetFileSpec(), width); +        dump_object_name = true; +        break; + +      case 'h': +      case 'o': +        // Image header address +        { +          uint32_t addr_nibble_width = +              target ? (target->GetArchitecture().GetAddressByteSize() * 2) +                     : 16; + +          ObjectFile *objfile = module->GetObjectFile(); +          if (objfile) { +            Address base_addr(objfile->GetBaseAddress()); +            if (base_addr.IsValid()) { +              if (target && !target->GetSectionLoadList().IsEmpty()) { +                lldb::addr_t load_addr = +                    base_addr.GetLoadAddress(target); +                if (load_addr == LLDB_INVALID_ADDRESS) { +                  base_addr.Dump(&strm, target, +                                   Address::DumpStyleModuleWithFileAddress, +                                   Address::DumpStyleFileAddress); +                } else { +                  if (format_char == 'o') { +                    // Show the offset of slide for the image +                    strm.Printf( +                        "0x%*.*" PRIx64, addr_nibble_width, addr_nibble_width, +                        load_addr - base_addr.GetFileAddress()); +                  } else { +                    // Show the load address of the image +                    strm.Printf("0x%*.*" PRIx64, addr_nibble_width, +                                addr_nibble_width, load_addr); +                  } +                } +                break; +              } +              // The address was valid, but the image isn't loaded, output the +              // address in an appropriate format +              base_addr.Dump(&strm, target, Address::DumpStyleFileAddress); +              break; +            } +          } +          strm.Printf("%*s", addr_nibble_width + 2, ""); +        } +        break; + +      case 'r': { +        size_t ref_count = 0; +        ModuleSP module_sp(module->shared_from_this()); +        if (module_sp) { +          // Take one away to make sure we don't count our local "module_sp" +          ref_count = module_sp.use_count() - 1; +        } +        if (width) +          strm.Printf("{%*" PRIu64 "}", width, (uint64_t)ref_count); +        else +          strm.Printf("{%" PRIu64 "}", (uint64_t)ref_count); +      } break; + +      case 's': +      case 'S': { +        if (const SymbolFile *symbol_file = module->GetSymbolFile()) { +          const FileSpec symfile_spec = +              symbol_file->GetObjectFile()->GetFileSpec(); +          if (format_char == 'S') { +            // Dump symbol file only if different from module file +            if (!symfile_spec || symfile_spec == module->GetFileSpec()) { +              print_space = false; +              break; +            } +            // Add a newline and indent past the index +            strm.Printf("\n%*s", indent, ""); +          } +          DumpFullpath(strm, &symfile_spec, width); +          dump_object_name = true; +          break; +        } +        strm.Printf("%.*s", width, "<NONE>"); +      } break; + +      case 'm': +        strm.Format("{0:%c}", llvm::fmt_align(module->GetModificationTime(), +                                              llvm::AlignStyle::Left, width)); +        break; + +      case 'p': +        strm.Printf("%p", static_cast<void *>(module)); +        break; + +      case 'u': +        DumpModuleUUID(strm, module); +        break; + +      default: +        break; +      } +    } +    if (dump_object_name) { +      const char *object_name = module->GetObjectName().GetCString(); +      if (object_name) +        strm.Printf("(%s)", object_name); +    } +    strm.EOL(); +  } + +  CommandOptions m_options; +}; + +#pragma mark CommandObjectTargetModulesShowUnwind + +// Lookup unwind information in images +#define LLDB_OPTIONS_target_modules_show_unwind +#include "CommandOptions.inc" + +class CommandObjectTargetModulesShowUnwind : public CommandObjectParsed { +public: +  enum { +    eLookupTypeInvalid = -1, +    eLookupTypeAddress = 0, +    eLookupTypeSymbol, +    eLookupTypeFunction, +    eLookupTypeFunctionOrSymbol, +    kNumLookupTypes +  }; + +  class CommandOptions : public Options { +  public: +    CommandOptions() +        : Options(), m_type(eLookupTypeInvalid), m_str(), +          m_addr(LLDB_INVALID_ADDRESS) {} + +    ~CommandOptions() override = default; + +    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, +                          ExecutionContext *execution_context) override { +      Status error; + +      const int short_option = m_getopt_table[option_idx].val; + +      switch (short_option) { +      case 'a': { +        m_str = option_arg; +        m_type = eLookupTypeAddress; +        m_addr = OptionArgParser::ToAddress(execution_context, option_arg, +                                            LLDB_INVALID_ADDRESS, &error); +        if (m_addr == LLDB_INVALID_ADDRESS) +          error.SetErrorStringWithFormat("invalid address string '%s'", +                                         option_arg.str().c_str()); +        break; +      } + +      case 'n': +        m_str = option_arg; +        m_type = eLookupTypeFunctionOrSymbol; +        break; + +      default: +        llvm_unreachable("Unimplemented option"); +      } + +      return error; +    } + +    void OptionParsingStarting(ExecutionContext *execution_context) override { +      m_type = eLookupTypeInvalid; +      m_str.clear(); +      m_addr = LLDB_INVALID_ADDRESS; +    } + +    llvm::ArrayRef<OptionDefinition> GetDefinitions() override { +      return llvm::makeArrayRef(g_target_modules_show_unwind_options); +    } + +    // Instance variables to hold the values for command options. + +    int m_type;        // Should be a eLookupTypeXXX enum after parsing options +    std::string m_str; // Holds name lookup +    lldb::addr_t m_addr; // Holds the address to lookup +  }; + +  CommandObjectTargetModulesShowUnwind(CommandInterpreter &interpreter) +      : CommandObjectParsed( +            interpreter, "target modules show-unwind", +            "Show synthesized unwind instructions for a function.", nullptr, +            eCommandRequiresTarget | eCommandRequiresProcess | +                eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), +        m_options() {} + +  ~CommandObjectTargetModulesShowUnwind() override = default; + +  Options *GetOptions() override { return &m_options; } + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = m_exe_ctx.GetTargetPtr(); +    Process *process = m_exe_ctx.GetProcessPtr(); +    ABI *abi = nullptr; +    if (process) +      abi = process->GetABI().get(); + +    if (process == nullptr) { +      result.AppendError( +          "You must have a process running to use this command."); +      result.SetStatus(eReturnStatusFailed); +      return false; +    } + +    ThreadList threads(process->GetThreadList()); +    if (threads.GetSize() == 0) { +      result.AppendError("The process must be paused to use this command."); +      result.SetStatus(eReturnStatusFailed); +      return false; +    } + +    ThreadSP thread(threads.GetThreadAtIndex(0)); +    if (!thread) { +      result.AppendError("The process must be paused to use this command."); +      result.SetStatus(eReturnStatusFailed); +      return false; +    } + +    SymbolContextList sc_list; + +    if (m_options.m_type == eLookupTypeFunctionOrSymbol) { +      ConstString function_name(m_options.m_str.c_str()); +      target->GetImages().FindFunctions(function_name, eFunctionNameTypeAuto, +                                        true, false, sc_list); +    } else if (m_options.m_type == eLookupTypeAddress && target) { +      Address addr; +      if (target->GetSectionLoadList().ResolveLoadAddress(m_options.m_addr, +                                                          addr)) { +        SymbolContext sc; +        ModuleSP module_sp(addr.GetModule()); +        module_sp->ResolveSymbolContextForAddress(addr, +                                                  eSymbolContextEverything, sc); +        if (sc.function || sc.symbol) { +          sc_list.Append(sc); +        } +      } +    } else { +      result.AppendError( +          "address-expression or function name option must be specified."); +      result.SetStatus(eReturnStatusFailed); +      return false; +    } + +    size_t num_matches = sc_list.GetSize(); +    if (num_matches == 0) { +      result.AppendErrorWithFormat("no unwind data found that matches '%s'.", +                                   m_options.m_str.c_str()); +      result.SetStatus(eReturnStatusFailed); +      return false; +    } + +    for (uint32_t idx = 0; idx < num_matches; idx++) { +      SymbolContext sc; +      sc_list.GetContextAtIndex(idx, sc); +      if (sc.symbol == nullptr && sc.function == nullptr) +        continue; +      if (!sc.module_sp || sc.module_sp->GetObjectFile() == nullptr) +        continue; +      AddressRange range; +      if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, +                              false, range)) +        continue; +      if (!range.GetBaseAddress().IsValid()) +        continue; +      ConstString funcname(sc.GetFunctionName()); +      if (funcname.IsEmpty()) +        continue; +      addr_t start_addr = range.GetBaseAddress().GetLoadAddress(target); +      if (abi) +        start_addr = abi->FixCodeAddress(start_addr); + +      FuncUnwindersSP func_unwinders_sp( +          sc.module_sp->GetUnwindTable() +              .GetUncachedFuncUnwindersContainingAddress(start_addr, sc)); +      if (!func_unwinders_sp) +        continue; + +      result.GetOutputStream().Printf( +          "UNWIND PLANS for %s`%s (start addr 0x%" PRIx64 ")\n\n", +          sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), +          funcname.AsCString(), start_addr); + +      UnwindPlanSP non_callsite_unwind_plan = +          func_unwinders_sp->GetUnwindPlanAtNonCallSite(*target, *thread); +      if (non_callsite_unwind_plan) { +        result.GetOutputStream().Printf( +            "Asynchronous (not restricted to call-sites) UnwindPlan is '%s'\n", +            non_callsite_unwind_plan->GetSourceName().AsCString()); +      } +      UnwindPlanSP callsite_unwind_plan = +          func_unwinders_sp->GetUnwindPlanAtCallSite(*target, *thread); +      if (callsite_unwind_plan) { +        result.GetOutputStream().Printf( +            "Synchronous (restricted to call-sites) UnwindPlan is '%s'\n", +            callsite_unwind_plan->GetSourceName().AsCString()); +      } +      UnwindPlanSP fast_unwind_plan = +          func_unwinders_sp->GetUnwindPlanFastUnwind(*target, *thread); +      if (fast_unwind_plan) { +        result.GetOutputStream().Printf( +            "Fast UnwindPlan is '%s'\n", +            fast_unwind_plan->GetSourceName().AsCString()); +      } + +      result.GetOutputStream().Printf("\n"); + +      UnwindPlanSP assembly_sp = +          func_unwinders_sp->GetAssemblyUnwindPlan(*target, *thread); +      if (assembly_sp) { +        result.GetOutputStream().Printf( +            "Assembly language inspection UnwindPlan:\n"); +        assembly_sp->Dump(result.GetOutputStream(), thread.get(), +                          LLDB_INVALID_ADDRESS); +        result.GetOutputStream().Printf("\n"); +      } + +      UnwindPlanSP of_unwind_sp = +          func_unwinders_sp->GetObjectFileUnwindPlan(*target); +      if (of_unwind_sp) { +        result.GetOutputStream().Printf("object file UnwindPlan:\n"); +        of_unwind_sp->Dump(result.GetOutputStream(), thread.get(), +                           LLDB_INVALID_ADDRESS); +        result.GetOutputStream().Printf("\n"); +      } + +      UnwindPlanSP of_unwind_augmented_sp = +          func_unwinders_sp->GetObjectFileAugmentedUnwindPlan(*target, +                                                              *thread); +      if (of_unwind_augmented_sp) { +        result.GetOutputStream().Printf("object file augmented UnwindPlan:\n"); +        of_unwind_augmented_sp->Dump(result.GetOutputStream(), thread.get(), +                                     LLDB_INVALID_ADDRESS); +        result.GetOutputStream().Printf("\n"); +      } + +      UnwindPlanSP ehframe_sp = +          func_unwinders_sp->GetEHFrameUnwindPlan(*target); +      if (ehframe_sp) { +        result.GetOutputStream().Printf("eh_frame UnwindPlan:\n"); +        ehframe_sp->Dump(result.GetOutputStream(), thread.get(), +                         LLDB_INVALID_ADDRESS); +        result.GetOutputStream().Printf("\n"); +      } + +      UnwindPlanSP ehframe_augmented_sp = +          func_unwinders_sp->GetEHFrameAugmentedUnwindPlan(*target, *thread); +      if (ehframe_augmented_sp) { +        result.GetOutputStream().Printf("eh_frame augmented UnwindPlan:\n"); +        ehframe_augmented_sp->Dump(result.GetOutputStream(), thread.get(), +                                   LLDB_INVALID_ADDRESS); +        result.GetOutputStream().Printf("\n"); +      } + +      if (UnwindPlanSP plan_sp = +              func_unwinders_sp->GetDebugFrameUnwindPlan(*target)) { +        result.GetOutputStream().Printf("debug_frame UnwindPlan:\n"); +        plan_sp->Dump(result.GetOutputStream(), thread.get(), +                      LLDB_INVALID_ADDRESS); +        result.GetOutputStream().Printf("\n"); +      } + +      if (UnwindPlanSP plan_sp = +              func_unwinders_sp->GetDebugFrameAugmentedUnwindPlan(*target, +                                                                  *thread)) { +        result.GetOutputStream().Printf("debug_frame augmented UnwindPlan:\n"); +        plan_sp->Dump(result.GetOutputStream(), thread.get(), +                      LLDB_INVALID_ADDRESS); +        result.GetOutputStream().Printf("\n"); +      } + +      UnwindPlanSP arm_unwind_sp = +          func_unwinders_sp->GetArmUnwindUnwindPlan(*target); +      if (arm_unwind_sp) { +        result.GetOutputStream().Printf("ARM.exidx unwind UnwindPlan:\n"); +        arm_unwind_sp->Dump(result.GetOutputStream(), thread.get(), +                            LLDB_INVALID_ADDRESS); +        result.GetOutputStream().Printf("\n"); +      } + +      if (UnwindPlanSP symfile_plan_sp = +              func_unwinders_sp->GetSymbolFileUnwindPlan(*thread)) { +        result.GetOutputStream().Printf("Symbol file UnwindPlan:\n"); +        symfile_plan_sp->Dump(result.GetOutputStream(), thread.get(), +                              LLDB_INVALID_ADDRESS); +        result.GetOutputStream().Printf("\n"); +      } + +      UnwindPlanSP compact_unwind_sp = +          func_unwinders_sp->GetCompactUnwindUnwindPlan(*target); +      if (compact_unwind_sp) { +        result.GetOutputStream().Printf("Compact unwind UnwindPlan:\n"); +        compact_unwind_sp->Dump(result.GetOutputStream(), thread.get(), +                                LLDB_INVALID_ADDRESS); +        result.GetOutputStream().Printf("\n"); +      } + +      if (fast_unwind_plan) { +        result.GetOutputStream().Printf("Fast UnwindPlan:\n"); +        fast_unwind_plan->Dump(result.GetOutputStream(), thread.get(), +                               LLDB_INVALID_ADDRESS); +        result.GetOutputStream().Printf("\n"); +      } + +      ABISP abi_sp = process->GetABI(); +      if (abi_sp) { +        UnwindPlan arch_default(lldb::eRegisterKindGeneric); +        if (abi_sp->CreateDefaultUnwindPlan(arch_default)) { +          result.GetOutputStream().Printf("Arch default UnwindPlan:\n"); +          arch_default.Dump(result.GetOutputStream(), thread.get(), +                            LLDB_INVALID_ADDRESS); +          result.GetOutputStream().Printf("\n"); +        } + +        UnwindPlan arch_entry(lldb::eRegisterKindGeneric); +        if (abi_sp->CreateFunctionEntryUnwindPlan(arch_entry)) { +          result.GetOutputStream().Printf( +              "Arch default at entry point UnwindPlan:\n"); +          arch_entry.Dump(result.GetOutputStream(), thread.get(), +                          LLDB_INVALID_ADDRESS); +          result.GetOutputStream().Printf("\n"); +        } +      } + +      result.GetOutputStream().Printf("\n"); +    } +    return result.Succeeded(); +  } + +  CommandOptions m_options; +}; + +// Lookup information in images +#define LLDB_OPTIONS_target_modules_lookup +#include "CommandOptions.inc" + +class CommandObjectTargetModulesLookup : public CommandObjectParsed { +public: +  enum { +    eLookupTypeInvalid = -1, +    eLookupTypeAddress = 0, +    eLookupTypeSymbol, +    eLookupTypeFileLine, // Line is optional +    eLookupTypeFunction, +    eLookupTypeFunctionOrSymbol, +    eLookupTypeType, +    kNumLookupTypes +  }; + +  class CommandOptions : public Options { +  public: +    CommandOptions() : Options() { OptionParsingStarting(nullptr); } + +    ~CommandOptions() override = default; + +    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, +                          ExecutionContext *execution_context) override { +      Status error; + +      const int short_option = m_getopt_table[option_idx].val; + +      switch (short_option) { +      case 'a': { +        m_type = eLookupTypeAddress; +        m_addr = OptionArgParser::ToAddress(execution_context, option_arg, +                                            LLDB_INVALID_ADDRESS, &error); +      } break; + +      case 'o': +        if (option_arg.getAsInteger(0, m_offset)) +          error.SetErrorStringWithFormat("invalid offset string '%s'", +                                         option_arg.str().c_str()); +        break; + +      case 's': +        m_str = option_arg; +        m_type = eLookupTypeSymbol; +        break; + +      case 'f': +        m_file.SetFile(option_arg, FileSpec::Style::native); +        m_type = eLookupTypeFileLine; +        break; + +      case 'i': +        m_include_inlines = false; +        break; + +      case 'l': +        if (option_arg.getAsInteger(0, m_line_number)) +          error.SetErrorStringWithFormat("invalid line number string '%s'", +                                         option_arg.str().c_str()); +        else if (m_line_number == 0) +          error.SetErrorString("zero is an invalid line number"); +        m_type = eLookupTypeFileLine; +        break; + +      case 'F': +        m_str = option_arg; +        m_type = eLookupTypeFunction; +        break; + +      case 'n': +        m_str = option_arg; +        m_type = eLookupTypeFunctionOrSymbol; +        break; + +      case 't': +        m_str = option_arg; +        m_type = eLookupTypeType; +        break; + +      case 'v': +        m_verbose = true; +        break; + +      case 'A': +        m_print_all = true; +        break; + +      case 'r': +        m_use_regex = true; +        break; +      default: +        llvm_unreachable("Unimplemented option"); +      } + +      return error; +    } + +    void OptionParsingStarting(ExecutionContext *execution_context) override { +      m_type = eLookupTypeInvalid; +      m_str.clear(); +      m_file.Clear(); +      m_addr = LLDB_INVALID_ADDRESS; +      m_offset = 0; +      m_line_number = 0; +      m_use_regex = false; +      m_include_inlines = true; +      m_verbose = false; +      m_print_all = false; +    } + +    llvm::ArrayRef<OptionDefinition> GetDefinitions() override { +      return llvm::makeArrayRef(g_target_modules_lookup_options); +    } + +    int m_type;        // Should be a eLookupTypeXXX enum after parsing options +    std::string m_str; // Holds name lookup +    FileSpec m_file;   // Files for file lookups +    lldb::addr_t m_addr; // Holds the address to lookup +    lldb::addr_t +        m_offset; // Subtract this offset from m_addr before doing lookups. +    uint32_t m_line_number; // Line number for file+line lookups +    bool m_use_regex;       // Name lookups in m_str are regular expressions. +    bool m_include_inlines; // Check for inline entries when looking up by +                            // file/line. +    bool m_verbose;         // Enable verbose lookup info +    bool m_print_all; // Print all matches, even in cases where there's a best +                      // match. +  }; + +  CommandObjectTargetModulesLookup(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "target modules lookup", +                            "Look up information within executable and " +                            "dependent shared library images.", +                            nullptr, eCommandRequiresTarget), +        m_options() { +    CommandArgumentEntry arg; +    CommandArgumentData file_arg; + +    // Define the first (and only) variant of this arg. +    file_arg.arg_type = eArgTypeFilename; +    file_arg.arg_repetition = eArgRepeatStar; + +    // There is only one variant this argument could be; put it into the +    // argument entry. +    arg.push_back(file_arg); + +    // Push the data for the first argument into the m_arguments vector. +    m_arguments.push_back(arg); +  } + +  ~CommandObjectTargetModulesLookup() override = default; + +  Options *GetOptions() override { return &m_options; } + +  bool LookupHere(CommandInterpreter &interpreter, CommandReturnObject &result, +                  bool &syntax_error) { +    switch (m_options.m_type) { +    case eLookupTypeAddress: +    case eLookupTypeFileLine: +    case eLookupTypeFunction: +    case eLookupTypeFunctionOrSymbol: +    case eLookupTypeSymbol: +    default: +      return false; +    case eLookupTypeType: +      break; +    } + +    StackFrameSP frame = m_exe_ctx.GetFrameSP(); + +    if (!frame) +      return false; + +    const SymbolContext &sym_ctx(frame->GetSymbolContext(eSymbolContextModule)); + +    if (!sym_ctx.module_sp) +      return false; + +    switch (m_options.m_type) { +    default: +      return false; +    case eLookupTypeType: +      if (!m_options.m_str.empty()) { +        if (LookupTypeHere(m_interpreter, result.GetOutputStream(), +                           *sym_ctx.module_sp, m_options.m_str.c_str(), +                           m_options.m_use_regex)) { +          result.SetStatus(eReturnStatusSuccessFinishResult); +          return true; +        } +      } +      break; +    } + +    return true; +  } + +  bool LookupInModule(CommandInterpreter &interpreter, Module *module, +                      CommandReturnObject &result, bool &syntax_error) { +    switch (m_options.m_type) { +    case eLookupTypeAddress: +      if (m_options.m_addr != LLDB_INVALID_ADDRESS) { +        if (LookupAddressInModule( +                m_interpreter, result.GetOutputStream(), module, +                eSymbolContextEverything | +                    (m_options.m_verbose +                         ? static_cast<int>(eSymbolContextVariable) +                         : 0), +                m_options.m_addr, m_options.m_offset, m_options.m_verbose)) { +          result.SetStatus(eReturnStatusSuccessFinishResult); +          return true; +        } +      } +      break; + +    case eLookupTypeSymbol: +      if (!m_options.m_str.empty()) { +        if (LookupSymbolInModule(m_interpreter, result.GetOutputStream(), +                                 module, m_options.m_str.c_str(), +                                 m_options.m_use_regex, m_options.m_verbose)) { +          result.SetStatus(eReturnStatusSuccessFinishResult); +          return true; +        } +      } +      break; + +    case eLookupTypeFileLine: +      if (m_options.m_file) { +        if (LookupFileAndLineInModule( +                m_interpreter, result.GetOutputStream(), module, +                m_options.m_file, m_options.m_line_number, +                m_options.m_include_inlines, m_options.m_verbose)) { +          result.SetStatus(eReturnStatusSuccessFinishResult); +          return true; +        } +      } +      break; + +    case eLookupTypeFunctionOrSymbol: +    case eLookupTypeFunction: +      if (!m_options.m_str.empty()) { +        if (LookupFunctionInModule( +                m_interpreter, result.GetOutputStream(), module, +                m_options.m_str.c_str(), m_options.m_use_regex, +                m_options.m_include_inlines, +                m_options.m_type == +                    eLookupTypeFunctionOrSymbol, // include symbols +                m_options.m_verbose)) { +          result.SetStatus(eReturnStatusSuccessFinishResult); +          return true; +        } +      } +      break; + +    case eLookupTypeType: +      if (!m_options.m_str.empty()) { +        if (LookupTypeInModule(m_interpreter, result.GetOutputStream(), module, +                               m_options.m_str.c_str(), +                               m_options.m_use_regex)) { +          result.SetStatus(eReturnStatusSuccessFinishResult); +          return true; +        } +      } +      break; + +    default: +      m_options.GenerateOptionUsage( +          result.GetErrorStream(), this, +          GetCommandInterpreter().GetDebugger().GetTerminalWidth()); +      syntax_error = true; +      break; +    } + +    result.SetStatus(eReturnStatusFailed); +    return false; +  } + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target *target = &GetSelectedTarget(); +    bool syntax_error = false; +    uint32_t i; +    uint32_t num_successful_lookups = 0; +    uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); +    result.GetOutputStream().SetAddressByteSize(addr_byte_size); +    result.GetErrorStream().SetAddressByteSize(addr_byte_size); +    // Dump all sections for all modules images + +    if (command.GetArgumentCount() == 0) { +      ModuleSP current_module; + +      // Where it is possible to look in the current symbol context first, +      // try that.  If this search was successful and --all was not passed, +      // don't print anything else. +      if (LookupHere(m_interpreter, result, syntax_error)) { +        result.GetOutputStream().EOL(); +        num_successful_lookups++; +        if (!m_options.m_print_all) { +          result.SetStatus(eReturnStatusSuccessFinishResult); +          return result.Succeeded(); +        } +      } + +      // Dump all sections for all other modules + +      const ModuleList &target_modules = target->GetImages(); +      std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); +      const size_t num_modules = target_modules.GetSize(); +      if (num_modules > 0) { +        for (i = 0; i < num_modules && !syntax_error; ++i) { +          Module *module_pointer = +              target_modules.GetModulePointerAtIndexUnlocked(i); + +          if (module_pointer != current_module.get() && +              LookupInModule(m_interpreter, +                             target_modules.GetModulePointerAtIndexUnlocked(i), +                             result, syntax_error)) { +            result.GetOutputStream().EOL(); +            num_successful_lookups++; +          } +        } +      } else { +        result.AppendError("the target has no associated executable images"); +        result.SetStatus(eReturnStatusFailed); +        return false; +      } +    } else { +      // Dump specified images (by basename or fullpath) +      const char *arg_cstr; +      for (i = 0; (arg_cstr = command.GetArgumentAtIndex(i)) != nullptr && +                  !syntax_error; +           ++i) { +        ModuleList module_list; +        const size_t num_matches = +            FindModulesByName(target, arg_cstr, module_list, false); +        if (num_matches > 0) { +          for (size_t j = 0; j < num_matches; ++j) { +            Module *module = module_list.GetModulePointerAtIndex(j); +            if (module) { +              if (LookupInModule(m_interpreter, module, result, syntax_error)) { +                result.GetOutputStream().EOL(); +                num_successful_lookups++; +              } +            } +          } +        } else +          result.AppendWarningWithFormat( +              "Unable to find an image that matches '%s'.\n", arg_cstr); +      } +    } + +    if (num_successful_lookups > 0) +      result.SetStatus(eReturnStatusSuccessFinishResult); +    else +      result.SetStatus(eReturnStatusFailed); +    return result.Succeeded(); +  } + +  CommandOptions m_options; +}; + +#pragma mark CommandObjectMultiwordImageSearchPaths + +// CommandObjectMultiwordImageSearchPaths + +class CommandObjectTargetModulesImageSearchPaths +    : public CommandObjectMultiword { +public: +  CommandObjectTargetModulesImageSearchPaths(CommandInterpreter &interpreter) +      : CommandObjectMultiword( +            interpreter, "target modules search-paths", +            "Commands for managing module search paths for a target.", +            "target modules search-paths <subcommand> [<subcommand-options>]") { +    LoadSubCommand( +        "add", CommandObjectSP( +                   new CommandObjectTargetModulesSearchPathsAdd(interpreter))); +    LoadSubCommand( +        "clear", CommandObjectSP(new CommandObjectTargetModulesSearchPathsClear( +                     interpreter))); +    LoadSubCommand( +        "insert", +        CommandObjectSP( +            new CommandObjectTargetModulesSearchPathsInsert(interpreter))); +    LoadSubCommand( +        "list", CommandObjectSP(new CommandObjectTargetModulesSearchPathsList( +                    interpreter))); +    LoadSubCommand( +        "query", CommandObjectSP(new CommandObjectTargetModulesSearchPathsQuery( +                     interpreter))); +  } + +  ~CommandObjectTargetModulesImageSearchPaths() override = default; +}; + +#pragma mark CommandObjectTargetModules + +// CommandObjectTargetModules + +class CommandObjectTargetModules : public CommandObjectMultiword { +public: +  // Constructors and Destructors +  CommandObjectTargetModules(CommandInterpreter &interpreter) +      : CommandObjectMultiword(interpreter, "target modules", +                               "Commands for accessing information for one or " +                               "more target modules.", +                               "target modules <sub-command> ...") { +    LoadSubCommand( +        "add", CommandObjectSP(new CommandObjectTargetModulesAdd(interpreter))); +    LoadSubCommand("load", CommandObjectSP(new CommandObjectTargetModulesLoad( +                               interpreter))); +    LoadSubCommand("dump", CommandObjectSP(new CommandObjectTargetModulesDump( +                               interpreter))); +    LoadSubCommand("list", CommandObjectSP(new CommandObjectTargetModulesList( +                               interpreter))); +    LoadSubCommand( +        "lookup", +        CommandObjectSP(new CommandObjectTargetModulesLookup(interpreter))); +    LoadSubCommand( +        "search-paths", +        CommandObjectSP( +            new CommandObjectTargetModulesImageSearchPaths(interpreter))); +    LoadSubCommand( +        "show-unwind", +        CommandObjectSP(new CommandObjectTargetModulesShowUnwind(interpreter))); +  } + +  ~CommandObjectTargetModules() override = default; + +private: +  // For CommandObjectTargetModules only +  DISALLOW_COPY_AND_ASSIGN(CommandObjectTargetModules); +}; + +class CommandObjectTargetSymbolsAdd : public CommandObjectParsed { +public: +  CommandObjectTargetSymbolsAdd(CommandInterpreter &interpreter) +      : CommandObjectParsed( +            interpreter, "target symbols add", +            "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 <cmd-options> [<symfile>]", +            eCommandRequiresTarget), +        m_option_group(), +        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(); +  } + +  ~CommandObjectTargetSymbolsAdd() override = default; + +  void +  HandleArgumentCompletion(CompletionRequest &request, +                           OptionElementVector &opt_element_vector) override { +    CommandCompletions::InvokeCommonCompletionCallbacks( +        GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, +        request, nullptr); +  } + +  Options *GetOptions() override { return &m_option_group; } + +protected: +  bool AddModuleSymbols(Target *target, ModuleSpec &module_spec, bool &flush, +                        CommandReturnObject &result) { +    const FileSpec &symbol_fspec = module_spec.GetSymbolFileSpec(); +    if (symbol_fspec) { +      char symfile_path[PATH_MAX]; +      symbol_fspec.GetPath(symfile_path, sizeof(symfile_path)); + +      if (!module_spec.GetUUID().IsValid()) { +        if (!module_spec.GetFileSpec() && !module_spec.GetPlatformFileSpec()) +          module_spec.GetFileSpec().GetFilename() = symbol_fspec.GetFilename(); +      } +      // 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 +      ModuleList matching_module_list; + +      size_t num_matches = 0; +      // First extract all module specs from the symbol file +      lldb_private::ModuleSpecList symfile_module_specs; +      if (ObjectFile::GetModuleSpecifications(module_spec.GetSymbolFileSpec(), +                                              0, 0, symfile_module_specs)) { +        // Now extract the module spec that matches the target architecture +        ModuleSpec target_arch_module_spec; +        ModuleSpec symfile_module_spec; +        target_arch_module_spec.GetArchitecture() = target->GetArchitecture(); +        if (symfile_module_specs.FindMatchingModuleSpec(target_arch_module_spec, +                                                        symfile_module_spec)) { +          // See if it has a UUID? +          if (symfile_module_spec.GetUUID().IsValid()) { +            // It has a UUID, look for this UUID in the target modules +            ModuleSpec symfile_uuid_module_spec; +            symfile_uuid_module_spec.GetUUID() = symfile_module_spec.GetUUID(); +            target->GetImages().FindModules(symfile_uuid_module_spec, +                                            matching_module_list); +            num_matches = matching_module_list.GetSize(); +          } +        } + +        if (num_matches == 0) { +          // No matches yet, iterate through the module specs to find a UUID +          // value that we can match up to an image in our target +          const size_t num_symfile_module_specs = +              symfile_module_specs.GetSize(); +          for (size_t i = 0; i < num_symfile_module_specs && num_matches == 0; +               ++i) { +            if (symfile_module_specs.GetModuleSpecAtIndex( +                    i, symfile_module_spec)) { +              if (symfile_module_spec.GetUUID().IsValid()) { +                // It has a UUID, look for this UUID in the target modules +                ModuleSpec symfile_uuid_module_spec; +                symfile_uuid_module_spec.GetUUID() = +                    symfile_module_spec.GetUUID(); +                target->GetImages().FindModules(symfile_uuid_module_spec, +                                                matching_module_list); +                num_matches = matching_module_list.GetSize(); +              } +            } +          } +        } +      } + +      // Just try to match up the file by basename if we have no matches at +      // this point +      if (num_matches == 0) { +        target->GetImages().FindModules(module_spec, matching_module_list); +        num_matches = matching_module_list.GetSize(); +      } + +      while (num_matches == 0) { +        ConstString filename_no_extension( +            module_spec.GetFileSpec().GetFileNameStrippingExtension()); +        // Empty string returned, lets bail +        if (!filename_no_extension) +          break; + +        // Check if there was no extension to strip and the basename is the +        // same +        if (filename_no_extension == module_spec.GetFileSpec().GetFilename()) +          break; + +        // Replace basename with one less extension +        module_spec.GetFileSpec().GetFilename() = filename_no_extension; + +        target->GetImages().FindModules(module_spec, matching_module_list); +        num_matches = matching_module_list.GetSize(); +      } + +      if (num_matches > 1) { +        result.AppendErrorWithFormat("multiple modules match symbol file '%s', " +                                     "use the --uuid option to resolve the " +                                     "ambiguity.\n", +                                     symfile_path); +      } else if (num_matches == 1) { +        ModuleSP module_sp(matching_module_list.GetModuleAtIndex(0)); + +        // 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! +        module_sp->SetSymbolFileFileSpec(symbol_fspec); + +        SymbolFile *symbol_file = +            module_sp->GetSymbolFile(true, &result.GetErrorStream()); +        if (symbol_file) { +          ObjectFile *object_file = symbol_file->GetObjectFile(); + +          if (object_file && object_file->GetFileSpec() == symbol_fspec) { +            // Provide feedback that the symfile has been successfully added. +            const FileSpec &module_fs = module_sp->GetFileSpec(); +            result.AppendMessageWithFormat( +                "symbol file '%s' has been added to '%s'\n", symfile_path, +                module_fs.GetPath().c_str()); + +            // Let clients know something changed in the module if it is +            // currently loaded +            ModuleList module_list; +            module_list.Append(module_sp); +            target->SymbolsDidLoad(module_list); + +            // Make sure we load any scripting resources that may be embedded +            // in the debug info files in case the platform supports that. +            Status error; +            StreamString feedback_stream; +            module_sp->LoadScriptingResourceInTarget(target, error, +                                                     &feedback_stream); +            if (error.Fail() && error.AsCString()) +              result.AppendWarningWithFormat( +                  "unable to load scripting data for module %s - error " +                  "reported was %s", +                  module_sp->GetFileSpec() +                      .GetFileNameStrippingExtension() +                      .GetCString(), +                  error.AsCString()); +            else if (feedback_stream.GetSize()) +              result.AppendWarningWithFormat("%s", feedback_stream.GetData()); + +            flush = true; +            result.SetStatus(eReturnStatusSuccessFinishResult); +            return true; +          } +        } +        // Clear the symbol file spec if anything went wrong +        module_sp->SetSymbolFileFileSpec(FileSpec()); +      } + +      namespace fs = llvm::sys::fs; +      if (module_spec.GetUUID().IsValid()) { +        StreamString ss_symfile_uuid; +        module_spec.GetUUID().Dump(&ss_symfile_uuid); +        result.AppendErrorWithFormat( +            "symbol file '%s' (%s) does not match any existing module%s\n", +            symfile_path, ss_symfile_uuid.GetData(), +            !fs::is_regular_file(symbol_fspec.GetPath()) +                ? "\n       please specify the full path to the symbol file" +                : ""); +      } else { +        result.AppendErrorWithFormat( +            "symbol file '%s' does not match any existing module%s\n", +            symfile_path, +            !fs::is_regular_file(symbol_fspec.GetPath()) +                ? "\n       please specify the full path to the symbol file" +                : ""); +      } +    } else { +      result.AppendError( +          "one or more executable image paths must be specified"); +    } +    result.SetStatus(eReturnStatusFailed); +    return false; +  } + +  bool DoExecute(Args &args, CommandReturnObject &result) override { +    Target *target = m_exe_ctx.GetTargetPtr(); +    result.SetStatus(eReturnStatusFailed); +    bool flush = false; +    ModuleSpec module_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) { +      if (uuid_option_set || file_option_set || frame_option_set) { +        bool success = false; +        bool error_set = false; +        if (frame_option_set) { +          Process *process = m_exe_ctx.GetProcessPtr(); +          if (process) { +            const StateType process_state = process->GetState(); +            if (StateIsStoppedState(process_state, true)) { +              StackFrame *frame = m_exe_ctx.GetFramePtr(); +              if (frame) { +                ModuleSP frame_module_sp( +                    frame->GetSymbolContext(eSymbolContextModule).module_sp); +                if (frame_module_sp) { +                  if (FileSystem::Instance().Exists( +                          frame_module_sp->GetPlatformFileSpec())) { +                    module_spec.GetArchitecture() = +                        frame_module_sp->GetArchitecture(); +                    module_spec.GetFileSpec() = +                        frame_module_sp->GetPlatformFileSpec(); +                  } +                  module_spec.GetUUID() = frame_module_sp->GetUUID(); +                  success = module_spec.GetUUID().IsValid() || +                            module_spec.GetFileSpec(); +                } else { +                  result.AppendError("frame has no module"); +                  error_set = true; +                } +              } else { +                result.AppendError("invalid current frame"); +                error_set = true; +              } +            } else { +              result.AppendErrorWithFormat("process is not stopped: %s", +                                           StateAsCString(process_state)); +              error_set = true; +            } +          } else { +            result.AppendError( +                "a process must exist in order to use the --frame option"); +            error_set = true; +          } +        } else { +          if (uuid_option_set) { +            module_spec.GetUUID() = +                m_uuid_option_group.GetOptionValue().GetCurrentValue(); +            success |= module_spec.GetUUID().IsValid(); +          } else if (file_option_set) { +            module_spec.GetFileSpec() = +                m_file_option.GetOptionValue().GetCurrentValue(); +            ModuleSP module_sp( +                target->GetImages().FindFirstModule(module_spec)); +            if (module_sp) { +              module_spec.GetFileSpec() = module_sp->GetFileSpec(); +              module_spec.GetPlatformFileSpec() = +                  module_sp->GetPlatformFileSpec(); +              module_spec.GetUUID() = module_sp->GetUUID(); +              module_spec.GetArchitecture() = module_sp->GetArchitecture(); +            } else { +              module_spec.GetArchitecture() = target->GetArchitecture(); +            } +            success |= module_spec.GetUUID().IsValid() || +                       FileSystem::Instance().Exists(module_spec.GetFileSpec()); +          } +        } + +        if (success) { +          if (Symbols::DownloadObjectAndSymbolFile(module_spec)) { +            if (module_spec.GetSymbolFileSpec()) +              success = AddModuleSymbols(target, module_spec, flush, result); +          } +        } + +        if (!success && !error_set) { +          StreamString error_strm; +          if (uuid_option_set) { +            error_strm.PutCString("unable to find debug symbols for UUID "); +            module_spec.GetUUID().Dump(&error_strm); +          } else if (file_option_set) { +            error_strm.PutCString( +                "unable to find debug symbols for the executable file "); +            error_strm << module_spec.GetFileSpec(); +          } else if (frame_option_set) { +            error_strm.PutCString( +                "unable to find debug symbols for the current frame"); +          } +          result.AppendError(error_strm.GetString()); +        } +      } 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 (frame_option_set) { +        result.AppendError("specify either one or more paths to symbol files " +                           "or use the --frame option without arguments"); +      } else if (file_option_set && argc > 1) { +        result.AppendError("specify at most one symbol file path when " +                           "--shlib option is set"); +      } else { +        PlatformSP platform_sp(target->GetPlatform()); + +        for (auto &entry : args.entries()) { +          if (!entry.ref().empty()) { +            auto &symbol_file_spec = module_spec.GetSymbolFileSpec(); +            symbol_file_spec.SetFile(entry.ref(), FileSpec::Style::native); +            FileSystem::Instance().Resolve(symbol_file_spec); +            if (file_option_set) { +              module_spec.GetFileSpec() = +                  m_file_option.GetOptionValue().GetCurrentValue(); +            } +            if (platform_sp) { +              FileSpec symfile_spec; +              if (platform_sp +                      ->ResolveSymbolFile(*target, module_spec, symfile_spec) +                      .Success()) +                module_spec.GetSymbolFileSpec() = symfile_spec; +            } + +            ArchSpec arch; +            bool symfile_exists = +                FileSystem::Instance().Exists(module_spec.GetSymbolFileSpec()); + +            if (symfile_exists) { +              if (!AddModuleSymbols(target, module_spec, flush, result)) +                break; +            } else { +              std::string resolved_symfile_path = +                  module_spec.GetSymbolFileSpec().GetPath(); +              if (resolved_symfile_path != entry.ref()) { +                result.AppendErrorWithFormat( +                    "invalid module path '%s' with resolved path '%s'\n", +                    entry.c_str(), resolved_symfile_path.c_str()); +                break; +              } +              result.AppendErrorWithFormat("invalid module path '%s'\n", +                                           entry.c_str()); +              break; +            } +          } +        } +      } +    } + +    if (flush) { +      Process *process = m_exe_ctx.GetProcessPtr(); +      if (process) +        process->Flush(); +    } +    return result.Succeeded(); +  } + +  OptionGroupOptions m_option_group; +  OptionGroupUUID m_uuid_option_group; +  OptionGroupFile m_file_option; +  OptionGroupBoolean m_current_frame_option; +}; + +#pragma mark CommandObjectTargetSymbols + +// CommandObjectTargetSymbols + +class CommandObjectTargetSymbols : public CommandObjectMultiword { +public: +  // Constructors and Destructors +  CommandObjectTargetSymbols(CommandInterpreter &interpreter) +      : CommandObjectMultiword( +            interpreter, "target symbols", +            "Commands for adding and managing debug symbol files.", +            "target symbols <sub-command> ...") { +    LoadSubCommand( +        "add", CommandObjectSP(new CommandObjectTargetSymbolsAdd(interpreter))); +  } + +  ~CommandObjectTargetSymbols() override = default; + +private: +  // For CommandObjectTargetModules only +  DISALLOW_COPY_AND_ASSIGN(CommandObjectTargetSymbols); +}; + +#pragma mark CommandObjectTargetStopHookAdd + +// CommandObjectTargetStopHookAdd +#define LLDB_OPTIONS_target_stop_hook_add +#include "CommandOptions.inc" + +class CommandObjectTargetStopHookAdd : public CommandObjectParsed, +                                       public IOHandlerDelegateMultiline { +public: +  class CommandOptions : public Options { +  public: +    CommandOptions() +        : Options(), m_line_start(0), m_line_end(UINT_MAX), +          m_func_name_type_mask(eFunctionNameTypeAuto), +          m_sym_ctx_specified(false), m_thread_specified(false), +          m_use_one_liner(false), m_one_liner() {} + +    ~CommandOptions() override = default; + +    llvm::ArrayRef<OptionDefinition> GetDefinitions() override { +      return llvm::makeArrayRef(g_target_stop_hook_add_options); +    } + +    Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, +                          ExecutionContext *execution_context) override { +      Status error; +      const int short_option = m_getopt_table[option_idx].val; + +      switch (short_option) { +      case 'c': +        m_class_name = option_arg; +        m_sym_ctx_specified = true; +        break; + +      case 'e': +        if (option_arg.getAsInteger(0, m_line_end)) { +          error.SetErrorStringWithFormat("invalid end line number: \"%s\"", +                                         option_arg.str().c_str()); +          break; +        } +        m_sym_ctx_specified = true; +        break; + +      case 'G': { +        bool value, success; +        value = OptionArgParser::ToBoolean(option_arg, false, &success); +        if (success) { +          m_auto_continue = value; +        } else +          error.SetErrorStringWithFormat( +              "invalid boolean value '%s' passed for -G option", +              option_arg.str().c_str()); +      } +      break; +      case 'l': +        if (option_arg.getAsInteger(0, m_line_start)) { +          error.SetErrorStringWithFormat("invalid start line number: \"%s\"", +                                         option_arg.str().c_str()); +          break; +        } +        m_sym_ctx_specified = true; +        break; + +      case 'i': +        m_no_inlines = true; +        break; + +      case 'n': +        m_function_name = option_arg; +        m_func_name_type_mask |= eFunctionNameTypeAuto; +        m_sym_ctx_specified = true; +        break; + +      case 'f': +        m_file_name = option_arg; +        m_sym_ctx_specified = true; +        break; + +      case 's': +        m_module_name = option_arg; +        m_sym_ctx_specified = true; +        break; + +      case 't': +        if (option_arg.getAsInteger(0, m_thread_id)) +          error.SetErrorStringWithFormat("invalid thread id string '%s'", +                                         option_arg.str().c_str()); +        m_thread_specified = true; +        break; + +      case 'T': +        m_thread_name = option_arg; +        m_thread_specified = true; +        break; + +      case 'q': +        m_queue_name = option_arg; +        m_thread_specified = true; +        break; + +      case 'x': +        if (option_arg.getAsInteger(0, m_thread_index)) +          error.SetErrorStringWithFormat("invalid thread index string '%s'", +                                         option_arg.str().c_str()); +        m_thread_specified = true; +        break; + +      case 'o': +        m_use_one_liner = true; +        m_one_liner.push_back(option_arg); +        break; + +      default: +        llvm_unreachable("Unimplemented option"); +      } +      return error; +    } + +    void OptionParsingStarting(ExecutionContext *execution_context) override { +      m_class_name.clear(); +      m_function_name.clear(); +      m_line_start = 0; +      m_line_end = UINT_MAX; +      m_file_name.clear(); +      m_module_name.clear(); +      m_func_name_type_mask = eFunctionNameTypeAuto; +      m_thread_id = LLDB_INVALID_THREAD_ID; +      m_thread_index = UINT32_MAX; +      m_thread_name.clear(); +      m_queue_name.clear(); + +      m_no_inlines = false; +      m_sym_ctx_specified = false; +      m_thread_specified = false; + +      m_use_one_liner = false; +      m_one_liner.clear(); +      m_auto_continue = false; +    } + +    std::string m_class_name; +    std::string m_function_name; +    uint32_t m_line_start; +    uint32_t m_line_end; +    std::string m_file_name; +    std::string m_module_name; +    uint32_t m_func_name_type_mask; // A pick from lldb::FunctionNameType. +    lldb::tid_t m_thread_id; +    uint32_t m_thread_index; +    std::string m_thread_name; +    std::string m_queue_name; +    bool m_sym_ctx_specified; +    bool m_no_inlines; +    bool m_thread_specified; +    // Instance variables to hold the values for one_liner options. +    bool m_use_one_liner; +    std::vector<std::string> m_one_liner; +    bool m_auto_continue; +  }; + +  CommandObjectTargetStopHookAdd(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "target stop-hook add", +                            "Add a hook to be executed when the target stops.", +                            "target stop-hook add"), +        IOHandlerDelegateMultiline("DONE", +                                   IOHandlerDelegate::Completion::LLDBCommand), +        m_options() {} + +  ~CommandObjectTargetStopHookAdd() override = default; + +  Options *GetOptions() override { return &m_options; } + +protected: +  void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { +    StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); +    if (output_sp && interactive) { +      output_sp->PutCString( +          "Enter your stop hook command(s).  Type 'DONE' to end.\n"); +      output_sp->Flush(); +    } +  } + +  void IOHandlerInputComplete(IOHandler &io_handler, +                              std::string &line) override { +    if (m_stop_hook_sp) { +      if (line.empty()) { +        StreamFileSP error_sp(io_handler.GetErrorStreamFileSP()); +        if (error_sp) { +          error_sp->Printf("error: stop hook #%" PRIu64 +                           " aborted, no commands.\n", +                           m_stop_hook_sp->GetID()); +          error_sp->Flush(); +        } +        Target *target = GetDebugger().GetSelectedTarget().get(); +        if (target) +          target->RemoveStopHookByID(m_stop_hook_sp->GetID()); +      } else { +        m_stop_hook_sp->GetCommandPointer()->SplitIntoLines(line); +        StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); +        if (output_sp) { +          output_sp->Printf("Stop hook #%" PRIu64 " added.\n", +                            m_stop_hook_sp->GetID()); +          output_sp->Flush(); +        } +      } +      m_stop_hook_sp.reset(); +    } +    io_handler.SetIsDone(true); +  } + +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    m_stop_hook_sp.reset(); + +    Target &target = GetSelectedOrDummyTarget(); +    Target::StopHookSP new_hook_sp = target.CreateStopHook(); + +    //  First step, make the specifier. +    std::unique_ptr<SymbolContextSpecifier> specifier_up; +    if (m_options.m_sym_ctx_specified) { +      specifier_up.reset( +          new SymbolContextSpecifier(GetDebugger().GetSelectedTarget())); + +      if (!m_options.m_module_name.empty()) { +        specifier_up->AddSpecification( +            m_options.m_module_name.c_str(), +            SymbolContextSpecifier::eModuleSpecified); +      } + +      if (!m_options.m_class_name.empty()) { +        specifier_up->AddSpecification( +            m_options.m_class_name.c_str(), +            SymbolContextSpecifier::eClassOrNamespaceSpecified); +      } + +      if (!m_options.m_file_name.empty()) { +        specifier_up->AddSpecification(m_options.m_file_name.c_str(), +                                       SymbolContextSpecifier::eFileSpecified); +      } + +      if (m_options.m_line_start != 0) { +        specifier_up->AddLineSpecification( +            m_options.m_line_start, +            SymbolContextSpecifier::eLineStartSpecified); +      } + +      if (m_options.m_line_end != UINT_MAX) { +        specifier_up->AddLineSpecification( +            m_options.m_line_end, SymbolContextSpecifier::eLineEndSpecified); +      } + +      if (!m_options.m_function_name.empty()) { +        specifier_up->AddSpecification( +            m_options.m_function_name.c_str(), +            SymbolContextSpecifier::eFunctionSpecified); +      } +    } + +      if (specifier_up) +        new_hook_sp->SetSpecifier(specifier_up.release()); + +      // Next see if any of the thread options have been entered: + +      if (m_options.m_thread_specified) { +        ThreadSpec *thread_spec = new ThreadSpec(); + +        if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID) { +          thread_spec->SetTID(m_options.m_thread_id); +        } + +        if (m_options.m_thread_index != UINT32_MAX) +          thread_spec->SetIndex(m_options.m_thread_index); + +        if (!m_options.m_thread_name.empty()) +          thread_spec->SetName(m_options.m_thread_name.c_str()); + +        if (!m_options.m_queue_name.empty()) +          thread_spec->SetQueueName(m_options.m_queue_name.c_str()); + +        new_hook_sp->SetThreadSpecifier(thread_spec); +      } +       +      new_hook_sp->SetAutoContinue(m_options.m_auto_continue); +      if (m_options.m_use_one_liner) { +        // Use one-liners. +        for (auto cmd : m_options.m_one_liner) +          new_hook_sp->GetCommandPointer()->AppendString( +            cmd.c_str()); +        result.AppendMessageWithFormat("Stop hook #%" PRIu64 " added.\n", +                                       new_hook_sp->GetID()); +      } else { +        m_stop_hook_sp = new_hook_sp; +        m_interpreter.GetLLDBCommandsFromIOHandler( +            "> ",     // Prompt +            *this,    // IOHandlerDelegate +            true,     // Run IOHandler in async mode +            nullptr); // Baton for the "io_handler" that will be passed back +                      // into our IOHandlerDelegate functions +      } +      result.SetStatus(eReturnStatusSuccessFinishNoResult); + +    return result.Succeeded(); +  } + +private: +  CommandOptions m_options; +  Target::StopHookSP m_stop_hook_sp; +}; + +#pragma mark CommandObjectTargetStopHookDelete + +// CommandObjectTargetStopHookDelete + +class CommandObjectTargetStopHookDelete : public CommandObjectParsed { +public: +  CommandObjectTargetStopHookDelete(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "target stop-hook delete", +                            "Delete a stop-hook.", +                            "target stop-hook delete [<idx>]") {} + +  ~CommandObjectTargetStopHookDelete() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target &target = GetSelectedOrDummyTarget(); +    // FIXME: see if we can use the breakpoint id style parser? +    size_t num_args = command.GetArgumentCount(); +    if (num_args == 0) { +      if (!m_interpreter.Confirm("Delete all stop hooks?", true)) { +        result.SetStatus(eReturnStatusFailed); +        return false; +      } else { +        target.RemoveAllStopHooks(); +      } +    } else { +      bool success; +      for (size_t i = 0; i < num_args; i++) { +        lldb::user_id_t user_id = StringConvert::ToUInt32( +            command.GetArgumentAtIndex(i), 0, 0, &success); +        if (!success) { +          result.AppendErrorWithFormat("invalid stop hook id: \"%s\".\n", +                                       command.GetArgumentAtIndex(i)); +          result.SetStatus(eReturnStatusFailed); +          return false; +        } +        success = target.RemoveStopHookByID(user_id); +        if (!success) { +          result.AppendErrorWithFormat("unknown stop hook id: \"%s\".\n", +                                       command.GetArgumentAtIndex(i)); +          result.SetStatus(eReturnStatusFailed); +          return false; +        } +      } +    } +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +    return result.Succeeded(); +  } +}; + +#pragma mark CommandObjectTargetStopHookEnableDisable + +// CommandObjectTargetStopHookEnableDisable + +class CommandObjectTargetStopHookEnableDisable : public CommandObjectParsed { +public: +  CommandObjectTargetStopHookEnableDisable(CommandInterpreter &interpreter, +                                           bool enable, const char *name, +                                           const char *help, const char *syntax) +      : CommandObjectParsed(interpreter, name, help, syntax), m_enable(enable) { +  } + +  ~CommandObjectTargetStopHookEnableDisable() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target &target = GetSelectedOrDummyTarget(); +    // FIXME: see if we can use the breakpoint id style parser? +    size_t num_args = command.GetArgumentCount(); +    bool success; + +    if (num_args == 0) { +      target.SetAllStopHooksActiveState(m_enable); +    } else { +      for (size_t i = 0; i < num_args; i++) { +        lldb::user_id_t user_id = StringConvert::ToUInt32( +            command.GetArgumentAtIndex(i), 0, 0, &success); +        if (!success) { +          result.AppendErrorWithFormat("invalid stop hook id: \"%s\".\n", +                                       command.GetArgumentAtIndex(i)); +          result.SetStatus(eReturnStatusFailed); +          return false; +        } +        success = target.SetStopHookActiveStateByID(user_id, m_enable); +        if (!success) { +          result.AppendErrorWithFormat("unknown stop hook id: \"%s\".\n", +                                       command.GetArgumentAtIndex(i)); +          result.SetStatus(eReturnStatusFailed); +          return false; +        } +      } +    } +      result.SetStatus(eReturnStatusSuccessFinishNoResult); +    return result.Succeeded(); +  } + +private: +  bool m_enable; +}; + +#pragma mark CommandObjectTargetStopHookList + +// CommandObjectTargetStopHookList + +class CommandObjectTargetStopHookList : public CommandObjectParsed { +public: +  CommandObjectTargetStopHookList(CommandInterpreter &interpreter) +      : CommandObjectParsed(interpreter, "target stop-hook list", +                            "List all stop-hooks.", +                            "target stop-hook list [<type>]") {} + +  ~CommandObjectTargetStopHookList() override = default; + +protected: +  bool DoExecute(Args &command, CommandReturnObject &result) override { +    Target &target = GetSelectedOrDummyTarget(); + +    size_t num_hooks = target.GetNumStopHooks(); +    if (num_hooks == 0) { +      result.GetOutputStream().PutCString("No stop hooks.\n"); +    } else { +      for (size_t i = 0; i < num_hooks; i++) { +        Target::StopHookSP this_hook = target.GetStopHookAtIndex(i); +        if (i > 0) +          result.GetOutputStream().PutCString("\n"); +        this_hook->GetDescription(&(result.GetOutputStream()), +                                  eDescriptionLevelFull); +      } +    } +    result.SetStatus(eReturnStatusSuccessFinishResult); +    return result.Succeeded(); +  } +}; + +#pragma mark CommandObjectMultiwordTargetStopHooks + +// CommandObjectMultiwordTargetStopHooks + +class CommandObjectMultiwordTargetStopHooks : public CommandObjectMultiword { +public: +  CommandObjectMultiwordTargetStopHooks(CommandInterpreter &interpreter) +      : CommandObjectMultiword( +            interpreter, "target stop-hook", +            "Commands for operating on debugger target stop-hooks.", +            "target stop-hook <subcommand> [<subcommand-options>]") { +    LoadSubCommand("add", CommandObjectSP( +                              new CommandObjectTargetStopHookAdd(interpreter))); +    LoadSubCommand( +        "delete", +        CommandObjectSP(new CommandObjectTargetStopHookDelete(interpreter))); +    LoadSubCommand("disable", +                   CommandObjectSP(new CommandObjectTargetStopHookEnableDisable( +                       interpreter, false, "target stop-hook disable [<id>]", +                       "Disable a stop-hook.", "target stop-hook disable"))); +    LoadSubCommand("enable", +                   CommandObjectSP(new CommandObjectTargetStopHookEnableDisable( +                       interpreter, true, "target stop-hook enable [<id>]", +                       "Enable a stop-hook.", "target stop-hook enable"))); +    LoadSubCommand("list", CommandObjectSP(new CommandObjectTargetStopHookList( +                               interpreter))); +  } + +  ~CommandObjectMultiwordTargetStopHooks() override = default; +}; + +#pragma mark CommandObjectMultiwordTarget + +// CommandObjectMultiwordTarget + +CommandObjectMultiwordTarget::CommandObjectMultiwordTarget( +    CommandInterpreter &interpreter) +    : CommandObjectMultiword(interpreter, "target", +                             "Commands for operating on debugger targets.", +                             "target <subcommand> [<subcommand-options>]") { +  LoadSubCommand("create", +                 CommandObjectSP(new CommandObjectTargetCreate(interpreter))); +  LoadSubCommand("delete", +                 CommandObjectSP(new CommandObjectTargetDelete(interpreter))); +  LoadSubCommand("list", +                 CommandObjectSP(new CommandObjectTargetList(interpreter))); +  LoadSubCommand("select", +                 CommandObjectSP(new CommandObjectTargetSelect(interpreter))); +  LoadSubCommand( +      "stop-hook", +      CommandObjectSP(new CommandObjectMultiwordTargetStopHooks(interpreter))); +  LoadSubCommand("modules", +                 CommandObjectSP(new CommandObjectTargetModules(interpreter))); +  LoadSubCommand("symbols", +                 CommandObjectSP(new CommandObjectTargetSymbols(interpreter))); +  LoadSubCommand("variable", +                 CommandObjectSP(new CommandObjectTargetVariable(interpreter))); +} + +CommandObjectMultiwordTarget::~CommandObjectMultiwordTarget() = default;  | 
