diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Commands')
30 files changed, 3145 insertions, 919 deletions
diff --git a/contrib/llvm-project/lldb/source/Commands/CommandCompletions.cpp b/contrib/llvm-project/lldb/source/Commands/CommandCompletions.cpp index 48df77357201..0ea6d4288169 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandCompletions.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandCompletions.cpp @@ -9,16 +9,21 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSet.h" +#include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/FileSpecList.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" +#include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Host/FileSystem.h" #include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Variable.h" +#include "lldb/Target/Language.h" +#include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Thread.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/TildeExpressionResolver.h" @@ -52,6 +57,7 @@ bool CommandCompletions::InvokeCommonCompletionCallbacks( {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories}, {eSymbolCompletion, CommandCompletions::Symbols}, {eModuleCompletion, CommandCompletions::Modules}, + {eModuleUUIDCompletion, CommandCompletions::ModuleUUIDs}, {eSettingsNameCompletion, CommandCompletions::SettingsNames}, {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames}, {eArchitectureCompletion, CommandCompletions::ArchitectureNames}, @@ -59,6 +65,19 @@ bool CommandCompletions::InvokeCommonCompletionCallbacks( {eRegisterCompletion, CommandCompletions::Registers}, {eBreakpointCompletion, CommandCompletions::Breakpoints}, {eProcessPluginCompletion, CommandCompletions::ProcessPluginNames}, + {eDisassemblyFlavorCompletion, CommandCompletions::DisassemblyFlavors}, + {eTypeLanguageCompletion, CommandCompletions::TypeLanguages}, + {eFrameIndexCompletion, CommandCompletions::FrameIndexes}, + {eStopHookIDCompletion, CommandCompletions::StopHookIDs}, + {eThreadIndexCompletion, CommandCompletions::ThreadIndexes}, + {eWatchPointIDCompletion, CommandCompletions::WatchPointIDs}, + {eBreakpointNameCompletion, CommandCompletions::BreakpointNames}, + {eProcessIDCompletion, CommandCompletions::ProcessIDs}, + {eProcessNameCompletion, CommandCompletions::ProcessNames}, + {eRemoteDiskFileCompletion, CommandCompletions::RemoteDiskFiles}, + {eRemoteDiskDirectoryCompletion, + CommandCompletions::RemoteDiskDirectories}, + {eTypeCategoryNameCompletion, CommandCompletions::TypeCategoryNames}, {eNoCompletion, nullptr} // This one has to be last in the list. }; @@ -472,6 +491,24 @@ void CommandCompletions::DiskDirectories(const llvm::Twine &partial_file_name, DiskFilesOrDirectories(partial_file_name, true, matches, Resolver); } +void CommandCompletions::RemoteDiskFiles(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + lldb::PlatformSP platform_sp = + interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform(); + if (platform_sp) + platform_sp->AutoCompleteDiskFileOrDirectory(request, false); +} + +void CommandCompletions::RemoteDiskDirectories(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + lldb::PlatformSP platform_sp = + interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform(); + if (platform_sp) + platform_sp->AutoCompleteDiskFileOrDirectory(request, true); +} + void CommandCompletions::Modules(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher) { @@ -486,6 +523,24 @@ void CommandCompletions::Modules(CommandInterpreter &interpreter, } } +void CommandCompletions::ModuleUUIDs(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); + if (!exe_ctx.HasTargetScope()) + return; + + exe_ctx.GetTargetPtr()->GetImages().ForEach( + [&request](const lldb::ModuleSP &module) { + StreamString strm; + module->GetDescription(strm.AsRawOstream(), + lldb::eDescriptionLevelInitial); + request.TryCompleteCurrentArg(module->GetUUID().GetAsString(), + strm.GetString()); + return true; + }); +} + void CommandCompletions::Symbols(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher) { @@ -588,9 +643,154 @@ void CommandCompletions::Breakpoints(CommandInterpreter &interpreter, } } +void CommandCompletions::BreakpointNames(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + lldb::TargetSP target = interpreter.GetDebugger().GetSelectedTarget(); + if (!target) + return; + + std::vector<std::string> name_list; + target->GetBreakpointNames(name_list); + + for (const std::string &name : name_list) + request.TryCompleteCurrentArg(name); +} + void CommandCompletions::ProcessPluginNames(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher) { PluginManager::AutoCompleteProcessName(request.GetCursorArgumentPrefix(), request); -}
\ No newline at end of file +} +void CommandCompletions::DisassemblyFlavors(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + // Currently the only valid options for disassemble -F are default, and for + // Intel architectures, att and intel. + static const char *flavors[] = {"default", "att", "intel"}; + for (const char *flavor : flavors) { + request.TryCompleteCurrentArg(flavor); + } +} + +void CommandCompletions::ProcessIDs(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + lldb::PlatformSP platform_sp(interpreter.GetPlatform(true)); + if (!platform_sp) + return; + ProcessInstanceInfoList process_infos; + ProcessInstanceInfoMatch match_info; + platform_sp->FindProcesses(match_info, process_infos); + for (const ProcessInstanceInfo &info : process_infos) + request.TryCompleteCurrentArg(std::to_string(info.GetProcessID()), + info.GetNameAsStringRef()); +} + +void CommandCompletions::ProcessNames(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + lldb::PlatformSP platform_sp(interpreter.GetPlatform(true)); + if (!platform_sp) + return; + ProcessInstanceInfoList process_infos; + ProcessInstanceInfoMatch match_info; + platform_sp->FindProcesses(match_info, process_infos); + for (const ProcessInstanceInfo &info : process_infos) + request.TryCompleteCurrentArg(info.GetNameAsStringRef()); +} + +void CommandCompletions::TypeLanguages(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + for (int bit : + Language::GetLanguagesSupportingTypeSystems().bitvector.set_bits()) { + request.TryCompleteCurrentArg( + Language::GetNameForLanguageType(static_cast<lldb::LanguageType>(bit))); + } +} + +void CommandCompletions::FrameIndexes(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); + if (!exe_ctx.HasProcessScope()) + return; + + lldb::ThreadSP thread_sp = exe_ctx.GetThreadSP(); + const uint32_t frame_num = thread_sp->GetStackFrameCount(); + for (uint32_t i = 0; i < frame_num; ++i) { + lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i); + StreamString strm; + frame_sp->Dump(&strm, false, true); + request.TryCompleteCurrentArg(std::to_string(i), strm.GetString()); + } +} + +void CommandCompletions::StopHookIDs(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + const lldb::TargetSP target_sp = + interpreter.GetExecutionContext().GetTargetSP(); + if (!target_sp) + return; + + const size_t num = target_sp->GetNumStopHooks(); + for (size_t idx = 0; idx < num; ++idx) { + StreamString strm; + // The value 11 is an offset to make the completion description looks + // neater. + strm.SetIndentLevel(11); + const Target::StopHookSP stophook_sp = target_sp->GetStopHookAtIndex(idx); + stophook_sp->GetDescription(&strm, lldb::eDescriptionLevelInitial); + request.TryCompleteCurrentArg(std::to_string(stophook_sp->GetID()), + strm.GetString()); + } +} + +void CommandCompletions::ThreadIndexes(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); + if (!exe_ctx.HasProcessScope()) + return; + + ThreadList &threads = exe_ctx.GetProcessPtr()->GetThreadList(); + lldb::ThreadSP thread_sp; + for (uint32_t idx = 0; (thread_sp = threads.GetThreadAtIndex(idx)); ++idx) { + StreamString strm; + thread_sp->GetStatus(strm, 0, 1, 1, true); + request.TryCompleteCurrentArg(std::to_string(thread_sp->GetIndexID()), + strm.GetString()); + } +} + +void CommandCompletions::WatchPointIDs(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); + if (!exe_ctx.HasTargetScope()) + return; + + const WatchpointList &wp_list = exe_ctx.GetTargetPtr()->GetWatchpointList(); + const size_t wp_num = wp_list.GetSize(); + for (size_t idx = 0; idx < wp_num; ++idx) { + const lldb::WatchpointSP wp_sp = wp_list.GetByIndex(idx); + StreamString strm; + wp_sp->Dump(&strm); + request.TryCompleteCurrentArg(std::to_string(wp_sp->GetID()), + strm.GetString()); + } +} + +void CommandCompletions::TypeCategoryNames(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + DataVisualization::Categories::ForEach( + [&request](const lldb::TypeCategoryImplSP &category_sp) { + request.TryCompleteCurrentArg(category_sp->GetName(), + category_sp->GetDescription()); + return true; + }); +} diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpoint.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpoint.cpp index be7ef8a1b60b..0844c56cef2f 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -17,6 +17,7 @@ #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h" #include "lldb/Interpreter/OptionValueBoolean.h" +#include "lldb/Interpreter/OptionValueFileColonLine.h" #include "lldb/Interpreter/OptionValueString.h" #include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Interpreter/Options.h" @@ -443,7 +444,22 @@ public: case 'X': m_source_regex_func_names.insert(std::string(option_arg)); break; - + + case 'y': + { + OptionValueFileColonLine value; + Status fcl_err = value.SetValueFromString(option_arg); + if (!fcl_err.Success()) { + error.SetErrorStringWithFormat( + "Invalid value for file:line specifier: %s", + fcl_err.AsCString()); + } else { + m_filenames.AppendIfUnique(value.GetFileSpec()); + m_line_num = value.GetLineNumber(); + m_column = value.GetColumnNumber(); + } + } break; + default: llvm_unreachable("Unimplemented option"); } @@ -1407,7 +1423,8 @@ public: class CommandOptions : public Options { public: - CommandOptions() : Options(), m_use_dummy(false), m_force(false) {} + CommandOptions() : Options(), m_use_dummy(false), m_force(false), + m_delete_disabled(false) {} ~CommandOptions() override = default; @@ -1424,6 +1441,10 @@ public: case 'D': m_use_dummy = true; break; + + case 'd': + m_delete_disabled = true; + break; default: llvm_unreachable("Unimplemented option"); @@ -1435,6 +1456,7 @@ public: void OptionParsingStarting(ExecutionContext *execution_context) override { m_use_dummy = false; m_force = false; + m_delete_disabled = false; } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { @@ -1444,16 +1466,18 @@ public: // Instance variables to hold the values for command options. bool m_use_dummy; bool m_force; + bool m_delete_disabled; }; protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy); - + result.Clear(); + std::unique_lock<std::recursive_mutex> lock; target.GetBreakpointList().GetListMutex(lock); - const BreakpointList &breakpoints = target.GetBreakpointList(); + BreakpointList &breakpoints = target.GetBreakpointList(); size_t num_breakpoints = breakpoints.GetSize(); @@ -1463,7 +1487,7 @@ protected: return false; } - if (command.empty()) { + if (command.empty() && !m_options.m_delete_disabled) { if (!m_options.m_force && !m_interpreter.Confirm( "About to delete all breakpoints, do you want to do that?", @@ -1479,10 +1503,34 @@ protected: } else { // Particular breakpoint selected; disable that breakpoint. BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( - command, &target, result, &valid_bp_ids, - BreakpointName::Permissions::PermissionKinds::deletePerm); - + + if (m_options.m_delete_disabled) { + BreakpointIDList excluded_bp_ids; + + if (!command.empty()) { + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( + command, &target, result, &excluded_bp_ids, + BreakpointName::Permissions::PermissionKinds::deletePerm); + } + for (auto breakpoint_sp : breakpoints.Breakpoints()) { + if (!breakpoint_sp->IsEnabled() && breakpoint_sp->AllowDelete()) { + BreakpointID bp_id(breakpoint_sp->GetID()); + size_t pos = 0; + if (!excluded_bp_ids.FindBreakpointID(bp_id, &pos)) + valid_bp_ids.AddBreakpointID(breakpoint_sp->GetID()); + } + } + if (valid_bp_ids.GetSize() == 0) { + result.AppendError("No disabled breakpoints."); + result.SetStatus(eReturnStatusFailed); + return false; + } + } else { + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( + command, &target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::deletePerm); + } + if (result.Succeeded()) { int delete_count = 0; int disable_count = 0; @@ -2081,7 +2129,79 @@ public: return llvm::makeArrayRef(g_breakpoint_read_options); } - // Instance variables to hold the values for command options. + void HandleOptionArgumentCompletion( + CompletionRequest &request, OptionElementVector &opt_element_vector, + int opt_element_index, CommandInterpreter &interpreter) override { + int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos; + int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; + + switch (GetDefinitions()[opt_defs_index].short_option) { + case 'f': + CommandCompletions::InvokeCommonCompletionCallbacks( + interpreter, CommandCompletions::eDiskFileCompletion, request, + nullptr); + break; + + case 'N': + llvm::Optional<FileSpec> file_spec; + const llvm::StringRef dash_f("-f"); + for (int arg_idx = 0; arg_idx < opt_arg_pos; arg_idx++) { + if (dash_f == request.GetParsedLine().GetArgumentAtIndex(arg_idx)) { + file_spec.emplace( + request.GetParsedLine().GetArgumentAtIndex(arg_idx + 1)); + break; + } + } + if (!file_spec) + return; + + FileSystem::Instance().Resolve(*file_spec); + Status error; + StructuredData::ObjectSP input_data_sp = + StructuredData::ParseJSONFromFile(*file_spec, error); + if (!error.Success()) + return; + + StructuredData::Array *bkpt_array = input_data_sp->GetAsArray(); + if (!bkpt_array) + return; + + const size_t num_bkpts = bkpt_array->GetSize(); + for (size_t i = 0; i < num_bkpts; i++) { + StructuredData::ObjectSP bkpt_object_sp = + bkpt_array->GetItemAtIndex(i); + if (!bkpt_object_sp) + return; + + StructuredData::Dictionary *bkpt_dict = + bkpt_object_sp->GetAsDictionary(); + if (!bkpt_dict) + return; + + StructuredData::ObjectSP bkpt_data_sp = + bkpt_dict->GetValueForKey(Breakpoint::GetSerializationKey()); + if (!bkpt_data_sp) + return; + + bkpt_dict = bkpt_data_sp->GetAsDictionary(); + if (!bkpt_dict) + return; + + StructuredData::Array *names_array; + + if (!bkpt_dict->GetValueForKeyAsArray("Names", names_array)) + return; + + size_t num_names = names_array->GetSize(); + + for (size_t i = 0; i < num_names; i++) { + llvm::StringRef name; + if (names_array->GetItemAtIndexAsString(i, name)) + request.TryCompleteCurrentArg(name); + } + } + } + } std::string m_filename; std::vector<std::string> m_names; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index 45df86589011..caaf3bfb482f 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -141,12 +141,16 @@ Example Python one-line breakpoint command: (lldb) breakpoint command add -s python 1 Enter your Python command(s). Type 'DONE' to end. -> print "Hit this breakpoint!" -> DONE +def function (frame, bp_loc, internal_dict): + """frame: the lldb.SBFrame for the location at which you stopped + bp_loc: an lldb.SBBreakpointLocation for the breakpoint location information + internal_dict: an LLDB support object not to be used""" + print("Hit this breakpoint!") + DONE As a convenience, this also works for a short Python one-liner: -(lldb) breakpoint command add -s python 1 -o 'import time; print time.asctime()' +(lldb) breakpoint command add -s python 1 -o 'import time; print(time.asctime())' (lldb) run Launching '.../a.out' (x86_64) (lldb) Fri Sep 10 12:17:45 2010 @@ -164,21 +168,14 @@ Example multiple line Python breakpoint command: (lldb) breakpoint command add -s p 1 Enter your Python command(s). Type 'DONE' to end. -> global bp_count -> bp_count = bp_count + 1 -> print "Hit this breakpoint " + repr(bp_count) + " times!" -> DONE - -Example multiple line Python breakpoint command, using function definition: - -(lldb) breakpoint command add -s python 1 -Enter your Python command(s). Type 'DONE' to end. -> def breakpoint_output (bp_no): -> out_string = "Hit breakpoint number " + repr (bp_no) -> print out_string -> return True -> breakpoint_output (1) -> DONE +def function (frame, bp_loc, internal_dict): + """frame: the lldb.SBFrame for the location at which you stopped + bp_loc: an lldb.SBBreakpointLocation for the breakpoint location information + internal_dict: an LLDB support object not to be used""" + global bp_count + bp_count = bp_count + 1 + print("Hit this breakpoint " + repr(bp_count) + " times!") + DONE )" "In this case, since there is a reference to a global variable, \ @@ -417,22 +414,23 @@ protected: // to set or collect command callback. Otherwise, call the methods // associated with this object. if (m_options.m_use_script_language) { + Status error; ScriptInterpreter *script_interp = GetDebugger().GetScriptInterpreter( /*can_create=*/true, m_options.m_script_language); // Special handling for one-liner specified inline. if (m_options.m_use_one_liner) { - script_interp->SetBreakpointCommandCallback( + error = script_interp->SetBreakpointCommandCallback( m_bp_options_vec, m_options.m_one_liner.c_str()); } else if (!m_func_options.GetName().empty()) { - Status error = script_interp->SetBreakpointCommandCallbackFunction( + error = script_interp->SetBreakpointCommandCallbackFunction( m_bp_options_vec, m_func_options.GetName().c_str(), m_func_options.GetStructuredData()); - if (!error.Success()) - result.SetError(error); } else { script_interp->CollectDataForBreakpointCommandCallback( m_bp_options_vec, result); } + if (!error.Success()) + result.SetError(error); } else { // Special handling for one-liner specified inline. if (m_options.m_use_one_liner) diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp index d77e69c6f6a6..3b3cdde6ab9a 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp @@ -6,15 +6,13 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/StringRef.h" - #include "CommandObjectCommands.h" #include "CommandObjectHelp.h" +#include "CommandObjectRegexCommand.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/IOHandler.h" #include "lldb/Interpreter/CommandHistory.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/CommandObjectRegexCommand.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/OptionValueBoolean.h" @@ -24,161 +22,13 @@ #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/StringList.h" +#include "llvm/ADT/StringRef.h" using namespace lldb; using namespace lldb_private; // CommandObjectCommandsSource -#define LLDB_OPTIONS_history -#include "CommandOptions.inc" - -class CommandObjectCommandsHistory : public CommandObjectParsed { -public: - CommandObjectCommandsHistory(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "command history", - "Dump the history of commands in this session.\n" - "Commands in the history list can be run again " - "using \"!<INDEX>\". \"!-<OFFSET>\" will re-run " - "the command that is <OFFSET> commands from the end" - " of the list (counting the current command).", - nullptr), - m_options() {} - - ~CommandObjectCommandsHistory() override = default; - - Options *GetOptions() override { return &m_options; } - -protected: - class CommandOptions : public Options { - public: - CommandOptions() - : Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) { - } - - ~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 'c': - error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign); - break; - case 's': - if (option_arg == "end") { - m_start_idx.SetCurrentValue(UINT64_MAX); - m_start_idx.SetOptionWasSet(); - } else - error = m_start_idx.SetValueFromString(option_arg, - eVarSetOperationAssign); - break; - case 'e': - error = - m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign); - break; - case 'C': - m_clear.SetCurrentValue(true); - m_clear.SetOptionWasSet(); - break; - default: - llvm_unreachable("Unimplemented option"); - } - - return error; - } - - void OptionParsingStarting(ExecutionContext *execution_context) override { - m_start_idx.Clear(); - m_stop_idx.Clear(); - m_count.Clear(); - m_clear.Clear(); - } - - llvm::ArrayRef<OptionDefinition> GetDefinitions() override { - return llvm::makeArrayRef(g_history_options); - } - - // Instance variables to hold the values for command options. - - OptionValueUInt64 m_start_idx; - OptionValueUInt64 m_stop_idx; - OptionValueUInt64 m_count; - OptionValueBoolean m_clear; - }; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - if (m_options.m_clear.GetCurrentValue() && - m_options.m_clear.OptionWasSet()) { - m_interpreter.GetCommandHistory().Clear(); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - } else { - if (m_options.m_start_idx.OptionWasSet() && - m_options.m_stop_idx.OptionWasSet() && - m_options.m_count.OptionWasSet()) { - result.AppendError("--count, --start-index and --end-index cannot be " - "all specified in the same invocation"); - result.SetStatus(lldb::eReturnStatusFailed); - } else { - std::pair<bool, uint64_t> start_idx( - m_options.m_start_idx.OptionWasSet(), - m_options.m_start_idx.GetCurrentValue()); - std::pair<bool, uint64_t> stop_idx( - m_options.m_stop_idx.OptionWasSet(), - m_options.m_stop_idx.GetCurrentValue()); - std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(), - m_options.m_count.GetCurrentValue()); - - const CommandHistory &history(m_interpreter.GetCommandHistory()); - - if (start_idx.first && start_idx.second == UINT64_MAX) { - if (count.first) { - start_idx.second = history.GetSize() - count.second; - stop_idx.second = history.GetSize() - 1; - } else if (stop_idx.first) { - start_idx.second = stop_idx.second; - stop_idx.second = history.GetSize() - 1; - } else { - start_idx.second = 0; - stop_idx.second = history.GetSize() - 1; - } - } else { - if (!start_idx.first && !stop_idx.first && !count.first) { - start_idx.second = 0; - stop_idx.second = history.GetSize() - 1; - } else if (start_idx.first) { - if (count.first) { - stop_idx.second = start_idx.second + count.second - 1; - } else if (!stop_idx.first) { - stop_idx.second = history.GetSize() - 1; - } - } else if (stop_idx.first) { - if (count.first) { - if (stop_idx.second >= count.second) - start_idx.second = stop_idx.second - count.second + 1; - else - start_idx.second = 0; - } - } else /* if (count.first) */ - { - start_idx.second = 0; - stop_idx.second = count.second - 1; - } - } - history.Dump(result.GetOutputStream(), start_idx.second, - stop_idx.second); - } - } - return result.Succeeded(); - } - - CommandOptions m_options; -}; - -// CommandObjectCommandsSource - #define LLDB_OPTIONS_source #include "CommandOptions.inc" @@ -614,7 +464,7 @@ protected: OptionArgVectorSP(new OptionArgVector); if (CommandObjectSP cmd_obj_sp = - m_interpreter.GetCommandSPExact(cmd_obj.GetCommandName(), false)) { + m_interpreter.GetCommandSPExact(cmd_obj.GetCommandName())) { if (m_interpreter.AliasExists(alias_command) || m_interpreter.UserCommandExists(alias_command)) { result.AppendWarningWithFormat( @@ -708,10 +558,9 @@ protected: if (!args.empty()) { CommandObjectSP tmp_sp = - m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName(), false); + m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName()); if (use_subcommand) - tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName(), - false); + tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName()); args.GetCommandString(args_string); } @@ -767,6 +616,17 @@ public: ~CommandObjectCommandsUnalias() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) + return; + + for (const auto &ent : m_interpreter.GetAliases()) { + request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); + } + } + protected: bool DoExecute(Args &args, CommandReturnObject &result) override { CommandObject::CommandMap::iterator pos; @@ -848,6 +708,18 @@ public: ~CommandObjectCommandsDelete() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) + return; + + for (const auto &ent : m_interpreter.GetCommands()) { + if (ent.second->IsRemovable()) + request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); + } + } + protected: bool DoExecute(Args &args, CommandReturnObject &result) override { CommandObject::CommandMap::iterator pos; @@ -1119,7 +991,7 @@ protected: std::string subst(std::string(regex_sed.substr( second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1))); - m_regex_cmd_up->AddRegexCommand(regex.c_str(), subst.c_str()); + m_regex_cmd_up->AddRegexCommand(regex, subst); } return error; } @@ -1399,6 +1271,9 @@ protected: case 'r': // NO-OP break; + case 'c': + relative_to_command_file = true; + break; default: llvm_unreachable("Unimplemented option"); } @@ -1407,11 +1282,13 @@ protected: } void OptionParsingStarting(ExecutionContext *execution_context) override { + relative_to_command_file = false; } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { return llvm::makeArrayRef(g_script_import_options); } + bool relative_to_command_file = false; }; bool DoExecute(Args &command, CommandReturnObject &result) override { @@ -1421,6 +1298,17 @@ protected: return false; } + FileSpec source_dir = {}; + if (m_options.relative_to_command_file) { + source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); + if (!source_dir) { + result.AppendError("command script import -c can only be specified " + "from a command file"); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + for (auto &entry : command.entries()) { Status error; @@ -1435,7 +1323,7 @@ protected: // more) m_exe_ctx.Clear(); if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( - entry.c_str(), init_session, error)) { + entry.c_str(), init_session, error, nullptr, source_dir)) { result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendErrorWithFormat("module importing failed: %s", @@ -1850,8 +1738,6 @@ CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); LoadSubCommand( "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); - LoadSubCommand("history", CommandObjectSP( - new CommandObjectCommandsHistory(interpreter))); LoadSubCommand( "script", CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp index b23adb087b49..58eaa3f973cb 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp @@ -304,11 +304,8 @@ void CommandObjectExpression::HandleCompletion(CompletionRequest &request) { return; ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); - - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) - target = &GetDummyTarget(); + Target *exe_target = exe_ctx.GetTargetPtr(); + Target &target = exe_target ? *exe_target : GetDummyTarget(); unsigned cursor_pos = request.GetRawCursorPos(); // Get the full user input including the suffix. The suffix is necessary @@ -342,7 +339,7 @@ void CommandObjectExpression::HandleCompletion(CompletionRequest &request) { auto language = exe_ctx.GetFrameRef().GetLanguage(); Status error; - lldb::UserExpressionSP expr(target->GetUserExpressionForLanguage( + lldb::UserExpressionSP expr(target.GetUserExpressionForLanguage( code, llvm::StringRef(), language, UserExpression::eResultTypeAny, options, nullptr, error)); if (error.Fail()) @@ -411,22 +408,19 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, // command object DoExecute has finished when doing multi-line expression // that use an input reader... ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); - - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) - target = &GetDummyTarget(); + Target *exe_target = exe_ctx.GetTargetPtr(); + Target &target = exe_target ? *exe_target : GetDummyTarget(); lldb::ValueObjectSP result_valobj_sp; StackFrame *frame = exe_ctx.GetFramePtr(); - const EvaluateExpressionOptions options = GetEvalOptions(*target); - ExpressionResults success = target->EvaluateExpression( + const EvaluateExpressionOptions options = GetEvalOptions(target); + ExpressionResults success = target.EvaluateExpression( expr, frame, result_valobj_sp, options, &m_fixed_expression); // We only tell you about the FixIt if we applied it. The compiler errors // will suggest the FixIt if it parsed. - if (!m_fixed_expression.empty() && target->GetEnableNotifyAboutFixIts()) { + if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) { if (success == eExpressionCompleted) error_stream.Printf(" Fix-it applied, fixed expression was: \n %s\n", m_fixed_expression.c_str()); diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp index 6ebad9b5c488..a656a99a1c71 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp @@ -291,17 +291,12 @@ public: void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override { - if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0) + if (request.GetCursorIndex() != 0) return; - lldb::ThreadSP thread_sp = m_exe_ctx.GetThreadSP(); - const uint32_t frame_num = thread_sp->GetStackFrameCount(); - for (uint32_t i = 0; i < frame_num; ++i) { - lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i); - StreamString strm; - frame_sp->Dump(&strm, false, true); - request.TryCompleteCurrentArg(std::to_string(i), strm.GetString()); - } + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eFrameIndexCompletion, + request, nullptr); } Options *GetOptions() override { return &m_options; } @@ -898,12 +893,14 @@ bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, RegularExpressionSP(new RegularExpression(m_options.m_module)); auto func = RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); - StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); + GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( + recognizer_sp, module, func); } else { auto module = ConstString(m_options.m_module); std::vector<ConstString> symbols(m_options.m_symbols.begin(), m_options.m_symbols.end()); - StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, symbols); + GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( + recognizer_sp, module, symbols); } #endif @@ -921,7 +918,9 @@ public: protected: bool DoExecute(Args &command, CommandReturnObject &result) override { - StackFrameRecognizerManager::RemoveAllRecognizers(); + GetSelectedOrDummyTarget() + .GetFrameRecognizerManager() + .RemoveAllRecognizers(); result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } @@ -941,7 +940,7 @@ public: if (request.GetCursorIndex() != 0) return; - StackFrameRecognizerManager::ForEach( + GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( [&request](uint32_t rid, std::string rname, std::string module, llvm::ArrayRef<lldb_private::ConstString> symbols, bool regexp) { @@ -973,7 +972,9 @@ protected: return false; } - StackFrameRecognizerManager::RemoveAllRecognizers(); + GetSelectedOrDummyTarget() + .GetFrameRecognizerManager() + .RemoveAllRecognizers(); result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } @@ -993,7 +994,14 @@ protected: return false; } - StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id); + if (!GetSelectedOrDummyTarget() + .GetFrameRecognizerManager() + .RemoveRecognizerWithID(recognizer_id)) { + result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", + command.GetArgumentAtIndex(0)); + result.SetStatus(eReturnStatusFailed); + return false; + } result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } @@ -1011,7 +1019,7 @@ public: protected: bool DoExecute(Args &command, CommandReturnObject &result) override { bool any_printed = false; - StackFrameRecognizerManager::ForEach( + GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( [&result, &any_printed]( uint32_t recognizer_id, std::string name, std::string module, llvm::ArrayRef<ConstString> symbols, bool regexp) { @@ -1106,8 +1114,9 @@ protected: return false; } - auto recognizer = - StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp); + auto recognizer = GetSelectedOrDummyTarget() + .GetFrameRecognizerManager() + .GetRecognizerForFrame(frame_sp); Stream &output_stream = result.GetOutputStream(); output_stream.Printf("frame %d ", frame_index); diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp index 474c37710149..7d5c642d0131 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp @@ -33,8 +33,7 @@ #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/StreamString.h" - - +#include "llvm/Support/MathExtras.h" #include <cinttypes> #include <memory> @@ -1281,29 +1280,6 @@ public: Options *GetOptions() override { return &m_option_group; } - bool UIntValueIsValidForSize(uint64_t uval64, size_t total_byte_size) { - if (total_byte_size > 8) - return false; - - if (total_byte_size == 8) - return true; - - const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1; - return uval64 <= max; - } - - bool SIntValueIsValidForSize(int64_t sval64, size_t total_byte_size) { - if (total_byte_size > 8) - return false; - - if (total_byte_size == 8) - return true; - - const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1; - const int64_t min = ~(max); - return min <= sval64 && sval64 <= max; - } - protected: bool DoExecute(Args &command, CommandReturnObject &result) override { // No need to check "process" for validity as eCommandRequiresProcess @@ -1449,7 +1425,7 @@ protected: "'%s' is not a valid hex string value.\n", entry.c_str()); result.SetStatus(eReturnStatusFailed); return false; - } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) { + } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) { result.AppendErrorWithFormat("Value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", @@ -1477,7 +1453,7 @@ protected: "'%s' is not a valid binary string value.\n", entry.c_str()); result.SetStatus(eReturnStatusFailed); return false; - } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) { + } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) { result.AppendErrorWithFormat("Value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", @@ -1516,7 +1492,7 @@ protected: "'%s' is not a valid signed decimal value.\n", entry.c_str()); result.SetStatus(eReturnStatusFailed); return false; - } else if (!SIntValueIsValidForSize(sval64, item_byte_size)) { + } else if (!llvm::isIntN(item_byte_size * 8, sval64)) { result.AppendErrorWithFormat( "Value %" PRIi64 " is too large or small to fit in a %" PRIu64 " byte signed integer value.\n", @@ -1535,7 +1511,7 @@ protected: entry.c_str()); result.SetStatus(eReturnStatusFailed); return false; - } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) { + } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) { result.AppendErrorWithFormat("Value %" PRIu64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", @@ -1552,7 +1528,7 @@ protected: "'%s' is not a valid octal string value.\n", entry.c_str()); result.SetStatus(eReturnStatusFailed); return false; - } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) { + } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) { result.AppendErrorWithFormat("Value %" PRIo64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", @@ -1687,63 +1663,72 @@ public: protected: bool DoExecute(Args &command, CommandReturnObject &result) override { ProcessSP process_sp = m_exe_ctx.GetProcessSP(); - if (process_sp) { - Status error; - lldb::addr_t load_addr = m_prev_end_addr; + if (!process_sp) { m_prev_end_addr = LLDB_INVALID_ADDRESS; + result.AppendError("invalid process"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + Status error; + lldb::addr_t load_addr = m_prev_end_addr; + m_prev_end_addr = LLDB_INVALID_ADDRESS; + + const size_t argc = command.GetArgumentCount(); + if (argc > 1 || (argc == 0 && load_addr == LLDB_INVALID_ADDRESS)) { + result.AppendErrorWithFormat("'%s' takes one argument:\nUsage: %s\n", + m_cmd_name.c_str(), m_cmd_syntax.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } - const size_t argc = command.GetArgumentCount(); - if (argc > 1 || (argc == 0 && load_addr == LLDB_INVALID_ADDRESS)) { - result.AppendErrorWithFormat("'%s' takes one argument:\nUsage: %s\n", - m_cmd_name.c_str(), m_cmd_syntax.c_str()); + if (argc == 1) { + auto load_addr_str = command[0].ref(); + load_addr = OptionArgParser::ToAddress(&m_exe_ctx, load_addr_str, + LLDB_INVALID_ADDRESS, &error); + if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) { + result.AppendErrorWithFormat("invalid address argument \"%s\": %s\n", + command[0].c_str(), error.AsCString()); result.SetStatus(eReturnStatusFailed); - } else { - if (command.GetArgumentCount() == 1) { - auto load_addr_str = command[0].ref(); - load_addr = OptionArgParser::ToAddress(&m_exe_ctx, load_addr_str, - LLDB_INVALID_ADDRESS, &error); - if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) { - result.AppendErrorWithFormat( - "invalid address argument \"%s\": %s\n", command[0].c_str(), - error.AsCString()); - result.SetStatus(eReturnStatusFailed); - } - } + return false; + } + } - lldb_private::MemoryRegionInfo range_info; - error = process_sp->GetMemoryRegionInfo(load_addr, range_info); - if (error.Success()) { - lldb_private::Address addr; - ConstString name = range_info.GetName(); - ConstString section_name; - if (process_sp->GetTarget().ResolveLoadAddress(load_addr, addr)) { - SectionSP section_sp(addr.GetSection()); - if (section_sp) { - // Got the top most section, not the deepest section - while (section_sp->GetParent()) - section_sp = section_sp->GetParent(); - section_name = section_sp->GetName(); - } - } - result.AppendMessageWithFormatv( - "[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}\n", - range_info.GetRange().GetRangeBase(), - range_info.GetRange().GetRangeEnd(), range_info.GetReadable(), - range_info.GetWritable(), range_info.GetExecutable(), - name ? " " : "", name, section_name ? " " : "", section_name); - m_prev_end_addr = range_info.GetRange().GetRangeEnd(); - result.SetStatus(eReturnStatusSuccessFinishResult); - } else { - result.SetStatus(eReturnStatusFailed); - result.AppendErrorWithFormat("%s\n", error.AsCString()); + lldb_private::MemoryRegionInfo range_info; + error = process_sp->GetMemoryRegionInfo(load_addr, range_info); + if (error.Success()) { + lldb_private::Address addr; + ConstString name = range_info.GetName(); + ConstString section_name; + if (process_sp->GetTarget().ResolveLoadAddress(load_addr, addr)) { + SectionSP section_sp(addr.GetSection()); + if (section_sp) { + // Got the top most section, not the deepest section + while (section_sp->GetParent()) + section_sp = section_sp->GetParent(); + section_name = section_sp->GetName(); } } - } else { - m_prev_end_addr = LLDB_INVALID_ADDRESS; - result.AppendError("invalid process"); - result.SetStatus(eReturnStatusFailed); + + result.AppendMessageWithFormatv( + "[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}", + range_info.GetRange().GetRangeBase(), + range_info.GetRange().GetRangeEnd(), range_info.GetReadable(), + range_info.GetWritable(), range_info.GetExecutable(), name ? " " : "", + name, section_name ? " " : "", section_name); + MemoryRegionInfo::OptionalBool memory_tagged = + range_info.GetMemoryTagged(); + if (memory_tagged == MemoryRegionInfo::OptionalBool::eYes) + result.AppendMessage("memory tagging: enabled"); + + m_prev_end_addr = range_info.GetRange().GetRangeEnd(); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; } - return result.Succeeded(); + + result.SetStatus(eReturnStatusFailed); + result.AppendErrorWithFormat("%s\n", error.AsCString()); + return false; } const char *GetRepeatCommand(Args ¤t_command_args, diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectMultiword.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectMultiword.cpp index 9033cfebf46b..0f20a1d88bd9 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectMultiword.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectMultiword.cpp @@ -261,11 +261,32 @@ CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter, CommandObjectProxy::~CommandObjectProxy() = default; +Options *CommandObjectProxy::GetOptions() { + CommandObject *proxy_command = GetProxyCommandObject(); + if (proxy_command) + return proxy_command->GetOptions(); + return CommandObject::GetOptions(); +} + +llvm::StringRef CommandObjectProxy::GetHelp() { + CommandObject *proxy_command = GetProxyCommandObject(); + if (proxy_command) + return proxy_command->GetHelp(); + return CommandObject::GetHelp(); +} + +llvm::StringRef CommandObjectProxy::GetSyntax() { + CommandObject *proxy_command = GetProxyCommandObject(); + if (proxy_command) + return proxy_command->GetSyntax(); + return CommandObject::GetSyntax(); +} + llvm::StringRef CommandObjectProxy::GetHelpLong() { CommandObject *proxy_command = GetProxyCommandObject(); if (proxy_command) return proxy_command->GetHelpLong(); - return llvm::StringRef(); + return CommandObject::GetHelpLong(); } bool CommandObjectProxy::IsRemovable() const { @@ -293,7 +314,9 @@ CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() { void CommandObjectProxy::GenerateHelpText(Stream &result) { CommandObject *proxy_command = GetProxyCommandObject(); if (proxy_command) - return proxy_command->GenerateHelpText(result); + proxy_command->GenerateHelpText(result); + else + CommandObject::GenerateHelpText(result); } lldb::CommandObjectSP @@ -345,13 +368,6 @@ bool CommandObjectProxy::WantsCompletion() { return false; } -Options *CommandObjectProxy::GetOptions() { - CommandObject *proxy_command = GetProxyCommandObject(); - if (proxy_command) - return proxy_command->GetOptions(); - return nullptr; -} - void CommandObjectProxy::HandleCompletion(CompletionRequest &request) { CommandObject *proxy_command = GetProxyCommandObject(); if (proxy_command) @@ -373,12 +389,15 @@ const char *CommandObjectProxy::GetRepeatCommand(Args ¤t_command_args, return nullptr; } +llvm::StringRef CommandObjectProxy::GetUnsupportedError() { + return "command is not implemented"; +} + bool CommandObjectProxy::Execute(const char *args_string, CommandReturnObject &result) { CommandObject *proxy_command = GetProxyCommandObject(); if (proxy_command) return proxy_command->Execute(args_string, result); - result.AppendError("command is not implemented"); - result.SetStatus(eReturnStatusFailed); + result.SetError(GetUnsupportedError()); return false; } diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectPlatform.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectPlatform.cpp index fcc8af6f915c..f306da3c8543 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectPlatform.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectPlatform.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "CommandObjectPlatform.h" +#include "CommandOptionsProcessLaunch.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" @@ -392,7 +393,8 @@ public: "or for a platform by name.", "platform settings", 0), m_options(), - m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w', 0, + m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w', + CommandCompletions::eRemoteDiskDirectoryCompletion, eArgTypePath, "The working directory for the platform.") { m_options.Append(&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); @@ -485,6 +487,15 @@ public: ~CommandObjectPlatformFOpen() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex() == 0) + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eRemoteDiskFileCompletion, request, nullptr); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { PlatformSP platform_sp( GetDebugger().GetPlatformList().GetSelectedPlatform()); @@ -817,6 +828,19 @@ public: ~CommandObjectPlatformGetFile() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex() == 0) + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eRemoteDiskFileCompletion, request, nullptr); + else if (request.GetCursorIndex() == 1) + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + request, nullptr); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { // If the number of arguments is incorrect, issue an error message. if (args.GetArgumentCount() != 2) { @@ -882,6 +906,17 @@ public: ~CommandObjectPlatformGetSize() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex() != 0) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eRemoteDiskFileCompletion, + request, nullptr); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { // If the number of arguments is incorrect, issue an error message. if (args.GetArgumentCount() != 1) { @@ -927,6 +962,19 @@ public: ~CommandObjectPlatformPutFile() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex() == 0) + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + request, nullptr); + else if (request.GetCursorIndex() == 1) + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eRemoteDiskFileCompletion, request, nullptr); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { const char *src = args.GetArgumentAtIndex(0); const char *dst = args.GetArgumentAtIndex(1); @@ -1036,7 +1084,7 @@ protected: return result.Succeeded(); } - ProcessLaunchCommandOptions m_options; + CommandOptionsProcessLaunch m_options; }; // "platform process list" @@ -1331,6 +1379,14 @@ public: ~CommandObjectPlatformProcessInfo() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eProcessIDCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &args, CommandReturnObject &result) override { Target *target = GetDebugger().GetSelectedTarget().get(); @@ -1447,46 +1503,6 @@ public: return llvm::makeArrayRef(g_platform_process_attach_options); } - void HandleOptionArgumentCompletion( - CompletionRequest &request, OptionElementVector &opt_element_vector, - int opt_element_index, CommandInterpreter &interpreter) override { - int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos; - int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; - - // We are only completing the name option for now... - - // Are we in the name? - if (GetDefinitions()[opt_defs_index].short_option != 'n') - return; - - // Look to see if there is a -P argument provided, and if so use that - // plugin, otherwise use the default plugin. - - const char *partial_name = nullptr; - partial_name = request.GetParsedLine().GetArgumentAtIndex(opt_arg_pos); - - PlatformSP platform_sp(interpreter.GetPlatform(true)); - if (!platform_sp) - return; - - ProcessInstanceInfoList process_infos; - ProcessInstanceInfoMatch match_info; - if (partial_name) { - match_info.GetProcessInfo().GetExecutableFile().SetFile( - partial_name, FileSpec::Style::native); - match_info.SetNameMatchType(NameMatch::StartsWith); - } - platform_sp->FindProcesses(match_info, process_infos); - const uint32_t num_matches = process_infos.size(); - if (num_matches == 0) - return; - - for (uint32_t i = 0; i < num_matches; ++i) { - request.AddCompletion(process_infos[i].GetNameAsStringRef()); - } - return; - } - // Options table: Required for subclasses of Options. static OptionDefinition g_option_table[]; @@ -1596,6 +1612,16 @@ public: else m_timeout = std::chrono::seconds(timeout_sec); break; + case 's': { + if (option_arg.empty()) { + error.SetErrorStringWithFormat( + "missing shell interpreter path for option -i|--interpreter."); + return error; + } + + m_shell_interpreter = option_arg.str(); + break; + } default: llvm_unreachable("Unimplemented option"); } @@ -1606,10 +1632,12 @@ public: void OptionParsingStarting(ExecutionContext *execution_context) override { m_timeout.reset(); m_use_host_platform = false; + m_shell_interpreter.clear(); } Timeout<std::micro> m_timeout = std::chrono::seconds(10); bool m_use_host_platform; + std::string m_shell_interpreter; }; CommandObjectPlatformShell(CommandInterpreter &interpreter) @@ -1635,7 +1663,6 @@ public: const bool is_alias = !raw_command_line.contains("platform"); OptionsWithRaw args(raw_command_line); - const char *expr = args.GetRawPart().c_str(); if (args.HasArgs()) if (!ParseOptions(args.GetArgs(), result)) @@ -1647,6 +1674,8 @@ public: return false; } + llvm::StringRef cmd = args.GetRawPart(); + PlatformSP platform_sp( m_options.m_use_host_platform ? Platform::GetHostPlatform() @@ -1657,7 +1686,8 @@ public: std::string output; int status = -1; int signo = -1; - error = (platform_sp->RunShellCommand(expr, working_dir, &status, &signo, + error = (platform_sp->RunShellCommand(m_options.m_shell_interpreter, cmd, + working_dir, &status, &signo, &output, m_options.m_timeout)); if (!output.empty()) result.GetOutputStream().PutCString(output); @@ -1706,6 +1736,16 @@ public: ~CommandObjectPlatformInstall() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + request, nullptr); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { if (args.GetArgumentCount() != 2) { result.AppendError("platform target-install takes two arguments"); diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectProcess.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectProcess.cpp index f86779d85b5f..35835f638557 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectProcess.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectProcess.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "CommandObjectProcess.h" +#include "CommandOptionsProcessLaunch.h" #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/BreakpointSite.h" @@ -48,19 +49,19 @@ protected: state = process->GetState(); if (process->IsAlive() && state != eStateConnected) { - char message[1024]; + std::string message; if (process->GetState() == eStateAttaching) - ::snprintf(message, sizeof(message), - "There is a pending attach, abort it and %s?", - m_new_process_action.c_str()); + message = + llvm::formatv("There is a pending attach, abort it and {0}?", + m_new_process_action); else if (process->GetShouldDetach()) - ::snprintf(message, sizeof(message), - "There is a running process, detach from it and %s?", - m_new_process_action.c_str()); + message = llvm::formatv( + "There is a running process, detach from it and {0}?", + m_new_process_action); else - ::snprintf(message, sizeof(message), - "There is a running process, kill it and %s?", - m_new_process_action.c_str()); + message = + llvm::formatv("There is a running process, kill it and {0}?", + m_new_process_action); if (!m_interpreter.Confirm(message, true)) { result.SetStatus(eReturnStatusFailed); @@ -184,6 +185,9 @@ protected: else m_options.launch_info.GetFlags().Clear(eLaunchFlagDisableASLR); + if (target->GetInheritTCC()) + m_options.launch_info.GetFlags().Set(eLaunchFlagInheritTCCFromParent); + if (target->GetDetachOnError()) m_options.launch_info.GetFlags().Set(eLaunchFlagDetachOnError); @@ -248,7 +252,7 @@ protected: return result.Succeeded(); } - ProcessLaunchCommandOptions m_options; + CommandOptionsProcessLaunch m_options; }; #define LLDB_OPTIONS_process_attach @@ -317,49 +321,6 @@ public: return llvm::makeArrayRef(g_process_attach_options); } - void HandleOptionArgumentCompletion( - CompletionRequest &request, OptionElementVector &opt_element_vector, - int opt_element_index, CommandInterpreter &interpreter) override { - int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos; - int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; - - switch (GetDefinitions()[opt_defs_index].short_option) { - case 'n': { - // Look to see if there is a -P argument provided, and if so use that - // plugin, otherwise use the default plugin. - - const char *partial_name = nullptr; - partial_name = request.GetParsedLine().GetArgumentAtIndex(opt_arg_pos); - - PlatformSP platform_sp(interpreter.GetPlatform(true)); - if (!platform_sp) - return; - ProcessInstanceInfoList process_infos; - ProcessInstanceInfoMatch match_info; - if (partial_name) { - match_info.GetProcessInfo().GetExecutableFile().SetFile( - partial_name, FileSpec::Style::native); - match_info.SetNameMatchType(NameMatch::StartsWith); - } - platform_sp->FindProcesses(match_info, process_infos); - const size_t num_matches = process_infos.size(); - if (num_matches == 0) - return; - for (size_t i = 0; i < num_matches; ++i) { - request.AddCompletion(process_infos[i].GetNameAsStringRef()); - } - } break; - - case 'P': - CommandCompletions::InvokeCommonCompletionCallbacks( - interpreter, CommandCompletions::eProcessPluginCompletion, request, - nullptr); - break; - } - } - - // Instance variables to hold the values for command options. - ProcessAttachInfo attach_info; }; @@ -404,7 +365,6 @@ protected: result.AppendError(error.AsCString("Error creating target")); return false; } - GetDebugger().GetTargetList().SetSelectedTarget(target); } // Record the old executable module, we want to issue a warning if the @@ -920,6 +880,17 @@ public: ~CommandObjectProcessLoad() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_exe_ctx.HasProcessScope()) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_options; } protected: @@ -985,6 +956,24 @@ public: ~CommandObjectProcessUnload() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + + if (request.GetCursorIndex() || !m_exe_ctx.HasProcessScope()) + return; + + Process *process = m_exe_ctx.GetProcessPtr(); + + const std::vector<lldb::addr_t> &tokens = process->GetImageTokens(); + const size_t token_num = tokens.size(); + for (size_t i = 0; i < token_num; ++i) { + if (tokens[i] == LLDB_INVALID_IMAGE_TOKEN) + continue; + request.TryCompleteCurrentArg(std::to_string(i)); + } + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Process *process = m_exe_ctx.GetProcessPtr(); diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectQuit.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectQuit.cpp index d0c7bbd3abf8..d4d15bea9a8e 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectQuit.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectQuit.cpp @@ -103,5 +103,9 @@ bool CommandObjectQuit::DoExecute(Args &command, CommandReturnObject &result) { CommandInterpreter::eBroadcastBitQuitCommandReceived; m_interpreter.BroadcastEvent(event_type); result.SetStatus(eReturnStatusQuit); + + if (m_interpreter.GetSaveSessionOnQuit()) + m_interpreter.SaveTranscript(result); + return true; } diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectRegexCommand.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectRegexCommand.cpp new file mode 100644 index 000000000000..1bf29d3c047b --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectRegexCommand.cpp @@ -0,0 +1,90 @@ +//===-- CommandObjectRegexCommand.cpp -------------------------------------===// +// +// 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 "CommandObjectRegexCommand.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +// CommandObjectRegexCommand constructor +CommandObjectRegexCommand::CommandObjectRegexCommand( + CommandInterpreter &interpreter, llvm::StringRef name, llvm::StringRef help, + llvm::StringRef syntax, uint32_t max_matches, uint32_t completion_type_mask, + bool is_removable) + : CommandObjectRaw(interpreter, name, help, syntax), + m_max_matches(max_matches), m_completion_type_mask(completion_type_mask), + m_entries(), m_is_removable(is_removable) {} + +// Destructor +CommandObjectRegexCommand::~CommandObjectRegexCommand() {} + +bool CommandObjectRegexCommand::DoExecute(llvm::StringRef command, + CommandReturnObject &result) { + EntryCollection::const_iterator pos, end = m_entries.end(); + for (pos = m_entries.begin(); pos != end; ++pos) { + llvm::SmallVector<llvm::StringRef, 4> matches; + if (pos->regex.Execute(command, &matches)) { + std::string new_command(pos->command); + char percent_var[8]; + size_t idx, percent_var_idx; + for (uint32_t match_idx = 1; match_idx <= m_max_matches; ++match_idx) { + if (match_idx < matches.size()) { + const std::string match_str = matches[match_idx].str(); + const int percent_var_len = + ::snprintf(percent_var, sizeof(percent_var), "%%%u", match_idx); + for (idx = 0; (percent_var_idx = new_command.find( + percent_var, idx)) != std::string::npos;) { + new_command.erase(percent_var_idx, percent_var_len); + new_command.insert(percent_var_idx, match_str); + idx += percent_var_idx + match_str.size(); + } + } + } + // Interpret the new command and return this as the result! + if (m_interpreter.GetExpandRegexAliases()) + result.GetOutputStream().Printf("%s\n", new_command.c_str()); + // Pass in true for "no context switching". The command that called us + // should have set up the context appropriately, we shouldn't have to + // redo that. + return m_interpreter.HandleCommand( + new_command.c_str(), eLazyBoolCalculate, result, nullptr, true, true); + } + } + result.SetStatus(eReturnStatusFailed); + if (!GetSyntax().empty()) + result.AppendError(GetSyntax()); + else + result.GetOutputStream() << "Command contents '" << command + << "' failed to match any " + "regular expression in the '" + << m_cmd_name << "' regex "; + return false; +} + +bool CommandObjectRegexCommand::AddRegexCommand(llvm::StringRef re_cstr, + llvm::StringRef command_cstr) { + m_entries.resize(m_entries.size() + 1); + // Only add the regular expression if it compiles + m_entries.back().regex = RegularExpression(re_cstr); + if (m_entries.back().regex.IsValid()) { + m_entries.back().command = command_cstr.str(); + return true; + } + // The regex didn't compile... + m_entries.pop_back(); + return false; +} + +void CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) { + if (m_completion_type_mask) { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), m_completion_type_mask, request, nullptr); + } +} diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectRegexCommand.h b/contrib/llvm-project/lldb/source/Commands/CommandObjectRegexCommand.h new file mode 100644 index 000000000000..2f65c2cd815d --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectRegexCommand.h @@ -0,0 +1,61 @@ +//===-- CommandObjectRegexCommand.h -----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_INTERPRETER_COMMANDOBJECTREGEXCOMMAND_H +#define LLDB_INTERPRETER_COMMANDOBJECTREGEXCOMMAND_H + +#include <list> + +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Utility/CompletionRequest.h" +#include "lldb/Utility/RegularExpression.h" + +namespace lldb_private { + +// CommandObjectRegexCommand + +class CommandObjectRegexCommand : public CommandObjectRaw { +public: + CommandObjectRegexCommand(CommandInterpreter &interpreter, + llvm::StringRef name, llvm::StringRef help, + llvm::StringRef syntax, uint32_t max_matches, + uint32_t completion_type_mask, bool is_removable); + + ~CommandObjectRegexCommand() override; + + bool IsRemovable() const override { return m_is_removable; } + + bool AddRegexCommand(llvm::StringRef re_cstr, llvm::StringRef command_cstr); + + bool HasRegexEntries() const { return !m_entries.empty(); } + + void HandleCompletion(CompletionRequest &request) override; + +protected: + bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override; + + struct Entry { + RegularExpression regex; + std::string command; + }; + + typedef std::list<Entry> EntryCollection; + const uint32_t m_max_matches; + const uint32_t m_completion_type_mask; + EntryCollection m_entries; + bool m_is_removable; + +private: + CommandObjectRegexCommand(const CommandObjectRegexCommand &) = delete; + const CommandObjectRegexCommand & + operator=(const CommandObjectRegexCommand &) = delete; +}; + +} // namespace lldb_private + +#endif // LLDB_INTERPRETER_COMMANDOBJECTREGEXCOMMAND_H diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp index 104130b70b2b..55f34c05d11d 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectReproducer.cpp @@ -27,10 +27,12 @@ using namespace lldb_private::repro; enum ReproducerProvider { eReproducerProviderCommands, eReproducerProviderFiles, + eReproducerProviderSymbolFiles, eReproducerProviderGDB, eReproducerProviderProcessInfo, eReproducerProviderVersion, eReproducerProviderWorkingDirectory, + eReproducerProviderHomeDirectory, eReproducerProviderNone }; @@ -46,6 +48,11 @@ static constexpr OptionEnumValueElement g_reproducer_provider_type[] = { "Files", }, { + eReproducerProviderSymbolFiles, + "symbol-files", + "Symbol Files", + }, + { eReproducerProviderGDB, "gdb", "GDB Remote Packets", @@ -66,6 +73,11 @@ static constexpr OptionEnumValueElement g_reproducer_provider_type[] = { "Working Directory", }, { + eReproducerProviderHomeDirectory, + "home", + "Home Directory", + }, + { eReproducerProviderNone, "none", "None", @@ -104,6 +116,9 @@ static constexpr OptionEnumValues ReproducerSignalType() { #define LLDB_OPTIONS_reproducer_xcrash #include "CommandOptions.inc" +#define LLDB_OPTIONS_reproducer_verify +#include "CommandOptions.inc" + template <typename T> llvm::Expected<T> static ReadFromYAML(StringRef filename) { auto error_or_file = MemoryBuffer::getFile(filename); @@ -122,6 +137,38 @@ llvm::Expected<T> static ReadFromYAML(StringRef filename) { return t; } +static void SetError(CommandReturnObject &result, Error err) { + result.GetErrorStream().Printf("error: %s\n", + toString(std::move(err)).c_str()); + result.SetStatus(eReturnStatusFailed); +} + +/// Create a loader from the given path if specified. Otherwise use the current +/// loader used for replay. +static Loader * +GetLoaderFromPathOrCurrent(llvm::Optional<Loader> &loader_storage, + CommandReturnObject &result, + FileSpec reproducer_path) { + if (reproducer_path) { + loader_storage.emplace(reproducer_path); + Loader *loader = &(*loader_storage); + if (Error err = loader->LoadIndex()) { + // This is a hard error and will set the result to eReturnStatusFailed. + SetError(result, std::move(err)); + return nullptr; + } + return loader; + } + + if (Loader *loader = Reproducer::Instance().GetLoader()) + return loader; + + // This is a soft error because this is expected to fail during capture. + result.SetError("Not specifying a reproducer is only support during replay."); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return nullptr; +} + class CommandObjectReproducerGenerate : public CommandObjectParsed { public: CommandObjectReproducerGenerate(CommandInterpreter &interpreter) @@ -145,6 +192,10 @@ protected: auto &r = Reproducer::Instance(); if (auto generator = r.GetGenerator()) { generator->Keep(); + if (llvm::Error e = repro::Finalize(r.GetReproducerPath())) { + SetError(result, std::move(e)); + return result.Succeeded(); + } } else if (r.IsReplaying()) { // Make this operation a NO-OP in replay mode. result.SetStatus(eReturnStatusSuccessFinishNoResult); @@ -300,12 +351,6 @@ protected: } }; -static void SetError(CommandReturnObject &result, Error err) { - result.GetErrorStream().Printf("error: %s\n", - toString(std::move(err)).c_str()); - result.SetStatus(eReturnStatusFailed); -} - class CommandObjectReproducerDump : public CommandObjectParsed { public: CommandObjectReproducerDump(CommandInterpreter &interpreter) @@ -370,29 +415,11 @@ protected: return false; } - // If no reproducer path is specified, use the loader currently used for - // replay. Otherwise create a new loader just for dumping. llvm::Optional<Loader> loader_storage; - Loader *loader = nullptr; - if (!m_options.file) { - loader = Reproducer::Instance().GetLoader(); - if (loader == nullptr) { - result.SetError( - "Not specifying a reproducer is only support during replay."); - result.SetStatus(eReturnStatusSuccessFinishNoResult); - return false; - } - } else { - loader_storage.emplace(m_options.file); - loader = &(*loader_storage); - if (Error err = loader->LoadIndex()) { - SetError(result, std::move(err)); - return false; - } - } - - // If we get here we should have a valid loader. - assert(loader); + Loader *loader = + GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file); + if (!loader) + return false; switch (m_options.provider) { case eReproducerProviderFiles: { @@ -421,6 +448,29 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); return true; } + case eReproducerProviderSymbolFiles: { + Expected<std::string> symbol_files = + loader->LoadBuffer<SymbolFileProvider>(); + if (!symbol_files) { + SetError(result, symbol_files.takeError()); + return false; + } + + std::vector<SymbolFileProvider::Entry> entries; + llvm::yaml::Input yin(*symbol_files); + yin >> entries; + + for (const auto &entry : entries) { + result.AppendMessageWithFormat("- uuid: %s\n", + entry.uuid.c_str()); + result.AppendMessageWithFormat(" module path: %s\n", + entry.module_path.c_str()); + result.AppendMessageWithFormat(" symbol path: %s\n", + entry.symbol_path.c_str()); + } + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } case eReproducerProviderVersion: { Expected<std::string> version = loader->LoadBuffer<VersionProvider>(); if (!version) { @@ -433,7 +483,7 @@ protected: } case eReproducerProviderWorkingDirectory: { Expected<std::string> cwd = - loader->LoadBuffer<WorkingDirectoryProvider>(); + repro::GetDirectoryFrom<WorkingDirectoryProvider>(loader); if (!cwd) { SetError(result, cwd.takeError()); return false; @@ -442,6 +492,17 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); return true; } + case eReproducerProviderHomeDirectory: { + Expected<std::string> home = + repro::GetDirectoryFrom<HomeDirectoryProvider>(loader); + if (!home) { + SetError(result, home.takeError()); + return false; + } + result.AppendMessage(*home); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } case eReproducerProviderCommands: { std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> multi_loader = repro::MultiLoader<repro::CommandProvider>::Create(loader); @@ -537,6 +598,101 @@ private: CommandOptions m_options; }; +class CommandObjectReproducerVerify : public CommandObjectParsed { +public: + CommandObjectReproducerVerify(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "reproducer verify", + "Verify the contents of a reproducer. " + "If no reproducer is specified during replay, it " + "verifies the content of the current reproducer.", + nullptr) {} + + ~CommandObjectReproducerVerify() override = default; + + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options(), file() {} + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'f': + file.SetFile(option_arg, FileSpec::Style::native); + FileSystem::Instance().Resolve(file); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + file.Clear(); + } + + ArrayRef<OptionDefinition> GetDefinitions() override { + return makeArrayRef(g_reproducer_verify_options); + } + + FileSpec file; + }; + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (!command.empty()) { + result.AppendErrorWithFormat("'%s' takes no arguments", + m_cmd_name.c_str()); + return false; + } + + llvm::Optional<Loader> loader_storage; + Loader *loader = + GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file); + if (!loader) + return false; + + bool errors = false; + auto error_callback = [&](llvm::StringRef error) { + errors = true; + result.AppendError(error); + }; + + bool warnings = false; + auto warning_callback = [&](llvm::StringRef warning) { + warnings = true; + result.AppendWarning(warning); + }; + + auto note_callback = [&](llvm::StringRef warning) { + result.AppendMessage(warning); + }; + + Verifier verifier(loader); + verifier.Verify(error_callback, warning_callback, note_callback); + + if (warnings || errors) { + result.AppendMessage("reproducer verification failed"); + result.SetStatus(eReturnStatusFailed); + } else { + result.AppendMessage("reproducer verification succeeded"); + result.SetStatus(eReturnStatusSuccessFinishResult); + } + + return result.Succeeded(); + } + +private: + CommandOptions m_options; +}; + CommandObjectReproducer::CommandObjectReproducer( CommandInterpreter &interpreter) : CommandObjectMultiword( @@ -559,6 +715,8 @@ CommandObjectReproducer::CommandObjectReproducer( new CommandObjectReproducerStatus(interpreter))); LoadSubCommand("dump", CommandObjectSP(new CommandObjectReproducerDump(interpreter))); + LoadSubCommand("verify", CommandObjectSP( + new CommandObjectReproducerVerify(interpreter))); LoadSubCommand("xcrash", CommandObjectSP( new CommandObjectReproducerXCrash(interpreter))); } diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.cpp new file mode 100644 index 000000000000..9dadf11ebfc8 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.cpp @@ -0,0 +1,138 @@ +//===-- CommandObjectScript.cpp -------------------------------------------===// +// +// 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 "CommandObjectScript.h" +#include "lldb/Core/Debugger.h" +#include "lldb/DataFormatters/DataVisualization.h" +#include "lldb/Host/Config.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Utility/Args.h" + +using namespace lldb; +using namespace lldb_private; + +static constexpr OptionEnumValueElement g_script_option_enumeration[] = { + { + eScriptLanguagePython, + "python", + "Python", + }, + { + eScriptLanguageLua, + "lua", + "Lua", + }, + { + eScriptLanguageNone, + "default", + "The default scripting language.", + }, +}; + +static constexpr OptionEnumValues ScriptOptionEnum() { + return OptionEnumValues(g_script_option_enumeration); +} + +#define LLDB_OPTIONS_script +#include "CommandOptions.inc" + +Status CommandObjectScript::CommandOptions::SetOptionValue( + uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'l': + language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum( + option_arg, GetDefinitions()[option_idx].enum_values, + eScriptLanguageNone, error); + if (!error.Success()) + error.SetErrorStringWithFormat("unrecognized value for language '%s'", + option_arg.str().c_str()); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; +} + +void CommandObjectScript::CommandOptions::OptionParsingStarting( + ExecutionContext *execution_context) { + language = lldb::eScriptLanguageNone; +} + +llvm::ArrayRef<OptionDefinition> +CommandObjectScript::CommandOptions::GetDefinitions() { + return llvm::makeArrayRef(g_script_options); +} + +CommandObjectScript::CommandObjectScript(CommandInterpreter &interpreter) + : CommandObjectRaw( + interpreter, "script", + "Invoke the script interpreter with provided code and display any " + "results. Start the interactive interpreter if no code is supplied.", + "script [--language <scripting-language> --] [<script-code>]") {} + +CommandObjectScript::~CommandObjectScript() {} + +bool CommandObjectScript::DoExecute(llvm::StringRef command, + CommandReturnObject &result) { + // Try parsing the language option but when the command contains a raw part + // separated by the -- delimiter. + OptionsWithRaw raw_args(command); + if (raw_args.HasArgs()) { + if (!ParseOptions(raw_args.GetArgs(), result)) + return false; + command = raw_args.GetRawPart(); + } + + lldb::ScriptLanguage language = + (m_options.language == lldb::eScriptLanguageNone) + ? m_interpreter.GetDebugger().GetScriptLanguage() + : m_options.language; + + if (language == lldb::eScriptLanguageNone) { + result.AppendError( + "the script-lang setting is set to none - scripting not available"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + ScriptInterpreter *script_interpreter = + GetDebugger().GetScriptInterpreter(true, language); + + if (script_interpreter == nullptr) { + result.AppendError("no script interpreter"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + // Script might change Python code we use for formatting. Make sure we keep + // up to date with it. + DataVisualization::ForceUpdate(); + + if (command.empty()) { + script_interpreter->ExecuteInterpreterLoop(); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return result.Succeeded(); + } + + // We can do better when reporting the status of one-liner script execution. + if (script_interpreter->ExecuteOneLine(command, &result)) + result.SetStatus(eReturnStatusSuccessFinishNoResult); + else + result.SetStatus(eReturnStatusFailed); + + return result.Succeeded(); +} diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.h b/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.h new file mode 100644 index 000000000000..b9fee7124818 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.h @@ -0,0 +1,42 @@ +//===-- CommandObjectScript.h -----------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H +#define LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H + +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +class CommandObjectScript : public CommandObjectRaw { +public: + CommandObjectScript(CommandInterpreter &interpreter); + ~CommandObjectScript() override; + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options() {} + ~CommandOptions() override = default; + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override; + void OptionParsingStarting(ExecutionContext *execution_context) override; + llvm::ArrayRef<OptionDefinition> GetDefinitions() override; + lldb::ScriptLanguage language = lldb::eScriptLanguageNone; + }; + +protected: + bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override; + +private: + CommandOptions m_options; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectSession.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectSession.cpp new file mode 100644 index 000000000000..c2cdfa29a3f6 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectSession.cpp @@ -0,0 +1,208 @@ +#include "CommandObjectSession.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionValue.h" +#include "lldb/Interpreter/OptionValueBoolean.h" +#include "lldb/Interpreter/OptionValueString.h" +#include "lldb/Interpreter/OptionValueUInt64.h" +#include "lldb/Interpreter/Options.h" + +using namespace lldb; +using namespace lldb_private; + +class CommandObjectSessionSave : public CommandObjectParsed { +public: + CommandObjectSessionSave(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "session save", + "Save the current session transcripts to a file.\n" + "If no file if specified, transcripts will be " + "saved to a temporary file.", + "session save [file]") { + CommandArgumentEntry arg1; + arg1.emplace_back(eArgTypePath, eArgRepeatOptional); + m_arguments.push_back(arg1); + } + + ~CommandObjectSessionSave() override = default; + + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + request, nullptr); + } + +protected: + bool DoExecute(Args &args, CommandReturnObject &result) override { + llvm::StringRef file_path; + + if (!args.empty()) + file_path = args[0].ref(); + + if (m_interpreter.SaveTranscript(result, file_path.str())) + result.SetStatus(eReturnStatusSuccessFinishNoResult); + else + result.SetStatus(eReturnStatusFailed); + return result.Succeeded(); + } +}; + +#define LLDB_OPTIONS_history +#include "CommandOptions.inc" + +class CommandObjectSessionHistory : public CommandObjectParsed { +public: + CommandObjectSessionHistory(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "session history", + "Dump the history of commands in this session.\n" + "Commands in the history list can be run again " + "using \"!<INDEX>\". \"!-<OFFSET>\" will re-run " + "the command that is <OFFSET> commands from the end" + " of the list (counting the current command).", + nullptr), + m_options() {} + + ~CommandObjectSessionHistory() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + class CommandOptions : public Options { + public: + CommandOptions() + : Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) { + } + + ~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 'c': + error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign); + break; + case 's': + if (option_arg == "end") { + m_start_idx.SetCurrentValue(UINT64_MAX); + m_start_idx.SetOptionWasSet(); + } else + error = m_start_idx.SetValueFromString(option_arg, + eVarSetOperationAssign); + break; + case 'e': + error = + m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign); + break; + case 'C': + m_clear.SetCurrentValue(true); + m_clear.SetOptionWasSet(); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_start_idx.Clear(); + m_stop_idx.Clear(); + m_count.Clear(); + m_clear.Clear(); + } + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_history_options); + } + + // Instance variables to hold the values for command options. + + OptionValueUInt64 m_start_idx; + OptionValueUInt64 m_stop_idx; + OptionValueUInt64 m_count; + OptionValueBoolean m_clear; + }; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (m_options.m_clear.GetCurrentValue() && + m_options.m_clear.OptionWasSet()) { + m_interpreter.GetCommandHistory().Clear(); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + } else { + if (m_options.m_start_idx.OptionWasSet() && + m_options.m_stop_idx.OptionWasSet() && + m_options.m_count.OptionWasSet()) { + result.AppendError("--count, --start-index and --end-index cannot be " + "all specified in the same invocation"); + result.SetStatus(lldb::eReturnStatusFailed); + } else { + std::pair<bool, uint64_t> start_idx( + m_options.m_start_idx.OptionWasSet(), + m_options.m_start_idx.GetCurrentValue()); + std::pair<bool, uint64_t> stop_idx( + m_options.m_stop_idx.OptionWasSet(), + m_options.m_stop_idx.GetCurrentValue()); + std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(), + m_options.m_count.GetCurrentValue()); + + const CommandHistory &history(m_interpreter.GetCommandHistory()); + + if (start_idx.first && start_idx.second == UINT64_MAX) { + if (count.first) { + start_idx.second = history.GetSize() - count.second; + stop_idx.second = history.GetSize() - 1; + } else if (stop_idx.first) { + start_idx.second = stop_idx.second; + stop_idx.second = history.GetSize() - 1; + } else { + start_idx.second = 0; + stop_idx.second = history.GetSize() - 1; + } + } else { + if (!start_idx.first && !stop_idx.first && !count.first) { + start_idx.second = 0; + stop_idx.second = history.GetSize() - 1; + } else if (start_idx.first) { + if (count.first) { + stop_idx.second = start_idx.second + count.second - 1; + } else if (!stop_idx.first) { + stop_idx.second = history.GetSize() - 1; + } + } else if (stop_idx.first) { + if (count.first) { + if (stop_idx.second >= count.second) + start_idx.second = stop_idx.second - count.second + 1; + else + start_idx.second = 0; + } + } else /* if (count.first) */ + { + start_idx.second = 0; + stop_idx.second = count.second - 1; + } + } + history.Dump(result.GetOutputStream(), start_idx.second, + stop_idx.second); + } + } + return result.Succeeded(); + } + + CommandOptions m_options; +}; + +CommandObjectSession::CommandObjectSession(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "session", + "Commands controlling LLDB session.", + "session <subcommand> [<command-options>]") { + LoadSubCommand("save", + CommandObjectSP(new CommandObjectSessionSave(interpreter))); + LoadSubCommand("history", + CommandObjectSP(new CommandObjectSessionHistory(interpreter))); +} diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectSession.h b/contrib/llvm-project/lldb/source/Commands/CommandObjectSession.h new file mode 100644 index 000000000000..0af0e279f47e --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectSession.h @@ -0,0 +1,23 @@ +//===-- CommandObjectSession.h ----------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTSESSION_H +#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTSESSION_H + +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +class CommandObjectSession : public CommandObjectMultiword { +public: + CommandObjectSession(CommandInterpreter &interpreter); +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTSESSION_H diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectSource.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectSource.cpp index 1ccfd3a5166f..8fff22a06366 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectSource.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectSource.cpp @@ -16,6 +16,7 @@ #include "lldb/Host/OptionParser.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionValueFileColonLine.h" #include "lldb/Interpreter/Options.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" @@ -667,6 +668,22 @@ class CommandObjectSourceList : public CommandObjectParsed { case 'r': reverse = true; break; + case 'y': + { + OptionValueFileColonLine value; + Status fcl_err = value.SetValueFromString(option_arg); + if (!fcl_err.Success()) { + error.SetErrorStringWithFormat( + "Invalid value for file:line specifier: %s", + fcl_err.AsCString()); + } else { + file_name = value.GetFileSpec().GetPath(); + start_line = value.GetLineNumber(); + // I don't see anything useful to do with a column number, but I don't + // want to complain since someone may well have cut and pasted a + // listing from somewhere that included a column. + } + } break; default: llvm_unreachable("Unimplemented option"); } diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectTarget.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectTarget.cpp index 7bb71f4d518c..1cb21384fd2a 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectTarget.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectTarget.cpp @@ -23,6 +23,8 @@ #include "lldb/Interpreter/OptionGroupBoolean.h" #include "lldb/Interpreter/OptionGroupFile.h" #include "lldb/Interpreter/OptionGroupFormat.h" +#include "lldb/Interpreter/OptionGroupPlatform.h" +#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h" #include "lldb/Interpreter/OptionGroupString.h" #include "lldb/Interpreter/OptionGroupUInt64.h" #include "lldb/Interpreter/OptionGroupUUID.h" @@ -48,6 +50,7 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatAdapters.h" @@ -206,8 +209,6 @@ private: #pragma mark CommandObjectTargetCreate -// "target create" - class CommandObjectTargetCreate : public CommandObjectParsed { public: CommandObjectTargetCreate(CommandInterpreter &interpreter) @@ -216,11 +217,9 @@ public: "Create a target using the argument as the main executable.", nullptr), m_option_group(), m_arch_option(), + m_platform_options(true), // Include the --platform 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 " @@ -245,8 +244,8 @@ public: 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_platform_options, LLDB_OPT_SET_ALL, 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); @@ -300,8 +299,7 @@ protected: } 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); + LLDB_SCOPED_TIMERF("(lldb) target create '%s'", file_path); FileSpec file_spec; if (file_path) { @@ -317,124 +315,127 @@ protected: 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)); + m_add_dependents.m_load_dependent_files, &m_platform_options, + 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"); + if (!target_sp) { + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + auto on_error = llvm::make_scope_exit( + [&target_list = debugger.GetTargetList(), &target_sp]() { + target_list.DeleteTarget(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; } - 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"); + } + } 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 (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; } + } 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); - } + 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 (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) { - FileSpec core_file_dir; - core_file_dir.GetDirectory() = core_file.GetDirectory(); - target_sp->AppendExecutableSearchPaths(core_file_dir); + if (core_file) { + 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)); + ProcessSP process_sp(target_sp->CreateProcess( + GetDebugger().GetListener(), llvm::StringRef(), &core_file, false)); - if (process_sp) { - // Seems weird that we Launch a core file, but that is what we - // do! - error = process_sp->LoadCore(); + 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.AppendMessageWithFormatv("Core file '{0}' ({1}) was loaded.\n", core_file.GetPath(), - target_sp->GetArchitecture().GetArchitectureName()); - result.SetStatus(eReturnStatusSuccessFinishNoResult); - } - } else { - result.AppendErrorWithFormatv( - "Unable to find process plug-in for core file '{0}'\n", - core_file.GetPath()); + if (error.Fail()) { + result.AppendError( + error.AsCString("can't find plug-in for core file")); result.SetStatus(eReturnStatusFailed); + return false; + } else { + result.AppendMessageWithFormatv( + "Core file '{0}' ({1}) was loaded.\n", core_file.GetPath(), + target_sp->GetArchitecture().GetArchitectureName()); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + on_error.release(); } } else { - result.AppendMessageWithFormat( - "Current executable set to '%s' (%s).\n", - file_spec.GetPath().c_str(), - target_sp->GetArchitecture().GetArchitectureName()); - result.SetStatus(eReturnStatusSuccessFinishNoResult); + result.AppendErrorWithFormatv( + "Unable to find process plug-in for core file '{0}'\n", + core_file.GetPath()); + result.SetStatus(eReturnStatusFailed); } } else { - result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); + result.AppendMessageWithFormat( + "Current executable set to '%s' (%s).\n", + file_spec.GetPath().c_str(), + target_sp->GetArchitecture().GetArchitectureName()); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + on_error.release(); } } else { result.AppendErrorWithFormat("'%s' takes exactly one executable path " @@ -442,14 +443,15 @@ protected: m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); } + return result.Succeeded(); } private: OptionGroupOptions m_option_group; OptionGroupArchitecture m_arch_option; + OptionGroupPlatform m_platform_options; OptionGroupFile m_core_file; - OptionGroupFile m_platform_path; OptionGroupFile m_symbol_file; OptionGroupFile m_remote_file; OptionGroupDependents m_add_dependents; @@ -457,8 +459,6 @@ private: #pragma mark CommandObjectTargetList -// "target list" - class CommandObjectTargetList : public CommandObjectParsed { public: CommandObjectTargetList(CommandInterpreter &interpreter) @@ -490,8 +490,6 @@ protected: #pragma mark CommandObjectTargetSelect -// "target select" - class CommandObjectTargetSelect : public CommandObjectParsed { public: CommandObjectTargetSelect(CommandInterpreter &interpreter) @@ -511,18 +509,11 @@ protected: 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); - } + target_list.SetSelectedTarget(target_idx); + Stream &strm = result.GetOutputStream(); + bool show_stopped_process_status = false; + DumpTargetList(target_list, show_stopped_process_status, strm); + result.SetStatus(eReturnStatusSuccessFinishResult); } else { if (num_targets > 0) { result.AppendErrorWithFormat( @@ -551,8 +542,6 @@ protected: #pragma mark CommandObjectTargetDelete -// "target delete" - class CommandObjectTargetDelete : public CommandObjectParsed { public: CommandObjectTargetDelete(CommandInterpreter &interpreter) @@ -697,8 +686,6 @@ protected: #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' @@ -917,6 +904,7 @@ protected: CompileUnit *comp_unit = nullptr; if (frame) { SymbolContext sc = frame->GetSymbolContext(eSymbolContextCompUnit); + comp_unit = sc.comp_unit; if (sc.comp_unit) { const bool can_create = true; VariableListSP comp_unit_varlist_sp( @@ -1167,6 +1155,25 @@ public: ~CommandObjectTargetModulesSearchPathsInsert() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_exe_ctx.HasTargetScope() || request.GetCursorIndex() != 0) + return; + + Target *target = m_exe_ctx.GetTargetPtr(); + const PathMappingList &list = target->GetImageSearchPathList(); + const size_t num = list.GetSize(); + ConstString old_path, new_path; + for (size_t i = 0; i < num; ++i) { + if (!list.GetPathsAtIndex(i, old_path, new_path)) + break; + StreamString strm; + strm << old_path << " -> " << new_path; + request.TryCompleteCurrentArg(std::to_string(i), strm.GetString()); + } + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target *target = &GetSelectedTarget(); @@ -1392,31 +1399,30 @@ static void DumpBasename(Stream &strm, const FileSpec *file_spec_ptr, } 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()); - } + if (num_modules == 0) + return 0; + + size_t num_dumped = 0; + strm.Format("Dumping headers for {0} module(s).\n", num_modules); + strm.IndentMore(); + for (ModuleSP module_sp : module_list.ModulesNoLocking()) { + if (module_sp) { + if (num_dumped++ > 0) { + strm.EOL(); + strm.EOL(); + } + ObjectFile *objfile = module_sp->GetObjectFile(); + if (objfile) + objfile->Dump(&strm); + else { + strm.Format("No object file for module: {0:F}\n", + module_sp->GetFileSpec()); } } - strm.IndentLess(); } + strm.IndentLess(); return num_dumped; } @@ -1624,7 +1630,8 @@ static size_t LookupFunctionInModule(CommandInterpreter &interpreter, return 0; } -static size_t LookupTypeInModule(CommandInterpreter &interpreter, Stream &strm, +static size_t LookupTypeInModule(Target *target, + CommandInterpreter &interpreter, Stream &strm, Module *module, const char *name_cstr, bool name_is_regex) { TypeList type_list; @@ -1652,7 +1659,7 @@ static size_t LookupTypeInModule(CommandInterpreter &interpreter, Stream &strm, // 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); + type_sp->GetDescription(&strm, eDescriptionLevelFull, true, target); // Print all typedef chains TypeSP typedef_type_sp(type_sp); TypeSP typedefed_type_sp(typedef_type_sp->GetTypedefType()); @@ -1661,7 +1668,8 @@ static size_t LookupTypeInModule(CommandInterpreter &interpreter, Stream &strm, strm.Printf(" typedef '%s': ", typedef_type_sp->GetName().GetCString()); typedefed_type_sp->GetFullCompilerType(); - typedefed_type_sp->GetDescription(&strm, eDescriptionLevelFull, true); + typedefed_type_sp->GetDescription(&strm, eDescriptionLevelFull, true, + target); typedef_type_sp = typedefed_type_sp; typedefed_type_sp = typedef_type_sp->GetTypedefType(); } @@ -1671,9 +1679,9 @@ static size_t LookupTypeInModule(CommandInterpreter &interpreter, Stream &strm, return type_list.GetSize(); } -static size_t LookupTypeHere(CommandInterpreter &interpreter, Stream &strm, - Module &module, const char *name_cstr, - bool name_is_regex) { +static size_t LookupTypeHere(Target *target, CommandInterpreter &interpreter, + Stream &strm, Module &module, + const char *name_cstr, bool name_is_regex) { TypeList type_list; const uint32_t max_num_matches = UINT32_MAX; bool name_is_fully_qualified = false; @@ -1696,8 +1704,8 @@ static size_t LookupTypeHere(CommandInterpreter &interpreter, Stream &strm, // 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 + type_sp->GetDescription(&strm, eDescriptionLevelFull, true, target); + // Print all typedef chains. TypeSP typedef_type_sp(type_sp); TypeSP typedefed_type_sp(typedef_type_sp->GetTypedefType()); while (typedefed_type_sp) { @@ -1705,7 +1713,8 @@ static size_t LookupTypeHere(CommandInterpreter &interpreter, Stream &strm, strm.Printf(" typedef '%s': ", typedef_type_sp->GetName().GetCString()); typedefed_type_sp->GetFullCompilerType(); - typedefed_type_sp->GetDescription(&strm, eDescriptionLevelFull, true); + typedefed_type_sp->GetDescription(&strm, eDescriptionLevelFull, true, + target); typedef_type_sp = typedefed_type_sp; typedefed_type_sp = typedef_type_sp->GetTypedefType(); } @@ -2015,14 +2024,13 @@ protected: 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(); + const ModuleList &module_list = target->GetImages(); + std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); + const size_t num_modules = module_list.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) { + result.GetOutputStream().Format( + "Dumping symbol table for {0} modules.\n", num_modules); + for (ModuleSP module_sp : module_list.ModulesNoLocking()) { if (num_dumped > 0) { result.GetOutputStream().EOL(); result.GetOutputStream().EOL(); @@ -2030,10 +2038,9 @@ protected: if (m_interpreter.WasInterrupted()) break; num_dumped++; - DumpModuleSymtab( - m_interpreter, result.GetOutputStream(), - target->GetImages().GetModulePointerAtIndexUnlocked(image_idx), - m_options.m_sort_order, name_preference); + DumpModuleSymtab(m_interpreter, result.GetOutputStream(), + module_sp.get(), m_options.m_sort_order, + name_preference); } } else { result.AppendError("the target has no associated executable images"); @@ -2050,9 +2057,8 @@ protected: 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) { + for (ModuleSP module_sp : module_list.Modules()) { + if (module_sp) { if (num_dumped > 0) { result.GetOutputStream().EOL(); result.GetOutputStream().EOL(); @@ -2060,8 +2066,9 @@ protected: if (m_interpreter.WasInterrupted()) break; num_dumped++; - DumpModuleSymtab(m_interpreter, result.GetOutputStream(), module, - m_options.m_sort_order, name_preference); + DumpModuleSymtab(m_interpreter, result.GetOutputStream(), + module_sp.get(), m_options.m_sort_order, + name_preference); } } } else @@ -2110,23 +2117,22 @@ protected: 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 { + if (num_modules == 0) { result.AppendError("the target has no associated executable images"); result.SetStatus(eReturnStatusFailed); return false; } + + result.GetOutputStream().Format("Dumping sections for {0} modules.\n", + 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 { // Dump specified images (by basename or fullpath) const char *arg_cstr; @@ -2188,7 +2194,8 @@ protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target *target = &GetSelectedTarget(); - const size_t num_modules = target->GetImages().GetSize(); + const ModuleList &module_list = target->GetImages(); + const size_t num_modules = module_list.GetSize(); if (num_modules == 0) { result.AppendError("the target has no associated executable images"); result.SetStatus(eReturnStatusFailed); @@ -2197,14 +2204,12 @@ protected: 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) { + result.GetOutputStream().Format("Dumping clang ast for {0} modules.\n", + num_modules); + for (ModuleSP module_sp : module_list.ModulesNoLocking()) { if (m_interpreter.WasInterrupted()) break; - Module *m = target->GetImages().GetModulePointerAtIndex(image_idx); - if (SymbolFile *sf = m->GetSymbolFile()) + if (SymbolFile *sf = module_sp->GetSymbolFile()) sf->DumpClangAST(result.GetOutputStream()); } result.SetStatus(eReturnStatusSuccessFinishResult); @@ -2269,23 +2274,19 @@ protected: 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 { + if (num_modules == 0) { result.AppendError("the target has no associated executable images"); result.SetStatus(eReturnStatusFailed); return false; } + result.GetOutputStream().Format( + "Dumping debug symbols for {0} modules.\n", num_modules); + for (ModuleSP module_sp : target_modules.ModulesNoLocking()) { + if (m_interpreter.WasInterrupted()) + break; + if (DumpModuleSymbolFile(result.GetOutputStream(), module_sp.get())) + num_dumped++; + } } else { // Dump specified images (by basename or fullpath) const char *arg_cstr; @@ -2363,15 +2364,13 @@ protected: 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) { + if (target_modules.GetSize() > 0) { uint32_t num_dumped = 0; - for (uint32_t i = 0; i < num_modules; ++i) { + for (ModuleSP module_sp : target_modules.ModulesNoLocking()) { if (m_interpreter.WasInterrupted()) break; if (DumpCompileUnitLineTable( - m_interpreter, result.GetOutputStream(), - target_modules.GetModulePointerAtIndexUnlocked(i), + m_interpreter, result.GetOutputStream(), module_sp.get(), file_spec, m_options.m_verbose ? eDescriptionLevelFull : eDescriptionLevelBrief)) @@ -3409,10 +3408,35 @@ protected: continue; result.GetOutputStream().Printf( - "UNWIND PLANS for %s`%s (start addr 0x%" PRIx64 ")\n\n", + "UNWIND PLANS for %s`%s (start addr 0x%" PRIx64 ")\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr); + Args args; + target->GetUserSpecifiedTrapHandlerNames(args); + size_t count = args.GetArgumentCount(); + for (size_t i = 0; i < count; i++) { + const char *trap_func_name = args.GetArgumentAtIndex(i); + if (strcmp(funcname.GetCString(), trap_func_name) == 0) + result.GetOutputStream().Printf( + "This function is " + "treated as a trap handler function via user setting.\n"); + } + PlatformSP platform_sp(target->GetPlatform()); + if (platform_sp) { + const std::vector<ConstString> trap_handler_names( + platform_sp->GetTrapHandlerSymbolNames()); + for (ConstString trap_name : trap_handler_names) { + if (trap_name == funcname) { + result.GetOutputStream().Printf( + "This function's " + "name is listed by the platform as a trap handler.\n"); + } + } + } + + result.GetOutputStream().Printf("\n"); + UnwindPlanSP non_callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtNonCallSite(*target, *thread); if (non_callsite_unwind_plan) { @@ -3745,9 +3769,9 @@ public: 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)) { + if (LookupTypeHere(&GetSelectedTarget(), m_interpreter, + result.GetOutputStream(), *sym_ctx.module_sp, + m_options.m_str.c_str(), m_options.m_use_regex)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } @@ -3817,9 +3841,9 @@ public: 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)) { + if (LookupTypeInModule( + &GetSelectedTarget(), m_interpreter, result.GetOutputStream(), + module, m_options.m_str.c_str(), m_options.m_use_regex)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } @@ -3868,25 +3892,20 @@ protected: 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 { + if (target_modules.GetSize() == 0) { result.AppendError("the target has no associated executable images"); result.SetStatus(eReturnStatusFailed); return false; } + + for (ModuleSP module_sp : target_modules.ModulesNoLocking()) { + if (module_sp != current_module && + LookupInModule(m_interpreter, module_sp.get(), result, + syntax_error)) { + result.GetOutputStream().EOL(); + num_successful_lookups++; + } + } } else { // Dump specified images (by basename or fullpath) const char *arg_cstr; @@ -4332,7 +4351,6 @@ protected: module_spec.GetSymbolFileSpec() = symfile_spec; } - ArchSpec arch; bool symfile_exists = FileSystem::Instance().Exists(module_spec.GetSymbolFileSpec()); @@ -4405,10 +4423,10 @@ private: class CommandObjectTargetStopHookAdd : public CommandObjectParsed, public IOHandlerDelegateMultiline { public: - class CommandOptions : public Options { + class CommandOptions : public OptionGroup { public: CommandOptions() - : Options(), m_line_start(0), m_line_end(UINT_MAX), + : OptionGroup(), 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() {} @@ -4422,7 +4440,8 @@ public: 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; + const int short_option = + g_target_stop_hook_add_options[option_idx].short_option; switch (short_option) { case 'c': @@ -4552,20 +4571,75 @@ public: // 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.", + "Add a hook to be executed when the target stops." + "The hook can either be a list of commands or an " + "appropriately defined Python class. You can also " + "add filters so the hook only runs a certain stop " + "points.", "target stop-hook add"), IOHandlerDelegateMultiline("DONE", IOHandlerDelegate::Completion::LLDBCommand), - m_options() {} + m_options(), m_python_class_options("scripted stop-hook", true, 'P') { + SetHelpLong( + R"( +Command Based stop-hooks: +------------------------- + Stop hooks can run a list of lldb commands by providing one or more + --one-line-command options. The commands will get run in the order they are + added. Or you can provide no commands, in which case you will enter a + command editor where you can enter the commands to be run. + +Python Based Stop Hooks: +------------------------ + Stop hooks can be implemented with a suitably defined Python class, whose name + is passed in the --python-class option. + + When the stop hook is added, the class is initialized by calling: + + def __init__(self, target, extra_args, dict): + + target: The target that the stop hook is being added to. + extra_args: An SBStructuredData Dictionary filled with the -key -value + option pairs passed to the command. + dict: An implementation detail provided by lldb. + + Then when the stop-hook triggers, lldb will run the 'handle_stop' method. + The method has the signature: + + def handle_stop(self, exe_ctx, stream): + + exe_ctx: An SBExecutionContext for the thread that has stopped. + stream: An SBStream, anything written to this stream will be printed in the + the stop message when the process stops. + + Return Value: The method returns "should_stop". If should_stop is false + from all the stop hook executions on threads that stopped + with a reason, then the process will continue. Note that this + will happen only after all the stop hooks are run. + +Filter Options: +--------------- + Stop hooks can be set to always run, or to only run when the stopped thread + matches the filter options passed on the command line. The available filter + options include a shared library or a thread or queue specification, + a line range in a source file, a function name or a class name. + )"); + m_all_options.Append(&m_python_class_options, + LLDB_OPT_SET_1 | LLDB_OPT_SET_2, + LLDB_OPT_SET_FROM_TO(4, 6)); + m_all_options.Append(&m_options); + m_all_options.Finalize(); + } ~CommandObjectTargetStopHookAdd() override = default; - Options *GetOptions() override { return &m_options; } + Options *GetOptions() override { return &m_all_options; } protected: void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { @@ -4589,10 +4663,15 @@ protected: error_sp->Flush(); } Target *target = GetDebugger().GetSelectedTarget().get(); - if (target) - target->RemoveStopHookByID(m_stop_hook_sp->GetID()); + if (target) { + target->UndoCreateStopHook(m_stop_hook_sp->GetID()); + } } else { - m_stop_hook_sp->GetCommandPointer()->SplitIntoLines(line); + // The IOHandler editor is only for command lines stop hooks: + Target::StopHookCommandLine *hook_ptr = + static_cast<Target::StopHookCommandLine *>(m_stop_hook_sp.get()); + + hook_ptr->SetActionFromString(line); StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); if (output_sp) { output_sp->Printf("Stop hook #%" PRIu64 " added.\n", @@ -4609,7 +4688,10 @@ protected: m_stop_hook_sp.reset(); Target &target = GetSelectedOrDummyTarget(); - Target::StopHookSP new_hook_sp = target.CreateStopHook(); + Target::StopHookSP new_hook_sp = + target.CreateStopHook(m_python_class_options.GetName().empty() ? + Target::StopHook::StopHookKind::CommandBased + : Target::StopHook::StopHookKind::ScriptBased); // First step, make the specifier. std::unique_ptr<SymbolContextSpecifier> specifier_up; @@ -4678,11 +4760,30 @@ protected: 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()); + // This is a command line stop hook: + Target::StopHookCommandLine *hook_ptr = + static_cast<Target::StopHookCommandLine *>(new_hook_sp.get()); + hook_ptr->SetActionFromStrings(m_options.m_one_liner); result.AppendMessageWithFormat("Stop hook #%" PRIu64 " added.\n", new_hook_sp->GetID()); + } else if (!m_python_class_options.GetName().empty()) { + // This is a scripted stop hook: + Target::StopHookScripted *hook_ptr = + static_cast<Target::StopHookScripted *>(new_hook_sp.get()); + Status error = hook_ptr->SetScriptCallback( + m_python_class_options.GetName(), + m_python_class_options.GetStructuredData()); + if (error.Success()) + result.AppendMessageWithFormat("Stop hook #%" PRIu64 " added.\n", + new_hook_sp->GetID()); + else { + // FIXME: Set the stop hook ID counter back. + result.AppendErrorWithFormat("Couldn't add stop hook: %s", + error.AsCString()); + result.SetStatus(eReturnStatusFailed); + target.UndoCreateStopHook(new_hook_sp->GetID()); + return false; + } } else { m_stop_hook_sp = new_hook_sp; m_interpreter.GetLLDBCommandsFromIOHandler("> ", // Prompt @@ -4695,6 +4796,9 @@ protected: private: CommandOptions m_options; + OptionGroupPythonClassWithDict m_python_class_options; + OptionGroupOptions m_all_options; + Target::StopHookSP m_stop_hook_sp; }; @@ -4711,6 +4815,14 @@ public: ~CommandObjectTargetStopHookDelete() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eStopHookIDCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target &target = GetSelectedOrDummyTarget(); @@ -4759,6 +4871,16 @@ public: ~CommandObjectTargetStopHookEnableDisable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eStopHookIDCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target &target = GetSelectedOrDummyTarget(); diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp index f0ad1798fec6..f4ce5cc599cb 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp @@ -8,6 +8,10 @@ #include "CommandObjectThread.h" +#include <sstream> + +#include "CommandObjectThreadUtil.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/ValueObject.h" #include "lldb/Host/OptionParser.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -26,207 +30,12 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlanStepInRange.h" +#include "lldb/Target/Trace.h" #include "lldb/Utility/State.h" using namespace lldb; using namespace lldb_private; -// CommandObjectIterateOverThreads - -class CommandObjectIterateOverThreads : public CommandObjectParsed { - - class UniqueStack { - - public: - UniqueStack(std::stack<lldb::addr_t> stack_frames, uint32_t thread_index_id) - : m_stack_frames(stack_frames) { - m_thread_index_ids.push_back(thread_index_id); - } - - void AddThread(uint32_t thread_index_id) const { - m_thread_index_ids.push_back(thread_index_id); - } - - const std::vector<uint32_t> &GetUniqueThreadIndexIDs() const { - return m_thread_index_ids; - } - - lldb::tid_t GetRepresentativeThread() const { - return m_thread_index_ids.front(); - } - - friend bool inline operator<(const UniqueStack &lhs, - const UniqueStack &rhs) { - return lhs.m_stack_frames < rhs.m_stack_frames; - } - - protected: - // Mark the thread index as mutable, as we don't care about it from a const - // perspective, we only care about m_stack_frames so we keep our std::set - // sorted. - mutable std::vector<uint32_t> m_thread_index_ids; - std::stack<lldb::addr_t> m_stack_frames; - }; - -public: - CommandObjectIterateOverThreads(CommandInterpreter &interpreter, - const char *name, const char *help, - const char *syntax, uint32_t flags) - : CommandObjectParsed(interpreter, name, help, syntax, flags) {} - - ~CommandObjectIterateOverThreads() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - result.SetStatus(m_success_return); - - bool all_threads = false; - if (command.GetArgumentCount() == 0) { - Thread *thread = m_exe_ctx.GetThreadPtr(); - if (!thread || !HandleOneThread(thread->GetID(), result)) - return false; - return result.Succeeded(); - } else if (command.GetArgumentCount() == 1) { - all_threads = ::strcmp(command.GetArgumentAtIndex(0), "all") == 0; - m_unique_stacks = ::strcmp(command.GetArgumentAtIndex(0), "unique") == 0; - } - - // Use tids instead of ThreadSPs to prevent deadlocking problems which - // result from JIT-ing code while iterating over the (locked) ThreadSP - // list. - std::vector<lldb::tid_t> tids; - - if (all_threads || m_unique_stacks) { - Process *process = m_exe_ctx.GetProcessPtr(); - - for (ThreadSP thread_sp : process->Threads()) - tids.push_back(thread_sp->GetID()); - } else { - const size_t num_args = command.GetArgumentCount(); - Process *process = m_exe_ctx.GetProcessPtr(); - - std::lock_guard<std::recursive_mutex> guard( - process->GetThreadList().GetMutex()); - - for (size_t i = 0; i < num_args; i++) { - uint32_t thread_idx; - if (!llvm::to_integer(command.GetArgumentAtIndex(i), thread_idx)) { - result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", - command.GetArgumentAtIndex(i)); - result.SetStatus(eReturnStatusFailed); - return false; - } - - ThreadSP thread = - process->GetThreadList().FindThreadByIndexID(thread_idx); - - if (!thread) { - result.AppendErrorWithFormat("no thread with index: \"%s\"\n", - command.GetArgumentAtIndex(i)); - result.SetStatus(eReturnStatusFailed); - return false; - } - - tids.push_back(thread->GetID()); - } - } - - if (m_unique_stacks) { - // Iterate over threads, finding unique stack buckets. - std::set<UniqueStack> unique_stacks; - for (const lldb::tid_t &tid : tids) { - if (!BucketThread(tid, unique_stacks, result)) { - return false; - } - } - - // Write the thread id's and unique call stacks to the output stream - Stream &strm = result.GetOutputStream(); - Process *process = m_exe_ctx.GetProcessPtr(); - for (const UniqueStack &stack : unique_stacks) { - // List the common thread ID's - const std::vector<uint32_t> &thread_index_ids = - stack.GetUniqueThreadIndexIDs(); - strm.Format("{0} thread(s) ", thread_index_ids.size()); - for (const uint32_t &thread_index_id : thread_index_ids) { - strm.Format("#{0} ", thread_index_id); - } - strm.EOL(); - - // List the shared call stack for this set of threads - uint32_t representative_thread_id = stack.GetRepresentativeThread(); - ThreadSP thread = process->GetThreadList().FindThreadByIndexID( - representative_thread_id); - if (!HandleOneThread(thread->GetID(), result)) { - return false; - } - } - } else { - uint32_t idx = 0; - for (const lldb::tid_t &tid : tids) { - if (idx != 0 && m_add_return) - result.AppendMessage(""); - - if (!HandleOneThread(tid, result)) - return false; - - ++idx; - } - } - return result.Succeeded(); - } - -protected: - // Override this to do whatever you need to do for one thread. - // - // If you return false, the iteration will stop, otherwise it will proceed. - // The result is set to m_success_return (defaults to - // eReturnStatusSuccessFinishResult) before the iteration, so you only need - // to set the return status in HandleOneThread if you want to indicate an - // error. If m_add_return is true, a blank line will be inserted between each - // of the listings (except the last one.) - - virtual bool HandleOneThread(lldb::tid_t, CommandReturnObject &result) = 0; - - bool BucketThread(lldb::tid_t tid, std::set<UniqueStack> &unique_stacks, - CommandReturnObject &result) { - // Grab the corresponding thread for the given thread id. - Process *process = m_exe_ctx.GetProcessPtr(); - Thread *thread = process->GetThreadList().FindThreadByID(tid).get(); - if (thread == nullptr) { - result.AppendErrorWithFormatv("Failed to process thread #{0}.\n", tid); - result.SetStatus(eReturnStatusFailed); - return false; - } - - // Collect the each frame's address for this call-stack - std::stack<lldb::addr_t> stack_frames; - const uint32_t frame_count = thread->GetStackFrameCount(); - for (uint32_t frame_index = 0; frame_index < frame_count; frame_index++) { - const lldb::StackFrameSP frame_sp = - thread->GetStackFrameAtIndex(frame_index); - const lldb::addr_t pc = frame_sp->GetStackID().GetPC(); - stack_frames.push(pc); - } - - uint32_t thread_index_id = thread->GetIndexID(); - UniqueStack new_unique_stack(stack_frames, thread_index_id); - - // Try to match the threads stack to and existing entry. - std::set<UniqueStack>::iterator matching_stack = - unique_stacks.find(new_unique_stack); - if (matching_stack != unique_stacks.end()) { - matching_stack->AddThread(thread_index_id); - } else { - unique_stacks.insert(new_unique_stack); - } - return true; - } - - ReturnStatus m_success_return = eReturnStatusSuccessFinishResult; - bool m_unique_stacks = false; - bool m_add_return = true; -}; - // CommandObjectThreadBacktrace #define LLDB_OPTIONS_thread_backtrace #include "CommandOptions.inc" @@ -482,8 +291,16 @@ public: // Check if we are in Non-Stop mode TargetSP target_sp = execution_context ? execution_context->GetTargetSP() : TargetSP(); - if (target_sp && target_sp->GetNonStopModeEnabled()) + if (target_sp && target_sp->GetNonStopModeEnabled()) { + // NonStopMode runs all threads by definition, so when it is on we don't + // need to check the process setting for runs all threads. m_run_mode = eOnlyThisThread; + } else { + ProcessSP process_sp = + execution_context ? execution_context->GetProcessSP() : ProcessSP(); + if (process_sp && process_sp->GetSteppingRunsAllThreads()) + m_run_mode = eAllThreads; + } m_avoid_regexp.clear(); m_step_in_target.clear(); @@ -541,6 +358,17 @@ public: ~CommandObjectThreadStepWithTypeAndScope() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_all_options; } protected: @@ -612,8 +440,7 @@ protected: if (m_options.m_run_mode == eAllThreads) bool_stop_other_threads = false; else if (m_options.m_run_mode == eOnlyDuringStepping) - bool_stop_other_threads = - (m_step_type != eStepTypeOut && m_step_type != eStepTypeScripted); + bool_stop_other_threads = (m_step_type != eStepTypeOut); else bool_stop_other_threads = true; @@ -808,6 +635,14 @@ public: ~CommandObjectThreadContinue() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + bool DoExecute(Args &command, CommandReturnObject &result) override { bool synchronous_execution = m_interpreter.GetSynchronous(); @@ -1300,6 +1135,17 @@ public: ~CommandObjectThreadSelect() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Process *process = m_exe_ctx.GetProcessPtr(); @@ -1431,6 +1277,14 @@ public: ~CommandObjectThreadInfo() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_options; } bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { @@ -1475,6 +1329,14 @@ public: ~CommandObjectThreadException() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { ThreadSP thread_sp = m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); @@ -1929,8 +1791,7 @@ public: protected: bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { // If we have already handled this from a -t option, skip it here. - if (std::find(m_options.m_tids.begin(), m_options.m_tids.end(), tid) != - m_options.m_tids.end()) + if (llvm::is_contained(m_options.m_tids, tid)) return true; Process *process = m_exe_ctx.GetProcessPtr(); @@ -1978,6 +1839,15 @@ public: ~CommandObjectThreadPlanDiscard() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_exe_ctx.HasThreadScope() || request.GetCursorIndex()) + return; + + m_exe_ctx.GetThreadPtr()->AutoCompleteThreadPlans(request); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { Thread *thread = m_exe_ctx.GetThreadPtr(); if (args.GetArgumentCount() != 1) { @@ -2104,6 +1974,271 @@ public: ~CommandObjectMultiwordThreadPlan() override = default; }; +// Next are the subcommands of CommandObjectMultiwordTrace + +// CommandObjectTraceStart + +/// This class works by delegating the logic to the actual trace plug-in that +/// can support the current process. +class CommandObjectTraceStart : public CommandObjectProxy { +public: + CommandObjectTraceStart(CommandInterpreter &interpreter) + : CommandObjectProxy(interpreter, "thread trace start", + "Start tracing threads with the corresponding trace " + "plug-in for the current process.", + "thread trace start [<trace-options>]") {} + +protected: + llvm::Expected<CommandObjectSP> DoGetProxyCommandObject() { + ProcessSP process_sp = m_interpreter.GetExecutionContext().GetProcessSP(); + + if (!process_sp) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Process not available."); + if (!process_sp->IsAlive()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Process must be launched."); + + llvm::Expected<TraceTypeInfo> trace_type = + process_sp->GetSupportedTraceType(); + + if (!trace_type) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), "Tracing is not supported. %s", + llvm::toString(trace_type.takeError()).c_str()); + + CommandObjectSP delegate_sp = + PluginManager::GetTraceStartCommand(trace_type->name, m_interpreter); + if (!delegate_sp) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "No trace plug-in matches the specified type: \"%s\"", + trace_type->name.c_str()); + return delegate_sp; + } + + CommandObject *GetProxyCommandObject() override { + if (llvm::Expected<CommandObjectSP> delegate = DoGetProxyCommandObject()) { + m_delegate_sp = *delegate; + m_delegate_error.clear(); + return m_delegate_sp.get(); + } else { + m_delegate_sp.reset(); + m_delegate_error = llvm::toString(delegate.takeError()); + return nullptr; + } + } + +private: + llvm::StringRef GetUnsupportedError() override { return m_delegate_error; } + + CommandObjectSP m_delegate_sp; + std::string m_delegate_error; +}; + +// CommandObjectTraceStop + +class CommandObjectTraceStop : public CommandObjectIterateOverThreads { +public: + CommandObjectTraceStop(CommandInterpreter &interpreter) + : CommandObjectIterateOverThreads( + interpreter, "thread trace stop", + "Stop tracing threads. " + "Defaults to the current thread. Thread indices can be " + "specified as arguments.\n Use the thread-index \"all\" to trace " + "all threads.", + "thread trace stop [<thread-index> <thread-index> ...]", + eCommandRequiresProcess | eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | + eCommandProcessMustBeTraced) {} + + ~CommandObjectTraceStop() override = default; + + bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { + const Thread &thread = + *m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); + Trace &trace = *m_exe_ctx.GetTargetSP()->GetTrace(); + + if (llvm::Error err = trace.StopTracingThread(thread)) { + result.AppendErrorWithFormat("Failed stopping thread %" PRIu64 ": %s\n", + tid, toString(std::move(err)).c_str()); + result.SetStatus(eReturnStatusFailed); + } + + // We don't return false on errors to try to stop as many threads as + // possible. + return true; + } +}; + +// CommandObjectTraceDumpInstructions +#define LLDB_OPTIONS_thread_trace_dump_instructions +#include "CommandOptions.inc" + +class CommandObjectTraceDumpInstructions + : public CommandObjectIterateOverThreads { +public: + 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 'c': { + int32_t count; + if (option_arg.empty() || option_arg.getAsInteger(0, count) || + count < 0) + error.SetErrorStringWithFormat( + "invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_count = count; + break; + } + case 'p': { + int32_t position; + if (option_arg.empty() || option_arg.getAsInteger(0, position) || + position < 0) + error.SetErrorStringWithFormat( + "invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_position = position; + break; + } + case 'r': { + m_raw = true; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_count = kDefaultCount; + m_position = llvm::None; + m_raw = false; + } + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_thread_trace_dump_instructions_options); + } + + static const size_t kDefaultCount = 20; + + // Instance variables to hold the values for command options. + size_t m_count; + llvm::Optional<ssize_t> m_position; + bool m_raw; + }; + + CommandObjectTraceDumpInstructions(CommandInterpreter &interpreter) + : CommandObjectIterateOverThreads( + interpreter, "thread trace dump instructions", + "Dump the traced instructions for one or more threads. If no " + "threads are specified, show the current thread. Use the " + "thread-index \"all\" to see all threads.", + nullptr, + eCommandRequiresProcess | eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | + eCommandProcessMustBeTraced), + m_options(), m_create_repeat_command_just_invoked(false) {} + + ~CommandObjectTraceDumpInstructions() override = default; + + Options *GetOptions() override { return &m_options; } + + const char *GetRepeatCommand(Args ¤t_command_args, + uint32_t index) override { + current_command_args.GetCommandString(m_repeat_command); + m_create_repeat_command_just_invoked = true; + m_consecutive_repetitions = 0; + return m_repeat_command.c_str(); + } + +protected: + bool DoExecute(Args &args, CommandReturnObject &result) override { + if (IsRepeatCommand()) + m_consecutive_repetitions++; + bool status = CommandObjectIterateOverThreads::DoExecute(args, result); + + m_create_repeat_command_just_invoked = false; + return status; + } + + bool IsRepeatCommand() { + return !m_repeat_command.empty() && !m_create_repeat_command_just_invoked; + } + + bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { + const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace(); + ThreadSP thread_sp = + m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); + + size_t count = m_options.m_count; + ssize_t position = m_options.m_position.getValueOr( + trace_sp->GetCursorPosition(*thread_sp)) - + m_consecutive_repetitions * count; + if (position < 0) + result.SetError("error: no more data"); + else + trace_sp->DumpTraceInstructions(*thread_sp, result.GetOutputStream(), + count, position, m_options.m_raw); + return true; + } + + CommandOptions m_options; + + // Repeat command helpers + std::string m_repeat_command; + bool m_create_repeat_command_just_invoked; + size_t m_consecutive_repetitions = 0; +}; + +// CommandObjectMultiwordTraceDump +class CommandObjectMultiwordTraceDump : public CommandObjectMultiword { +public: + CommandObjectMultiwordTraceDump(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "dump", + "Commands for displaying trace information of the threads " + "in the current process.", + "thread trace dump <subcommand> [<subcommand objects>]") { + LoadSubCommand( + "instructions", + CommandObjectSP(new CommandObjectTraceDumpInstructions(interpreter))); + } + ~CommandObjectMultiwordTraceDump() override = default; +}; + +// CommandObjectMultiwordTrace +class CommandObjectMultiwordTrace : public CommandObjectMultiword { +public: + CommandObjectMultiwordTrace(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "trace", + "Commands for operating on traces of the threads in the current " + "process.", + "thread trace <subcommand> [<subcommand objects>]") { + LoadSubCommand("dump", CommandObjectSP(new CommandObjectMultiwordTraceDump( + interpreter))); + LoadSubCommand("start", + CommandObjectSP(new CommandObjectTraceStart(interpreter))); + LoadSubCommand("stop", + CommandObjectSP(new CommandObjectTraceStop(interpreter))); + } + + ~CommandObjectMultiwordTrace() override = default; +}; + // CommandObjectMultiwordThread CommandObjectMultiwordThread::CommandObjectMultiwordThread( @@ -2179,6 +2314,8 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread( LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan( interpreter))); + LoadSubCommand("trace", + CommandObjectSP(new CommandObjectMultiwordTrace(interpreter))); } CommandObjectMultiwordThread::~CommandObjectMultiwordThread() = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.cpp new file mode 100644 index 000000000000..b93698c7be60 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.cpp @@ -0,0 +1,158 @@ +//===-- CommandObjectThreadUtil.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 "CommandObjectThreadUtil.h" + +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +CommandObjectIterateOverThreads::CommandObjectIterateOverThreads( + CommandInterpreter &interpreter, const char *name, const char *help, + const char *syntax, uint32_t flags) + : CommandObjectParsed(interpreter, name, help, syntax, flags) {} + +bool CommandObjectIterateOverThreads::DoExecute(Args &command, + CommandReturnObject &result) { + result.SetStatus(m_success_return); + + bool all_threads = false; + if (command.GetArgumentCount() == 0) { + Thread *thread = m_exe_ctx.GetThreadPtr(); + if (!thread || !HandleOneThread(thread->GetID(), result)) + return false; + return result.Succeeded(); + } else if (command.GetArgumentCount() == 1) { + all_threads = ::strcmp(command.GetArgumentAtIndex(0), "all") == 0; + m_unique_stacks = ::strcmp(command.GetArgumentAtIndex(0), "unique") == 0; + } + + // Use tids instead of ThreadSPs to prevent deadlocking problems which + // result from JIT-ing code while iterating over the (locked) ThreadSP + // list. + std::vector<lldb::tid_t> tids; + + if (all_threads || m_unique_stacks) { + Process *process = m_exe_ctx.GetProcessPtr(); + + for (ThreadSP thread_sp : process->Threads()) + tids.push_back(thread_sp->GetID()); + } else { + const size_t num_args = command.GetArgumentCount(); + Process *process = m_exe_ctx.GetProcessPtr(); + + std::lock_guard<std::recursive_mutex> guard( + process->GetThreadList().GetMutex()); + + for (size_t i = 0; i < num_args; i++) { + uint32_t thread_idx; + if (!llvm::to_integer(command.GetArgumentAtIndex(i), thread_idx)) { + result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", + command.GetArgumentAtIndex(i)); + result.SetStatus(eReturnStatusFailed); + return false; + } + + ThreadSP thread = + process->GetThreadList().FindThreadByIndexID(thread_idx); + + if (!thread) { + result.AppendErrorWithFormat("no thread with index: \"%s\"\n", + command.GetArgumentAtIndex(i)); + result.SetStatus(eReturnStatusFailed); + return false; + } + + tids.push_back(thread->GetID()); + } + } + + if (m_unique_stacks) { + // Iterate over threads, finding unique stack buckets. + std::set<UniqueStack> unique_stacks; + for (const lldb::tid_t &tid : tids) { + if (!BucketThread(tid, unique_stacks, result)) { + return false; + } + } + + // Write the thread id's and unique call stacks to the output stream + Stream &strm = result.GetOutputStream(); + Process *process = m_exe_ctx.GetProcessPtr(); + for (const UniqueStack &stack : unique_stacks) { + // List the common thread ID's + const std::vector<uint32_t> &thread_index_ids = + stack.GetUniqueThreadIndexIDs(); + strm.Format("{0} thread(s) ", thread_index_ids.size()); + for (const uint32_t &thread_index_id : thread_index_ids) { + strm.Format("#{0} ", thread_index_id); + } + strm.EOL(); + + // List the shared call stack for this set of threads + uint32_t representative_thread_id = stack.GetRepresentativeThread(); + ThreadSP thread = process->GetThreadList().FindThreadByIndexID( + representative_thread_id); + if (!HandleOneThread(thread->GetID(), result)) { + return false; + } + } + } else { + uint32_t idx = 0; + for (const lldb::tid_t &tid : tids) { + if (idx != 0 && m_add_return) + result.AppendMessage(""); + + if (!HandleOneThread(tid, result)) + return false; + + ++idx; + } + } + return result.Succeeded(); +} + +bool CommandObjectIterateOverThreads::BucketThread( + lldb::tid_t tid, std::set<UniqueStack> &unique_stacks, + CommandReturnObject &result) { + // Grab the corresponding thread for the given thread id. + Process *process = m_exe_ctx.GetProcessPtr(); + Thread *thread = process->GetThreadList().FindThreadByID(tid).get(); + if (thread == nullptr) { + result.AppendErrorWithFormatv("Failed to process thread #{0}.\n", tid); + result.SetStatus(eReturnStatusFailed); + return false; + } + + // Collect the each frame's address for this call-stack + std::stack<lldb::addr_t> stack_frames; + const uint32_t frame_count = thread->GetStackFrameCount(); + for (uint32_t frame_index = 0; frame_index < frame_count; frame_index++) { + const lldb::StackFrameSP frame_sp = + thread->GetStackFrameAtIndex(frame_index); + const lldb::addr_t pc = frame_sp->GetStackID().GetPC(); + stack_frames.push(pc); + } + + uint32_t thread_index_id = thread->GetIndexID(); + UniqueStack new_unique_stack(stack_frames, thread_index_id); + + // Try to match the threads stack to and existing entry. + std::set<UniqueStack>::iterator matching_stack = + unique_stacks.find(new_unique_stack); + if (matching_stack != unique_stacks.end()) { + matching_stack->AddThread(thread_index_id); + } else { + unique_stacks.insert(new_unique_stack); + } + return true; +} diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.h b/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.h new file mode 100644 index 000000000000..7122982d8943 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.h @@ -0,0 +1,81 @@ +//===-- CommandObjectThreadUtil.h -------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTTHREADUTIL_H +#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTTHREADUTIL_H + +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +class CommandObjectIterateOverThreads : public CommandObjectParsed { + + class UniqueStack { + public: + UniqueStack(std::stack<lldb::addr_t> stack_frames, uint32_t thread_index_id) + : m_stack_frames(stack_frames) { + m_thread_index_ids.push_back(thread_index_id); + } + + void AddThread(uint32_t thread_index_id) const { + m_thread_index_ids.push_back(thread_index_id); + } + + const std::vector<uint32_t> &GetUniqueThreadIndexIDs() const { + return m_thread_index_ids; + } + + lldb::tid_t GetRepresentativeThread() const { + return m_thread_index_ids.front(); + } + + friend bool inline operator<(const UniqueStack &lhs, + const UniqueStack &rhs) { + return lhs.m_stack_frames < rhs.m_stack_frames; + } + + protected: + // Mark the thread index as mutable, as we don't care about it from a const + // perspective, we only care about m_stack_frames so we keep our std::set + // sorted. + mutable std::vector<uint32_t> m_thread_index_ids; + std::stack<lldb::addr_t> m_stack_frames; + }; + +public: + CommandObjectIterateOverThreads(CommandInterpreter &interpreter, + const char *name, const char *help, + const char *syntax, uint32_t flags); + + ~CommandObjectIterateOverThreads() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override; + +protected: + // Override this to do whatever you need to do for one thread. + // + // If you return false, the iteration will stop, otherwise it will proceed. + // The result is set to m_success_return (defaults to + // eReturnStatusSuccessFinishResult) before the iteration, so you only need + // to set the return status in HandleOneThread if you want to indicate an + // error. If m_add_return is true, a blank line will be inserted between each + // of the listings (except the last one.) + + virtual bool HandleOneThread(lldb::tid_t, CommandReturnObject &result) = 0; + + bool BucketThread(lldb::tid_t tid, std::set<UniqueStack> &unique_stacks, + CommandReturnObject &result); + + lldb::ReturnStatus m_success_return = lldb::eReturnStatusSuccessFinishResult; + bool m_unique_stacks = false; + bool m_add_return = true; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTTHREADUTIL_H diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectTrace.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectTrace.cpp new file mode 100644 index 000000000000..170630b85b2e --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectTrace.cpp @@ -0,0 +1,305 @@ +//===-- CommandObjectTrace.cpp --------------------------------------------===// +// +// 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 "CommandObjectTrace.h" + +#include "llvm/Support/JSON.h" +#include "llvm/Support/MemoryBuffer.h" + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionGroupFormat.h" +#include "lldb/Interpreter/OptionValueBoolean.h" +#include "lldb/Interpreter/OptionValueLanguage.h" +#include "lldb/Interpreter/OptionValueString.h" +#include "lldb/Interpreter/Options.h" +#include "lldb/Target/Trace.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +// CommandObjectTraceLoad +#define LLDB_OPTIONS_trace_load +#include "CommandOptions.inc" + +#pragma mark CommandObjectTraceLoad + +class CommandObjectTraceLoad : public CommandObjectParsed { +public: + class CommandOptions : public Options { + public: + CommandOptions() : Options() { OptionParsingStarting(nullptr); } + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'v': { + m_verbose = true; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_verbose = false; + } + + ArrayRef<OptionDefinition> GetDefinitions() override { + return makeArrayRef(g_trace_load_options); + } + + bool m_verbose; // Enable verbose logging for debugging purposes. + }; + + CommandObjectTraceLoad(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "trace load", + "Load a processor trace session from a JSON file.", + "trace load"), + m_options() {} + + ~CommandObjectTraceLoad() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (command.size() != 1) { + result.AppendError( + "a single path to a JSON file containing a trace session" + "is required"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + auto end_with_failure = [&result](llvm::Error err) -> bool { + result.AppendErrorWithFormat("%s\n", + llvm::toString(std::move(err)).c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + }; + + FileSpec json_file(command[0].ref()); + + auto buffer_or_error = llvm::MemoryBuffer::getFile(json_file.GetPath()); + if (!buffer_or_error) { + return end_with_failure(llvm::createStringError( + std::errc::invalid_argument, "could not open input file: %s - %s.", + json_file.GetPath().c_str(), + buffer_or_error.getError().message().c_str())); + } + + llvm::Expected<json::Value> session_file = + json::parse(buffer_or_error.get()->getBuffer().str()); + if (!session_file) + return end_with_failure(session_file.takeError()); + + if (Expected<lldb::TraceSP> traceOrErr = + Trace::FindPlugin(GetDebugger(), *session_file, + json_file.GetDirectory().AsCString())) { + lldb::TraceSP trace_sp = traceOrErr.get(); + if (m_options.m_verbose) + result.AppendMessageWithFormat("loading trace with plugin %s\n", + trace_sp->GetPluginName().AsCString()); + } else + return end_with_failure(traceOrErr.takeError()); + + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + + CommandOptions m_options; +}; + +// CommandObjectTraceDump +#define LLDB_OPTIONS_trace_dump +#include "CommandOptions.inc" + +#pragma mark CommandObjectTraceDump + +class CommandObjectTraceDump : public CommandObjectParsed { +public: + 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 'v': { + m_verbose = true; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_verbose = false; + } + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_trace_dump_options); + } + + bool m_verbose; // Enable verbose logging for debugging purposes. + }; + + CommandObjectTraceDump(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "trace dump", + "Dump the loaded processor trace data.", + "trace dump"), + m_options() {} + + ~CommandObjectTraceDump() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + Status error; + // TODO: fill in the dumping code here! + if (error.Success()) { + result.SetStatus(eReturnStatusSuccessFinishResult); + } else { + result.AppendErrorWithFormat("%s\n", error.AsCString()); + result.SetStatus(eReturnStatusFailed); + } + return result.Succeeded(); + } + + CommandOptions m_options; +}; + +// CommandObjectTraceSchema +#define LLDB_OPTIONS_trace_schema +#include "CommandOptions.inc" + +#pragma mark CommandObjectTraceSchema + +class CommandObjectTraceSchema : public CommandObjectParsed { +public: + 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 'v': { + m_verbose = true; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_verbose = false; + } + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_trace_schema_options); + } + + bool m_verbose; // Enable verbose logging for debugging purposes. + }; + + CommandObjectTraceSchema(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "trace schema", + "Show the schema of the given trace plugin.", + "trace schema <plug-in>. Use the plug-in name " + "\"all\" to see all schemas.\n"), + m_options() {} + + ~CommandObjectTraceSchema() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + Status error; + if (command.empty()) { + result.SetError( + "trace schema cannot be invoked without a plug-in as argument"); + return false; + } + + StringRef plugin_name(command[0].c_str()); + if (plugin_name == "all") { + size_t index = 0; + while (true) { + StringRef schema = PluginManager::GetTraceSchema(index++); + if (schema.empty()) + break; + + result.AppendMessage(schema); + } + } else { + if (Expected<StringRef> schemaOrErr = + Trace::FindPluginSchema(plugin_name)) + result.AppendMessage(*schemaOrErr); + else + error = schemaOrErr.takeError(); + } + + if (error.Success()) { + result.SetStatus(eReturnStatusSuccessFinishResult); + } else { + result.AppendErrorWithFormat("%s\n", error.AsCString()); + result.SetStatus(eReturnStatusFailed); + } + return result.Succeeded(); + } + + CommandOptions m_options; +}; + +// CommandObjectTrace + +CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "trace", + "Commands for loading and using processor " + "trace information.", + "trace [<sub-command-options>]") { + LoadSubCommand("load", + CommandObjectSP(new CommandObjectTraceLoad(interpreter))); + LoadSubCommand("dump", + CommandObjectSP(new CommandObjectTraceDump(interpreter))); + LoadSubCommand("schema", + CommandObjectSP(new CommandObjectTraceSchema(interpreter))); +} + +CommandObjectTrace::~CommandObjectTrace() = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectTrace.h b/contrib/llvm-project/lldb/source/Commands/CommandObjectTrace.h new file mode 100644 index 000000000000..2dca0e26b243 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectTrace.h @@ -0,0 +1,25 @@ +//===-- CommandObjectTrace.h ------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTTRACE_H +#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTTRACE_H + +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +class CommandObjectTrace : public CommandObjectMultiword { +public: + CommandObjectTrace(CommandInterpreter &interpreter); + + ~CommandObjectTrace() override; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTTRACE_H diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectType.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectType.cpp index b2020f26621f..004c066b57aa 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectType.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectType.cpp @@ -37,6 +37,9 @@ #include <functional> #include <memory> +#define CHECK_FORMATTER_KIND_MASK(VAL) \ + ((m_formatter_kind_mask & (VAL)) == (VAL)) + using namespace lldb; using namespace lldb_private; @@ -777,6 +780,39 @@ public: ~CommandObjectTypeFormatterDelete() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + + DataVisualization::Categories::ForEach( + [this, &request](const lldb::TypeCategoryImplSP &category_sp) { + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemValue)) + category_sp->GetTypeFormatsContainer()->AutoComplete(request); + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemRegexValue)) + category_sp->GetRegexTypeFormatsContainer()->AutoComplete(request); + + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemSummary)) + category_sp->GetTypeSummariesContainer()->AutoComplete(request); + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemRegexSummary)) + category_sp->GetRegexTypeSummariesContainer()->AutoComplete( + request); + + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemFilter)) + category_sp->GetTypeFiltersContainer()->AutoComplete(request); + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemRegexFilter)) + category_sp->GetRegexTypeFiltersContainer()->AutoComplete(request); + + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemSynth)) + category_sp->GetTypeSyntheticsContainer()->AutoComplete(request); + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemRegexSynth)) + category_sp->GetRegexTypeSyntheticsContainer()->AutoComplete( + request); + return true; + }); + } + protected: virtual bool FormatterSpecificDeletion(ConstString typeCS) { return false; } @@ -1066,13 +1102,15 @@ protected: TypeCategoryImpl::ForEachCallbacks<FormatterType> foreach; foreach .SetExact([&result, &formatter_regex, &any_printed]( - ConstString name, + const TypeMatcher &type_matcher, const FormatterSharedPointer &format_sp) -> bool { if (formatter_regex) { bool escape = true; - if (name.GetStringRef() == formatter_regex->GetText()) { + if (type_matcher.CreatedBySameMatchString( + ConstString(formatter_regex->GetText()))) { escape = false; - } else if (formatter_regex->Execute(name.GetStringRef())) { + } else if (formatter_regex->Execute( + type_matcher.GetMatchString().GetStringRef())) { escape = false; } @@ -1081,20 +1119,23 @@ protected: } any_printed = true; - result.GetOutputStream().Printf("%s: %s\n", name.AsCString(), - format_sp->GetDescription().c_str()); + result.GetOutputStream().Printf( + "%s: %s\n", type_matcher.GetMatchString().GetCString(), + format_sp->GetDescription().c_str()); return true; }); foreach .SetWithRegex([&result, &formatter_regex, &any_printed]( - const RegularExpression ®ex, + const TypeMatcher &type_matcher, const FormatterSharedPointer &format_sp) -> bool { if (formatter_regex) { bool escape = true; - if (regex.GetText() == formatter_regex->GetText()) { + if (type_matcher.CreatedBySameMatchString( + ConstString(formatter_regex->GetText()))) { escape = false; - } else if (formatter_regex->Execute(regex.GetText())) { + } else if (formatter_regex->Execute( + type_matcher.GetMatchString().GetStringRef())) { escape = false; } @@ -1103,9 +1144,9 @@ protected: } any_printed = true; - result.GetOutputStream().Printf("%s: %s\n", - regex.GetText().str().c_str(), - format_sp->GetDescription().c_str()); + result.GetOutputStream().Printf( + "%s: %s\n", type_matcher.GetMatchString().GetCString(), + format_sp->GetDescription().c_str()); return true; }); @@ -1681,10 +1722,10 @@ protected: if (DataVisualization::NamedSummaryFormats::GetCount() > 0) { result.GetOutputStream().Printf("Named summaries:\n"); DataVisualization::NamedSummaryFormats::ForEach( - [&result](ConstString name, + [&result](const TypeMatcher &type_matcher, const TypeSummaryImplSP &summary_sp) -> bool { result.GetOutputStream().Printf( - "%s: %s\n", name.AsCString(), + "%s: %s\n", type_matcher.GetMatchString().GetCString(), summary_sp->GetDescription().c_str()); return true; }); @@ -1764,6 +1805,14 @@ public: ~CommandObjectTypeCategoryDefine() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eTypeCategoryNameCompletion, request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -1860,6 +1909,14 @@ public: ~CommandObjectTypeCategoryEnable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eTypeCategoryNameCompletion, request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -1922,6 +1979,14 @@ public: ~CommandObjectTypeCategoryDelete() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eTypeCategoryNameCompletion, request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -2027,6 +2092,14 @@ public: ~CommandObjectTypeCategoryDisable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eTypeCategoryNameCompletion, request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -2084,6 +2157,16 @@ public: ~CommandObjectTypeCategoryList() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eTypeCategoryNameCompletion, request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp index ce4662930a7c..e7b1f31f3960 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -292,6 +292,14 @@ public: ~CommandObjectWatchpointEnable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target *target = &GetSelectedTarget(); @@ -362,6 +370,14 @@ public: ~CommandObjectWatchpointDisable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target *target = &GetSelectedTarget(); @@ -439,6 +455,14 @@ public: ~CommandObjectWatchpointDelete() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_options; } class CommandOptions : public Options { @@ -557,6 +581,14 @@ public: ~CommandObjectWatchpointIgnore() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_options; } class CommandOptions : public Options { @@ -677,6 +709,14 @@ public: ~CommandObjectWatchpointModify() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_options; } class CommandOptions : public Options { @@ -823,6 +863,16 @@ corresponding to the byte size of the data type."); ~CommandObjectWatchpointSetVariable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex() != 0) + return; + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_option_group; } protected: @@ -905,7 +955,7 @@ protected: // We're in business. // Find out the size of this variable. size = m_option_watchpoint.watch_size == 0 - ? valobj_sp->GetByteSize() + ? valobj_sp->GetByteSize().getValueOr(0) : m_option_watchpoint.watch_size; } compiler_type = valobj_sp->GetCompilerType(); diff --git a/contrib/llvm-project/lldb/source/Commands/CommandOptionsProcessLaunch.cpp b/contrib/llvm-project/lldb/source/Commands/CommandOptionsProcessLaunch.cpp new file mode 100644 index 000000000000..4445457ca852 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandOptionsProcessLaunch.cpp @@ -0,0 +1,147 @@ +//===-- CommandOptionsProcessLaunch.cpp -----------------------------------===// +// +// 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 "CommandOptionsProcessLaunch.h" + +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Target.h" + +#include "llvm/ADT/ArrayRef.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +#define LLDB_OPTIONS_process_launch +#include "CommandOptions.inc" + +Status CommandOptionsProcessLaunch::SetOptionValue( + uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 's': // Stop at program entry point + launch_info.GetFlags().Set(eLaunchFlagStopAtEntry); + break; + + case 'i': // STDIN for read only + { + FileAction action; + if (action.Open(STDIN_FILENO, FileSpec(option_arg), true, false)) + launch_info.AppendFileAction(action); + break; + } + + case 'o': // Open STDOUT for write only + { + FileAction action; + if (action.Open(STDOUT_FILENO, FileSpec(option_arg), false, true)) + launch_info.AppendFileAction(action); + break; + } + + case 'e': // STDERR for write only + { + FileAction action; + if (action.Open(STDERR_FILENO, FileSpec(option_arg), false, true)) + launch_info.AppendFileAction(action); + break; + } + + case 'P': // Process plug-in name + launch_info.SetProcessPluginName(option_arg); + break; + + case 'n': // Disable STDIO + { + FileAction action; + const FileSpec dev_null(FileSystem::DEV_NULL); + if (action.Open(STDIN_FILENO, dev_null, true, false)) + launch_info.AppendFileAction(action); + if (action.Open(STDOUT_FILENO, dev_null, false, true)) + launch_info.AppendFileAction(action); + if (action.Open(STDERR_FILENO, dev_null, false, true)) + launch_info.AppendFileAction(action); + break; + } + + case 'w': + launch_info.SetWorkingDirectory(FileSpec(option_arg)); + break; + + case 't': // Open process in new terminal window + launch_info.GetFlags().Set(eLaunchFlagLaunchInTTY); + break; + + case 'a': { + TargetSP target_sp = + execution_context ? execution_context->GetTargetSP() : TargetSP(); + PlatformSP platform_sp = + target_sp ? target_sp->GetPlatform() : PlatformSP(); + launch_info.GetArchitecture() = + Platform::GetAugmentedArchSpec(platform_sp.get(), option_arg); + } break; + + case 'A': // Disable ASLR. + { + bool success; + const bool disable_aslr_arg = + OptionArgParser::ToBoolean(option_arg, true, &success); + if (success) + disable_aslr = disable_aslr_arg ? eLazyBoolYes : eLazyBoolNo; + else + error.SetErrorStringWithFormat( + "Invalid boolean value for disable-aslr option: '%s'", + option_arg.empty() ? "<null>" : option_arg.str().c_str()); + break; + } + + case 'X': // shell expand args. + { + bool success; + const bool expand_args = + OptionArgParser::ToBoolean(option_arg, true, &success); + if (success) + launch_info.SetShellExpandArguments(expand_args); + else + error.SetErrorStringWithFormat( + "Invalid boolean value for shell-expand-args option: '%s'", + option_arg.empty() ? "<null>" : option_arg.str().c_str()); + break; + } + + case 'c': + if (!option_arg.empty()) + launch_info.SetShell(FileSpec(option_arg)); + else + launch_info.SetShell(HostInfo::GetDefaultShell()); + break; + + case 'v': + launch_info.GetEnvironment().insert(option_arg); + break; + + default: + error.SetErrorStringWithFormat("unrecognized short option character '%c'", + short_option); + break; + } + return error; +} + +llvm::ArrayRef<OptionDefinition> CommandOptionsProcessLaunch::GetDefinitions() { + return llvm::makeArrayRef(g_process_launch_options); +} diff --git a/contrib/llvm-project/lldb/source/Commands/CommandOptionsProcessLaunch.h b/contrib/llvm-project/lldb/source/Commands/CommandOptionsProcessLaunch.h new file mode 100644 index 000000000000..4028d8e02cb2 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandOptionsProcessLaunch.h @@ -0,0 +1,49 @@ +//===-- CommandOptionsProcessLaunch.h -------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_COMMANDS_COMMANDOPTIONSPROCESSLAUNCH_H +#define LLDB_SOURCE_COMMANDS_COMMANDOPTIONSPROCESSLAUNCH_H + +#include "lldb/Host/ProcessLaunchInfo.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { + +// CommandOptionsProcessLaunch + +class CommandOptionsProcessLaunch : public lldb_private::Options { +public: + CommandOptionsProcessLaunch() : lldb_private::Options() { + // Keep default values of all options in one place: OptionParsingStarting + // () + OptionParsingStarting(nullptr); + } + + ~CommandOptionsProcessLaunch() override = default; + + lldb_private::Status + SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + lldb_private::ExecutionContext *execution_context) override; + + void OptionParsingStarting( + lldb_private::ExecutionContext *execution_context) override { + launch_info.Clear(); + disable_aslr = lldb_private::eLazyBoolCalculate; + } + + llvm::ArrayRef<lldb_private::OptionDefinition> GetDefinitions() override; + + // Instance variables to hold the values for command options. + + lldb_private::ProcessLaunchInfo launch_info; + lldb_private::LazyBool disable_aslr; +}; // CommandOptionsProcessLaunch + +}; // namespace lldb_private + +#endif // LLDB_SOURCE_COMMANDS_COMMANDOPTIONSPROCESSLAUNCH_H diff --git a/contrib/llvm-project/lldb/source/Commands/Options.td b/contrib/llvm-project/lldb/source/Commands/Options.td index d6f1e0a3c96d..d3329078893a 100644 --- a/contrib/llvm-project/lldb/source/Commands/Options.td +++ b/contrib/llvm-project/lldb/source/Commands/Options.td @@ -105,7 +105,7 @@ let Command = "breakpoint dummy" in { let Command = "breakpoint set" in { def breakpoint_set_shlib : Option<"shlib", "s">, Arg<"ShlibName">, - Completion<"Module">, Groups<[1,2,3,4,5,6,7,8,9,11]>, // *not* in group 10 + Completion<"Module">, Groups<[1,2,3,4,5,6,7,8,9,11,12]>, // *not* in group 10 Desc<"Set the breakpoint only in this shared library. Can repeat this " "option multiple times to specify multiple shared libraries.">; def breakpoint_set_hardware : Option<"hardware", "H">, @@ -186,21 +186,24 @@ let Command = "breakpoint set" in { "expression (note: currently only implemented for setting breakpoints on " "identifiers). If not set the target.language setting is used.">; def breakpoint_set_skip_prologue : Option<"skip-prologue", "K">, - Arg<"Boolean">, Groups<[1,3,4,5,6,7,8]>, + Arg<"Boolean">, Groups<[1,3,4,5,6,7,8,12]>, Desc<"sKip the prologue if the breakpoint is at the beginning of a " "function. If not set the target.skip-prologue setting is used.">; def breakpoint_set_breakpoint_name : Option<"breakpoint-name", "N">, Arg<"BreakpointName">, Desc<"Adds this to the list of names for this breakpoint.">; def breakpoint_set_address_slide : Option<"address-slide", "R">, - Arg<"Address">, Groups<[1,3,4,5,6,7,8]>, + Arg<"Address">, Groups<[1,3,4,5,6,7,8,12]>, Desc<"Add the specified offset to whatever address(es) the breakpoint " "resolves to. At present this applies the offset directly as given, and " "doesn't try to align it to instruction boundaries.">; def breakpoint_set_move_to_nearest_code : Option<"move-to-nearest-code", "m">, - Groups<[1, 9]>, Arg<"Boolean">, + Groups<[1,9,12]>, Arg<"Boolean">, Desc<"Move breakpoints to nearest code. If not set the " "target.move-to-nearest-codesetting is used.">; + def breakpoint_set_file_colon_line : Option<"joint-specifier", "y">, Group<12>, Arg<"FileLineColumn">, + Required, Completion<"SourceFile">, + Desc<"A specifier in the form filename:line[:column] for setting file & line breakpoints.">; /* Don't add this option till it actually does something useful... def breakpoint_set_exception_typename : Option<"exception-typename", "O">, Arg<"TypeName">, Desc<"The breakpoint will only stop if an " @@ -224,6 +227,9 @@ let Command = "breakpoint delete" in { def breakpoint_delete_dummy_breakpoints : Option<"dummy-breakpoints", "D">, Group<1>, Desc<"Delete Dummy breakpoints - i.e. breakpoints set before a " "file is provided, which prime new targets.">; + def breakpoint_delete_disabled : Option<"disabled", "d">, Group<1>, + Desc<"Delete all breakpoints which are currently disabled. When using the disabled option " + "any breakpoints listed on the command line are EXCLUDED from deletion.">; } let Command = "breakpoint name" in { @@ -321,7 +327,7 @@ let Command = "disassemble" in { def disassemble_options_pc : Option<"pc", "p">, Group<5>, Desc<"Disassemble around the current pc.">; def disassemble_options_line : Option<"line", "l">, Group<6>, - Desc<"Disassemble the current frame's current source line instructions if" + Desc<"Disassemble the current frame's current source line instructions if " "there is debug line table information, else disassemble around the pc.">; def disassemble_options_address : Option<"address", "a">, Group<7>, Arg<"AddressOrExpression">, @@ -366,7 +372,7 @@ let Command = "expression" in { "top-level entities without a $ prefix.">; def expression_options_allow_jit : Option<"allow-jit", "j">, Groups<[1,2]>, Arg<"Boolean">, - Desc<"Controls whether the expression can fall back to being JITted if it's" + Desc<"Controls whether the expression can fall back to being JITted if it's " "not supported by the interpreter (defaults to true).">; } @@ -448,6 +454,12 @@ let Command = "reproducer dump" in { "provided, that reproducer is dumped.">; } +let Command = "reproducer verify" in { + def reproducer_verify_file : Option<"file", "f">, Group<1>, Arg<"Filename">, + Desc<"The reproducer path. If a reproducer is replayed and no path is " + "provided, that reproducer is dumped.">; +} + let Command = "reproducer xcrash" in { def reproducer_signal : Option<"signal", "s">, Group<1>, EnumArg<"None", "ReproducerSignalType()">, @@ -628,6 +640,39 @@ let Command = "platform shell" in { Desc<"Run the commands on the host shell when enabled.">; def platform_shell_timeout : Option<"timeout", "t">, Arg<"Value">, Desc<"Seconds to wait for the remote host to finish running the command.">; + def platform_shell_interpreter : Option<"shell", "s">, Arg<"Path">, + Desc<"Shell interpreter path. This is the binary used to run the command.">; +} + +let Command = "process launch" in { + def process_launch_stop_at_entry : Option<"stop-at-entry", "s">, + Desc<"Stop at the entry point of the program when launching a process.">; + def process_launch_disable_aslr : Option<"disable-aslr", "A">, Arg<"Boolean">, + Desc<"Set whether to disable address space layout randomization when launching a process.">; + def process_launch_plugin : Option<"plugin", "P">, Arg<"Plugin">, + Desc<"Name of the process plugin you want to use.">; + def process_launch_working_dir : Option<"working-dir", "w">, Arg<"DirectoryName">, + Desc<"Set the current working directory to <path> when running the inferior.">; + def process_launch_arch : Option<"arch", "a">, Arg<"Architecture">, + Desc<"Set the architecture for the process to launch when ambiguous.">; + def process_launch_environment : Option<"environment", "v">, + Arg<"None">, Desc<"Specify an environment variable name/value string " + "(--environment NAME=VALUE). Can be specified multiple times for subsequent " + "environment entries.">; + def process_launch_shell : Option<"shell", "c">, GroupRange<1,3>, + OptionalArg<"Filename">, Desc<"Run the process in a shell (not supported on all platforms).">; + def process_launch_stdin : Option<"stdin", "i">, Group<1>, + Arg<"Filename">, Desc<"Redirect stdin for the process to <filename>.">; + def process_launch_stdout : Option<"stdout", "o">, Group<1>, + Arg<"Filename">, Desc<"Redirect stdout for the process to <filename>.">; + def process_launch_stderr : Option<"stderr", "e">, Group<1>, + Arg<"Filename">, Desc<"Redirect stderr for the process to <filename>.">; + def process_launch_tty : Option<"tty", "t">, Group<2>, + Desc<"Start the process in a terminal (not supported on all platforms).">; + def process_launch_no_stdio : Option<"no-stdio", "n">, Group<3>, + Desc<"Do not set up for terminal I/O to go to running process.">; + def process_launch_shell_expand_args : Option<"shell-expand-args", "X">, Group<4>, + Arg<"Boolean">, Desc<"Set whether to shell expand arguments to the process when launching.">; } let Command = "process attach" in { @@ -690,6 +735,10 @@ let Command = "script import" in { Desc<"Allow the script to be loaded even if it was already loaded before. " "This argument exists for backwards compatibility, but reloading is always " "allowed, whether you specify it or not.">; + def relative_to_command_file : Option<"relative-to-command-file", "c">, + Group<1>, Desc<"Resolve non-absolute paths relative to the location of the " + "current command file. This argument can only be used when the command is " + "being sourced from a file.">; } let Command = "script add" in { @@ -706,6 +755,12 @@ let Command = "script add" in { "LLDB event system.">; } +let Command = "script" in { + def script_language : Option<"language", "l">, + EnumArg<"ScriptLang", "ScriptOptionEnum()">, Desc<"Specify the scripting " + " language. If none is specific the default scripting language is used.">; +} + let Command = "source info" in { def source_info_count : Option<"count", "c">, Arg<"Count">, Desc<"The number of line entries to display.">; @@ -729,7 +784,7 @@ let Command = "source info" in { let Command = "source list" in { def source_list_count : Option<"count", "c">, Arg<"Count">, Desc<"The number of source lines to display.">; - def source_list_shlib : Option<"shlib", "s">, Groups<[1,2]>, Arg<"ShlibName">, + def source_list_shlib : Option<"shlib", "s">, Groups<[1,2,5]>, Arg<"ShlibName">, Completion<"Module">, Desc<"Look up the source file in the given shared library.">; def source_list_show_breakpoints : Option<"show-breakpoints", "b">, @@ -747,6 +802,10 @@ let Command = "source list" in { " information for the corresponding file and line.">; def source_list_reverse : Option<"reverse", "r">, Group<4>, Desc<"Reverse the" " listing to look backwards from the last displayed block of source.">; + def source_list_file_colon_line : Option<"joint-specifier", "y">, Group<5>, + Arg<"FileLineColumn">, Completion<"SourceFile">, + Desc<"A specifier in the form filename:line[:column] from which to display" + " source.">; } let Command = "target dependents" in { @@ -855,7 +914,7 @@ let Command = "target modules lookup" in { } let Command = "target stop hook add" in { - def target_stop_hook_add_one_liner : Option<"one-liner", "o">, + def target_stop_hook_add_one_liner : Option<"one-liner", "o">, GroupRange<1,3>, Arg<"OneLiner">, Desc<"Add a command for the stop hook. Can be specified " "more than once, and commands will be run in the order they appear.">; def target_stop_hook_add_shlib : Option<"shlib", "s">, Arg<"ShlibName">, @@ -873,19 +932,19 @@ let Command = "target stop hook add" in { def target_stop_hook_add_queue_name : Option<"queue-name", "q">, Arg<"QueueName">, Desc<"The stop hook is run only for threads in the queue " "whose name is given by this argument.">; - def target_stop_hook_add_file : Option<"file", "f">, Group<1>, + def target_stop_hook_add_file : Option<"file", "f">, Groups<[1,4]>, Arg<"Filename">, Desc<"Specify the source file within which the stop-hook " "is to be run.">, Completion<"SourceFile">; - def target_stop_hook_add_start_line : Option<"start-line", "l">, Group<1>, + def target_stop_hook_add_start_line : Option<"start-line", "l">, Groups<[1,4]>, Arg<"LineNum">, Desc<"Set the start of the line range for which the " "stop-hook is to be run.">; - def target_stop_hook_add_end_line : Option<"end-line", "e">, Group<1>, + def target_stop_hook_add_end_line : Option<"end-line", "e">, Groups<[1,4]>, Arg<"LineNum">, Desc<"Set the end of the line range for which the stop-hook" " is to be run.">; - def target_stop_hook_add_classname : Option<"classname", "c">, Group<2>, + def target_stop_hook_add_classname : Option<"classname", "c">, Groups<[2,5]>, Arg<"ClassName">, Desc<"Specify the class within which the stop-hook is to be run.">; - def target_stop_hook_add_name : Option<"name", "n">, Group<3>, + def target_stop_hook_add_name : Option<"name", "n">, Groups<[3,6]>, Arg<"FunctionName">, Desc<"Set the function name within which the stop hook" " will be run.">, Completion<"Symbol">; def target_stop_hook_add_auto_continue : Option<"auto-continue", "G">, @@ -924,7 +983,7 @@ let Command = "thread step scope" in { EnumArg<"RunMode", "TriRunningModes()">, Desc<"Determine how to run other " "threads while stepping the current thread.">; def thread_step_scope_step_over_regexp : Option<"step-over-regexp", "r">, - Group<1>, Arg<"RegularExpression">, Desc<"A regular expression that defines" + Group<1>, Arg<"RegularExpression">, Desc<"A regular expression that defines " "function names to not to stop at when stepping in.">; def thread_step_scope_step_in_target : Option<"step-in-target", "t">, Group<1>, Arg<"FunctionName">, Desc<"The name of the directly called " @@ -937,10 +996,10 @@ let Command = "thread until" in { def thread_until_thread : Option<"thread", "t">, Group<1>, Arg<"ThreadIndex">, Desc<"Thread index for the thread for until operation">; def thread_until_run_mode : Option<"run-mode", "m">, Group<1>, - EnumArg<"RunMode", "DuoRunningModes()">, Desc<"Determine how to run other" + EnumArg<"RunMode", "DuoRunningModes()">, Desc<"Determine how to run other " "threads while stepping this one">; def thread_until_address : Option<"address", "a">, Group<1>, - Arg<"AddressOrExpression">, Desc<"Run until we reach the specified address," + Arg<"AddressOrExpression">, Desc<"Run until we reach the specified address, " "or leave the function - can be specified multiple times.">; } @@ -981,6 +1040,19 @@ let Command = "thread plan list" in { Desc<"Display thread plans for unreported threads">; } +let Command = "thread trace dump instructions" in { + def thread_trace_dump_instructions_count : Option<"count", "c">, Group<1>, + Arg<"Count">, + Desc<"The number of instructions to display ending at the current position.">; + def thread_trace_dump_instructions_position : Option<"position", "p">, + Group<1>, + Arg<"Index">, + Desc<"The position to use instead of the current position of the trace.">; + def thread_trace_dump_instructions_raw : Option<"raw", "r">, + Group<1>, + Desc<"Dump only instruction address without disassembly nor symbol information.">; +} + let Command = "type summary add" in { def type_summary_add_category : Option<"category", "w">, Arg<"Name">, Desc<"Add this to the given category instead of the default one.">; @@ -1117,7 +1189,7 @@ let Command = "watchpoint list" in { "brief description of the watchpoint (no location info).">; def watchpoint_list_full : Option<"full", "f">, Group<2>, Desc<"Give a full " "description of the watchpoint and its locations.">; - def watchpoint_list_verbose : Option<"verbose", "v">, Group<3>, Desc<"Explain" + def watchpoint_list_verbose : Option<"verbose", "v">, Group<3>, Desc<"Explain " "everything we know about the watchpoint (for debugging debugger bugs).">; } @@ -1154,3 +1226,19 @@ let Command = "watchpoint delete" in { def watchpoint_delete_force : Option<"force", "f">, Group<1>, Desc<"Delete all watchpoints without querying for confirmation.">; } + +let Command = "trace load" in { + def trace_load_verbose : Option<"verbose", "v">, Group<1>, + Desc<"Show verbose trace load logging for debugging the plug-in " + "implementation.">; +} + +let Command = "trace dump" in { + def trace_dump_verbose : Option<"verbose", "v">, Group<1>, + Desc<"Show verbose trace information.">; +} + +let Command = "trace schema" in { + def trace_schema_verbose : Option<"verbose", "v">, Group<1>, + Desc<"Show verbose trace schema logging for debugging the plug-in.">; +} |