|  | //===-- 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) { | 
|  | Target *target = static_cast<Target *>(baton); | 
|  | if (target) { | 
|  | return target->GetImages().FindGlobalVariables(ConstString(name), | 
|  | UINT32_MAX, variable_list); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | matches = target->GetImages().FindGlobalVariables(regex, UINT32_MAX, | 
|  | variable_list); | 
|  | } 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; | 
|  | const bool append = true; | 
|  | // 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), append, | 
|  | 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), append, 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; | 
|  | const bool append = true; | 
|  | size_t num_matches = 0; | 
|  | if (name_is_regex) { | 
|  | RegularExpression function_name_regex((llvm::StringRef(name))); | 
|  | num_matches = module->FindFunctions(function_name_regex, include_symbols, | 
|  | include_inlines, append, sc_list); | 
|  | } else { | 
|  | ConstString function_name(name); | 
|  | num_matches = module->FindFunctions( | 
|  | function_name, nullptr, eFunctionNameTypeAuto, include_symbols, | 
|  | include_inlines, append, sc_list); | 
|  | } | 
|  |  | 
|  | 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) { | 
|  | if (module && name_cstr && name_cstr[0]) { | 
|  | TypeList type_list; | 
|  | 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; | 
|  | num_matches = | 
|  | module->FindTypes(name, name_is_fully_qualified, max_num_matches, | 
|  | searched_symbol_files, type_list); | 
|  |  | 
|  | 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"); | 
|  | for (TypeSP type_sp : type_list.Types()) { | 
|  | 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 num_matches; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | size_t num_matches = 1; | 
|  | bool name_is_fully_qualified = false; | 
|  |  | 
|  | ConstString name(name_cstr); | 
|  | llvm::DenseSet<SymbolFile *> searched_symbol_files; | 
|  | num_matches = module.FindTypes(name, name_is_fully_qualified, max_num_matches, | 
|  | searched_symbol_files, type_list); | 
|  |  | 
|  | if (num_matches) { | 
|  | 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 num_matches; | 
|  | } | 
|  |  | 
|  | 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) { | 
|  | const size_t num_matches = | 
|  | target->GetImages().FindModules(module_spec, module_list); | 
|  |  | 
|  | // 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; | 
|  | const size_t num_matches = | 
|  | target->GetImages().FindModules(module_spec, matching_modules); | 
|  |  | 
|  | 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, true, 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 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(); | 
|  | num_matches = target->GetImages().FindModules( | 
|  | symfile_uuid_module_spec, matching_module_list); | 
|  | } | 
|  | } | 
|  |  | 
|  | 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(); | 
|  | num_matches = target->GetImages().FindModules( | 
|  | symfile_uuid_module_spec, matching_module_list); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Just try to match up the file by basename if we have no matches at | 
|  | // this point | 
|  | if (num_matches == 0) | 
|  | num_matches = | 
|  | target->GetImages().FindModules(module_spec, matching_module_list); | 
|  |  | 
|  | 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; | 
|  |  | 
|  | num_matches = | 
|  | target->GetImages().FindModules(module_spec, matching_module_list); | 
|  | } | 
|  |  | 
|  | 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.GetOutputStreamFile()); | 
|  | 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.GetErrorStreamFile()); | 
|  | 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.GetOutputStreamFile()); | 
|  | 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; |