15ffd83dbSDimitry Andric //===-- CommandObjectThread.cpp -------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "CommandObjectThread.h" 100b57cec5SDimitry Andric 11fe6060f1SDimitry Andric #include <memory> 12bdd1243dSDimitry Andric #include <optional> 13e8d8bef9SDimitry Andric #include <sstream> 14e8d8bef9SDimitry Andric 15e8d8bef9SDimitry Andric #include "CommandObjectThreadUtil.h" 16fe6060f1SDimitry Andric #include "CommandObjectTrace.h" 17e8d8bef9SDimitry Andric #include "lldb/Core/PluginManager.h" 180b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h" 190b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h" 200b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h" 21fcaf7f86SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h" 220b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 230b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h" 249dba64beSDimitry Andric #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h" 250b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h" 260b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h" 270b57cec5SDimitry Andric #include "lldb/Symbol/Function.h" 280b57cec5SDimitry Andric #include "lldb/Symbol/LineEntry.h" 290b57cec5SDimitry Andric #include "lldb/Symbol/LineTable.h" 300b57cec5SDimitry Andric #include "lldb/Target/Process.h" 310b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h" 320b57cec5SDimitry Andric #include "lldb/Target/SystemRuntime.h" 330b57cec5SDimitry Andric #include "lldb/Target/Target.h" 340b57cec5SDimitry Andric #include "lldb/Target/Thread.h" 350b57cec5SDimitry Andric #include "lldb/Target/ThreadPlan.h" 360b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepInRange.h" 37e8d8bef9SDimitry Andric #include "lldb/Target/Trace.h" 3881ad6265SDimitry Andric #include "lldb/Target/TraceDumper.h" 390b57cec5SDimitry Andric #include "lldb/Utility/State.h" 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric using namespace lldb; 420b57cec5SDimitry Andric using namespace lldb_private; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric // CommandObjectThreadBacktrace 450b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_backtrace 460b57cec5SDimitry Andric #include "CommandOptions.inc" 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads { 490b57cec5SDimitry Andric public: 500b57cec5SDimitry Andric class CommandOptions : public Options { 510b57cec5SDimitry Andric public: 5204eeddc0SDimitry Andric CommandOptions() { 530b57cec5SDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 540b57cec5SDimitry Andric // () 550b57cec5SDimitry Andric OptionParsingStarting(nullptr); 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric ~CommandOptions() override = default; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 610b57cec5SDimitry Andric ExecutionContext *execution_context) override { 620b57cec5SDimitry Andric Status error; 630b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric switch (short_option) { 66bdd1243dSDimitry Andric case 'c': 670b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_count)) { 680b57cec5SDimitry Andric m_count = UINT32_MAX; 690b57cec5SDimitry Andric error.SetErrorStringWithFormat( 700b57cec5SDimitry Andric "invalid integer value for option '%c'", short_option); 71bdd1243dSDimitry Andric } 72bdd1243dSDimitry Andric break; 730b57cec5SDimitry Andric case 's': 740b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_start)) 750b57cec5SDimitry Andric error.SetErrorStringWithFormat( 760b57cec5SDimitry Andric "invalid integer value for option '%c'", short_option); 770b57cec5SDimitry Andric break; 780b57cec5SDimitry Andric case 'e': { 790b57cec5SDimitry Andric bool success; 800b57cec5SDimitry Andric m_extended_backtrace = 810b57cec5SDimitry Andric OptionArgParser::ToBoolean(option_arg, false, &success); 820b57cec5SDimitry Andric if (!success) 830b57cec5SDimitry Andric error.SetErrorStringWithFormat( 840b57cec5SDimitry Andric "invalid boolean value for option '%c'", short_option); 850b57cec5SDimitry Andric } break; 860b57cec5SDimitry Andric default: 879dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric return error; 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 930b57cec5SDimitry Andric m_count = UINT32_MAX; 940b57cec5SDimitry Andric m_start = 0; 950b57cec5SDimitry Andric m_extended_backtrace = false; 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 99bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_backtrace_options); 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric // Instance variables to hold the values for command options. 1030b57cec5SDimitry Andric uint32_t m_count; 1040b57cec5SDimitry Andric uint32_t m_start; 1050b57cec5SDimitry Andric bool m_extended_backtrace; 1060b57cec5SDimitry Andric }; 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric CommandObjectThreadBacktrace(CommandInterpreter &interpreter) 1090b57cec5SDimitry Andric : CommandObjectIterateOverThreads( 1100b57cec5SDimitry Andric interpreter, "thread backtrace", 1110b57cec5SDimitry Andric "Show thread call stacks. Defaults to the current thread, thread " 1120b57cec5SDimitry Andric "indexes can be specified as arguments.\n" 1130b57cec5SDimitry Andric "Use the thread-index \"all\" to see all threads.\n" 1140b57cec5SDimitry Andric "Use the thread-index \"unique\" to see threads grouped by unique " 1150b57cec5SDimitry Andric "call stacks.\n" 1160b57cec5SDimitry Andric "Use 'settings set frame-format' to customize the printing of " 1170b57cec5SDimitry Andric "frames in the backtrace and 'settings set thread-format' to " 1180b57cec5SDimitry Andric "customize the thread header.", 1190b57cec5SDimitry Andric nullptr, 1200b57cec5SDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 1210b57cec5SDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 12204eeddc0SDimitry Andric eCommandProcessMustBePaused) {} 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric ~CommandObjectThreadBacktrace() override = default; 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 1270b57cec5SDimitry Andric 128bdd1243dSDimitry Andric std::optional<std::string> GetRepeatCommand(Args ¤t_args, 12981ad6265SDimitry Andric uint32_t idx) override { 13081ad6265SDimitry Andric llvm::StringRef count_opt("--count"); 13181ad6265SDimitry Andric llvm::StringRef start_opt("--start"); 13281ad6265SDimitry Andric 13381ad6265SDimitry Andric // If no "count" was provided, we are dumping the entire backtrace, so 13481ad6265SDimitry Andric // there isn't a repeat command. So we search for the count option in 13581ad6265SDimitry Andric // the args, and if we find it, we make a copy and insert or modify the 13681ad6265SDimitry Andric // start option's value to start count indices greater. 13781ad6265SDimitry Andric 13881ad6265SDimitry Andric Args copy_args(current_args); 13981ad6265SDimitry Andric size_t num_entries = copy_args.GetArgumentCount(); 14081ad6265SDimitry Andric // These two point at the index of the option value if found. 14181ad6265SDimitry Andric size_t count_idx = 0; 14281ad6265SDimitry Andric size_t start_idx = 0; 14381ad6265SDimitry Andric size_t count_val = 0; 14481ad6265SDimitry Andric size_t start_val = 0; 14581ad6265SDimitry Andric 14681ad6265SDimitry Andric for (size_t idx = 0; idx < num_entries; idx++) { 14781ad6265SDimitry Andric llvm::StringRef arg_string = copy_args[idx].ref(); 14881ad6265SDimitry Andric if (arg_string.equals("-c") || count_opt.startswith(arg_string)) { 14981ad6265SDimitry Andric idx++; 15081ad6265SDimitry Andric if (idx == num_entries) 151bdd1243dSDimitry Andric return std::nullopt; 15281ad6265SDimitry Andric count_idx = idx; 15381ad6265SDimitry Andric if (copy_args[idx].ref().getAsInteger(0, count_val)) 154bdd1243dSDimitry Andric return std::nullopt; 15581ad6265SDimitry Andric } else if (arg_string.equals("-s") || start_opt.startswith(arg_string)) { 15681ad6265SDimitry Andric idx++; 15781ad6265SDimitry Andric if (idx == num_entries) 158bdd1243dSDimitry Andric return std::nullopt; 15981ad6265SDimitry Andric start_idx = idx; 16081ad6265SDimitry Andric if (copy_args[idx].ref().getAsInteger(0, start_val)) 161bdd1243dSDimitry Andric return std::nullopt; 16281ad6265SDimitry Andric } 16381ad6265SDimitry Andric } 16481ad6265SDimitry Andric if (count_idx == 0) 165bdd1243dSDimitry Andric return std::nullopt; 16681ad6265SDimitry Andric 16781ad6265SDimitry Andric std::string new_start_val = llvm::formatv("{0}", start_val + count_val); 16881ad6265SDimitry Andric if (start_idx == 0) { 16981ad6265SDimitry Andric copy_args.AppendArgument(start_opt); 17081ad6265SDimitry Andric copy_args.AppendArgument(new_start_val); 17181ad6265SDimitry Andric } else { 17281ad6265SDimitry Andric copy_args.ReplaceArgumentAtIndex(start_idx, new_start_val); 17381ad6265SDimitry Andric } 17481ad6265SDimitry Andric std::string repeat_command; 17581ad6265SDimitry Andric if (!copy_args.GetQuotedCommandString(repeat_command)) 176bdd1243dSDimitry Andric return std::nullopt; 17781ad6265SDimitry Andric return repeat_command; 17881ad6265SDimitry Andric } 17981ad6265SDimitry Andric 1800b57cec5SDimitry Andric protected: 1810b57cec5SDimitry Andric void DoExtendedBacktrace(Thread *thread, CommandReturnObject &result) { 1820b57cec5SDimitry Andric SystemRuntime *runtime = thread->GetProcess()->GetSystemRuntime(); 1830b57cec5SDimitry Andric if (runtime) { 1840b57cec5SDimitry Andric Stream &strm = result.GetOutputStream(); 1850b57cec5SDimitry Andric const std::vector<ConstString> &types = 1860b57cec5SDimitry Andric runtime->GetExtendedBacktraceTypes(); 1870b57cec5SDimitry Andric for (auto type : types) { 1880b57cec5SDimitry Andric ThreadSP ext_thread_sp = runtime->GetExtendedBacktraceThread( 1890b57cec5SDimitry Andric thread->shared_from_this(), type); 1900b57cec5SDimitry Andric if (ext_thread_sp && ext_thread_sp->IsValid()) { 1910b57cec5SDimitry Andric const uint32_t num_frames_with_source = 0; 1920b57cec5SDimitry Andric const bool stop_format = false; 193bdd1243dSDimitry Andric strm.PutChar('\n'); 1940b57cec5SDimitry Andric if (ext_thread_sp->GetStatus(strm, m_options.m_start, 1950b57cec5SDimitry Andric m_options.m_count, 196480093f4SDimitry Andric num_frames_with_source, stop_format)) { 1970b57cec5SDimitry Andric DoExtendedBacktrace(ext_thread_sp.get(), result); 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric } 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric } 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 2050b57cec5SDimitry Andric ThreadSP thread_sp = 2060b57cec5SDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 2070b57cec5SDimitry Andric if (!thread_sp) { 2080b57cec5SDimitry Andric result.AppendErrorWithFormat( 2090b57cec5SDimitry Andric "thread disappeared while computing backtraces: 0x%" PRIx64 "\n", 2100b57cec5SDimitry Andric tid); 2110b57cec5SDimitry Andric return false; 2120b57cec5SDimitry Andric } 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric Thread *thread = thread_sp.get(); 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric Stream &strm = result.GetOutputStream(); 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric // Only dump stack info if we processing unique stacks. 2190b57cec5SDimitry Andric const bool only_stacks = m_unique_stacks; 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric // Don't show source context when doing backtraces. 2220b57cec5SDimitry Andric const uint32_t num_frames_with_source = 0; 2230b57cec5SDimitry Andric const bool stop_format = true; 2240b57cec5SDimitry Andric if (!thread->GetStatus(strm, m_options.m_start, m_options.m_count, 2250b57cec5SDimitry Andric num_frames_with_source, stop_format, only_stacks)) { 2260b57cec5SDimitry Andric result.AppendErrorWithFormat( 2270b57cec5SDimitry Andric "error displaying backtrace for thread: \"0x%4.4x\"\n", 2280b57cec5SDimitry Andric thread->GetIndexID()); 2290b57cec5SDimitry Andric return false; 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric if (m_options.m_extended_backtrace) { 232*fe013be4SDimitry Andric if (!INTERRUPT_REQUESTED(GetDebugger(), 233*fe013be4SDimitry Andric "Interrupt skipped extended backtrace")) { 2340b57cec5SDimitry Andric DoExtendedBacktrace(thread, result); 2350b57cec5SDimitry Andric } 236*fe013be4SDimitry Andric } 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric return true; 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric CommandOptions m_options; 2420b57cec5SDimitry Andric }; 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric enum StepScope { eStepScopeSource, eStepScopeInstruction }; 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_step_scope 2470b57cec5SDimitry Andric #include "CommandOptions.inc" 2480b57cec5SDimitry Andric 2499dba64beSDimitry Andric class ThreadStepScopeOptionGroup : public OptionGroup { 2500b57cec5SDimitry Andric public: 25104eeddc0SDimitry Andric ThreadStepScopeOptionGroup() { 2520b57cec5SDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 2530b57cec5SDimitry Andric // () 2540b57cec5SDimitry Andric OptionParsingStarting(nullptr); 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric 2579dba64beSDimitry Andric ~ThreadStepScopeOptionGroup() override = default; 2589dba64beSDimitry Andric 2599dba64beSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 260bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_step_scope_options); 2619dba64beSDimitry Andric } 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2640b57cec5SDimitry Andric ExecutionContext *execution_context) override { 2650b57cec5SDimitry Andric Status error; 266480093f4SDimitry Andric const int short_option = 267480093f4SDimitry Andric g_thread_step_scope_options[option_idx].short_option; 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric switch (short_option) { 2700b57cec5SDimitry Andric case 'a': { 2710b57cec5SDimitry Andric bool success; 2720b57cec5SDimitry Andric bool avoid_no_debug = 2730b57cec5SDimitry Andric OptionArgParser::ToBoolean(option_arg, true, &success); 2740b57cec5SDimitry Andric if (!success) 275480093f4SDimitry Andric error.SetErrorStringWithFormat("invalid boolean value for option '%c'", 276480093f4SDimitry Andric short_option); 2770b57cec5SDimitry Andric else { 278480093f4SDimitry Andric m_step_in_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo; 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric } break; 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric case 'A': { 2830b57cec5SDimitry Andric bool success; 2840b57cec5SDimitry Andric bool avoid_no_debug = 2850b57cec5SDimitry Andric OptionArgParser::ToBoolean(option_arg, true, &success); 2860b57cec5SDimitry Andric if (!success) 287480093f4SDimitry Andric error.SetErrorStringWithFormat("invalid boolean value for option '%c'", 288480093f4SDimitry Andric short_option); 2890b57cec5SDimitry Andric else { 290480093f4SDimitry Andric m_step_out_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo; 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric } break; 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric case 'c': 2950b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_step_count)) 2960b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid step count '%s'", 2970b57cec5SDimitry Andric option_arg.str().c_str()); 2980b57cec5SDimitry Andric break; 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric case 'm': { 3010b57cec5SDimitry Andric auto enum_values = GetDefinitions()[option_idx].enum_values; 3020b57cec5SDimitry Andric m_run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum( 3030b57cec5SDimitry Andric option_arg, enum_values, eOnlyDuringStepping, error); 3040b57cec5SDimitry Andric } break; 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric case 'e': 3070b57cec5SDimitry Andric if (option_arg == "block") { 3080b57cec5SDimitry Andric m_end_line_is_block_end = true; 3090b57cec5SDimitry Andric break; 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_end_line)) 3120b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid end line number '%s'", 3130b57cec5SDimitry Andric option_arg.str().c_str()); 3140b57cec5SDimitry Andric break; 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric case 'r': 3170b57cec5SDimitry Andric m_avoid_regexp.clear(); 3185ffd83dbSDimitry Andric m_avoid_regexp.assign(std::string(option_arg)); 3190b57cec5SDimitry Andric break; 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric case 't': 3220b57cec5SDimitry Andric m_step_in_target.clear(); 3235ffd83dbSDimitry Andric m_step_in_target.assign(std::string(option_arg)); 3240b57cec5SDimitry Andric break; 3250b57cec5SDimitry Andric 3260b57cec5SDimitry Andric default: 3279dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric return error; 3300b57cec5SDimitry Andric } 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 3330b57cec5SDimitry Andric m_step_in_avoid_no_debug = eLazyBoolCalculate; 3340b57cec5SDimitry Andric m_step_out_avoid_no_debug = eLazyBoolCalculate; 3350b57cec5SDimitry Andric m_run_mode = eOnlyDuringStepping; 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric // Check if we are in Non-Stop mode 3380b57cec5SDimitry Andric TargetSP target_sp = 3390b57cec5SDimitry Andric execution_context ? execution_context->GetTargetSP() : TargetSP(); 340e8d8bef9SDimitry Andric ProcessSP process_sp = 341e8d8bef9SDimitry Andric execution_context ? execution_context->GetProcessSP() : ProcessSP(); 342e8d8bef9SDimitry Andric if (process_sp && process_sp->GetSteppingRunsAllThreads()) 343e8d8bef9SDimitry Andric m_run_mode = eAllThreads; 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric m_avoid_regexp.clear(); 3460b57cec5SDimitry Andric m_step_in_target.clear(); 3470b57cec5SDimitry Andric m_step_count = 1; 3480b57cec5SDimitry Andric m_end_line = LLDB_INVALID_LINE_NUMBER; 3490b57cec5SDimitry Andric m_end_line_is_block_end = false; 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric // Instance variables to hold the values for command options. 3530b57cec5SDimitry Andric LazyBool m_step_in_avoid_no_debug; 3540b57cec5SDimitry Andric LazyBool m_step_out_avoid_no_debug; 3550b57cec5SDimitry Andric RunMode m_run_mode; 3560b57cec5SDimitry Andric std::string m_avoid_regexp; 3570b57cec5SDimitry Andric std::string m_step_in_target; 3580b57cec5SDimitry Andric uint32_t m_step_count; 3590b57cec5SDimitry Andric uint32_t m_end_line; 3600b57cec5SDimitry Andric bool m_end_line_is_block_end; 3610b57cec5SDimitry Andric }; 3620b57cec5SDimitry Andric 3639dba64beSDimitry Andric class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed { 3649dba64beSDimitry Andric public: 3650b57cec5SDimitry Andric CommandObjectThreadStepWithTypeAndScope(CommandInterpreter &interpreter, 3660b57cec5SDimitry Andric const char *name, const char *help, 3670b57cec5SDimitry Andric const char *syntax, 3680b57cec5SDimitry Andric StepType step_type, 3690b57cec5SDimitry Andric StepScope step_scope) 3700b57cec5SDimitry Andric : CommandObjectParsed(interpreter, name, help, syntax, 3710b57cec5SDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 3720b57cec5SDimitry Andric eCommandTryTargetAPILock | 3730b57cec5SDimitry Andric eCommandProcessMustBeLaunched | 3740b57cec5SDimitry Andric eCommandProcessMustBePaused), 37504eeddc0SDimitry Andric m_step_type(step_type), m_step_scope(step_scope), 376480093f4SDimitry Andric m_class_options("scripted step") { 3770b57cec5SDimitry Andric CommandArgumentEntry arg; 3780b57cec5SDimitry Andric CommandArgumentData thread_id_arg; 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 3810b57cec5SDimitry Andric thread_id_arg.arg_type = eArgTypeThreadID; 3820b57cec5SDimitry Andric thread_id_arg.arg_repetition = eArgRepeatOptional; 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 3850b57cec5SDimitry Andric // argument entry. 3860b57cec5SDimitry Andric arg.push_back(thread_id_arg); 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 3890b57cec5SDimitry Andric m_arguments.push_back(arg); 3909dba64beSDimitry Andric 3919dba64beSDimitry Andric if (step_type == eStepTypeScripted) { 392480093f4SDimitry Andric m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2, 393480093f4SDimitry Andric LLDB_OPT_SET_1); 3949dba64beSDimitry Andric } 3959dba64beSDimitry Andric m_all_options.Append(&m_options); 3969dba64beSDimitry Andric m_all_options.Finalize(); 3970b57cec5SDimitry Andric } 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric ~CommandObjectThreadStepWithTypeAndScope() override = default; 4000b57cec5SDimitry Andric 401e8d8bef9SDimitry Andric void 402e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 403e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override { 404e8d8bef9SDimitry Andric if (request.GetCursorIndex()) 405e8d8bef9SDimitry Andric return; 406e8d8bef9SDimitry Andric 407*fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 408*fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request, 409*fe013be4SDimitry Andric nullptr); 410e8d8bef9SDimitry Andric } 411e8d8bef9SDimitry Andric 412480093f4SDimitry Andric Options *GetOptions() override { return &m_all_options; } 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric protected: 4150b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 4160b57cec5SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr(); 4170b57cec5SDimitry Andric bool synchronous_execution = m_interpreter.GetSynchronous(); 4180b57cec5SDimitry Andric 4190b57cec5SDimitry Andric const uint32_t num_threads = process->GetThreadList().GetSize(); 4200b57cec5SDimitry Andric Thread *thread = nullptr; 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric if (command.GetArgumentCount() == 0) { 4230b57cec5SDimitry Andric thread = GetDefaultThread(); 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric if (thread == nullptr) { 4260b57cec5SDimitry Andric result.AppendError("no selected thread in process"); 4270b57cec5SDimitry Andric return false; 4280b57cec5SDimitry Andric } 4290b57cec5SDimitry Andric } else { 4300b57cec5SDimitry Andric const char *thread_idx_cstr = command.GetArgumentAtIndex(0); 4315ffd83dbSDimitry Andric uint32_t step_thread_idx; 4325ffd83dbSDimitry Andric 4335ffd83dbSDimitry Andric if (!llvm::to_integer(thread_idx_cstr, step_thread_idx)) { 4340b57cec5SDimitry Andric result.AppendErrorWithFormat("invalid thread index '%s'.\n", 4350b57cec5SDimitry Andric thread_idx_cstr); 4360b57cec5SDimitry Andric return false; 4370b57cec5SDimitry Andric } 4380b57cec5SDimitry Andric thread = 4390b57cec5SDimitry Andric process->GetThreadList().FindThreadByIndexID(step_thread_idx).get(); 4400b57cec5SDimitry Andric if (thread == nullptr) { 4410b57cec5SDimitry Andric result.AppendErrorWithFormat( 4420b57cec5SDimitry Andric "Thread index %u is out of range (valid values are 0 - %u).\n", 4430b57cec5SDimitry Andric step_thread_idx, num_threads); 4440b57cec5SDimitry Andric return false; 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric } 4470b57cec5SDimitry Andric 4480b57cec5SDimitry Andric if (m_step_type == eStepTypeScripted) { 449480093f4SDimitry Andric if (m_class_options.GetName().empty()) { 4500b57cec5SDimitry Andric result.AppendErrorWithFormat("empty class name for scripted step."); 4510b57cec5SDimitry Andric return false; 4520b57cec5SDimitry Andric } else if (!GetDebugger().GetScriptInterpreter()->CheckObjectExists( 453480093f4SDimitry Andric m_class_options.GetName().c_str())) { 4540b57cec5SDimitry Andric result.AppendErrorWithFormat( 4550b57cec5SDimitry Andric "class for scripted step: \"%s\" does not exist.", 456480093f4SDimitry Andric m_class_options.GetName().c_str()); 4570b57cec5SDimitry Andric return false; 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric } 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER && 4620b57cec5SDimitry Andric m_step_type != eStepTypeInto) { 4630b57cec5SDimitry Andric result.AppendErrorWithFormat( 4640b57cec5SDimitry Andric "end line option is only valid for step into"); 4650b57cec5SDimitry Andric return false; 4660b57cec5SDimitry Andric } 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric const bool abort_other_plans = false; 4690b57cec5SDimitry Andric const lldb::RunMode stop_other_threads = m_options.m_run_mode; 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric // This is a bit unfortunate, but not all the commands in this command 4720b57cec5SDimitry Andric // object support only while stepping, so I use the bool for them. 4730b57cec5SDimitry Andric bool bool_stop_other_threads; 4740b57cec5SDimitry Andric if (m_options.m_run_mode == eAllThreads) 4750b57cec5SDimitry Andric bool_stop_other_threads = false; 4760b57cec5SDimitry Andric else if (m_options.m_run_mode == eOnlyDuringStepping) 477e8d8bef9SDimitry Andric bool_stop_other_threads = (m_step_type != eStepTypeOut); 4780b57cec5SDimitry Andric else 4790b57cec5SDimitry Andric bool_stop_other_threads = true; 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric ThreadPlanSP new_plan_sp; 4820b57cec5SDimitry Andric Status new_plan_status; 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric if (m_step_type == eStepTypeInto) { 4850b57cec5SDimitry Andric StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); 4860b57cec5SDimitry Andric assert(frame != nullptr); 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric if (frame->HasDebugInformation()) { 4890b57cec5SDimitry Andric AddressRange range; 4900b57cec5SDimitry Andric SymbolContext sc = frame->GetSymbolContext(eSymbolContextEverything); 4910b57cec5SDimitry Andric if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER) { 4920b57cec5SDimitry Andric Status error; 4930b57cec5SDimitry Andric if (!sc.GetAddressRangeFromHereToEndLine(m_options.m_end_line, range, 4940b57cec5SDimitry Andric error)) { 4950b57cec5SDimitry Andric result.AppendErrorWithFormat("invalid end-line option: %s.", 4960b57cec5SDimitry Andric error.AsCString()); 4970b57cec5SDimitry Andric return false; 4980b57cec5SDimitry Andric } 4990b57cec5SDimitry Andric } else if (m_options.m_end_line_is_block_end) { 5000b57cec5SDimitry Andric Status error; 5010b57cec5SDimitry Andric Block *block = frame->GetSymbolContext(eSymbolContextBlock).block; 5020b57cec5SDimitry Andric if (!block) { 5030b57cec5SDimitry Andric result.AppendErrorWithFormat("Could not find the current block."); 5040b57cec5SDimitry Andric return false; 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric AddressRange block_range; 5080b57cec5SDimitry Andric Address pc_address = frame->GetFrameCodeAddress(); 5090b57cec5SDimitry Andric block->GetRangeContainingAddress(pc_address, block_range); 5100b57cec5SDimitry Andric if (!block_range.GetBaseAddress().IsValid()) { 5110b57cec5SDimitry Andric result.AppendErrorWithFormat( 5120b57cec5SDimitry Andric "Could not find the current block address."); 5130b57cec5SDimitry Andric return false; 5140b57cec5SDimitry Andric } 5150b57cec5SDimitry Andric lldb::addr_t pc_offset_in_block = 5160b57cec5SDimitry Andric pc_address.GetFileAddress() - 5170b57cec5SDimitry Andric block_range.GetBaseAddress().GetFileAddress(); 5180b57cec5SDimitry Andric lldb::addr_t range_length = 5190b57cec5SDimitry Andric block_range.GetByteSize() - pc_offset_in_block; 5200b57cec5SDimitry Andric range = AddressRange(pc_address, range_length); 5210b57cec5SDimitry Andric } else { 5220b57cec5SDimitry Andric range = sc.line_entry.range; 5230b57cec5SDimitry Andric } 5240b57cec5SDimitry Andric 5250b57cec5SDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepInRange( 5260b57cec5SDimitry Andric abort_other_plans, range, 5270b57cec5SDimitry Andric frame->GetSymbolContext(eSymbolContextEverything), 5280b57cec5SDimitry Andric m_options.m_step_in_target.c_str(), stop_other_threads, 5290b57cec5SDimitry Andric new_plan_status, m_options.m_step_in_avoid_no_debug, 5300b57cec5SDimitry Andric m_options.m_step_out_avoid_no_debug); 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric if (new_plan_sp && !m_options.m_avoid_regexp.empty()) { 5330b57cec5SDimitry Andric ThreadPlanStepInRange *step_in_range_plan = 5340b57cec5SDimitry Andric static_cast<ThreadPlanStepInRange *>(new_plan_sp.get()); 5350b57cec5SDimitry Andric step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str()); 5360b57cec5SDimitry Andric } 5370b57cec5SDimitry Andric } else 5380b57cec5SDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 5390b57cec5SDimitry Andric false, abort_other_plans, bool_stop_other_threads, new_plan_status); 5400b57cec5SDimitry Andric } else if (m_step_type == eStepTypeOver) { 5410b57cec5SDimitry Andric StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); 5420b57cec5SDimitry Andric 5430b57cec5SDimitry Andric if (frame->HasDebugInformation()) 5440b57cec5SDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepOverRange( 5450b57cec5SDimitry Andric abort_other_plans, 5460b57cec5SDimitry Andric frame->GetSymbolContext(eSymbolContextEverything).line_entry, 5470b57cec5SDimitry Andric frame->GetSymbolContext(eSymbolContextEverything), 5480b57cec5SDimitry Andric stop_other_threads, new_plan_status, 5490b57cec5SDimitry Andric m_options.m_step_out_avoid_no_debug); 5500b57cec5SDimitry Andric else 5510b57cec5SDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 5520b57cec5SDimitry Andric true, abort_other_plans, bool_stop_other_threads, new_plan_status); 5530b57cec5SDimitry Andric } else if (m_step_type == eStepTypeTrace) { 5540b57cec5SDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 5550b57cec5SDimitry Andric false, abort_other_plans, bool_stop_other_threads, new_plan_status); 5560b57cec5SDimitry Andric } else if (m_step_type == eStepTypeTraceOver) { 5570b57cec5SDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 5580b57cec5SDimitry Andric true, abort_other_plans, bool_stop_other_threads, new_plan_status); 5590b57cec5SDimitry Andric } else if (m_step_type == eStepTypeOut) { 5600b57cec5SDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepOut( 5610b57cec5SDimitry Andric abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes, 562*fe013be4SDimitry Andric eVoteNoOpinion, 563*fe013be4SDimitry Andric thread->GetSelectedFrameIndex(DoNoSelectMostRelevantFrame), 564*fe013be4SDimitry Andric new_plan_status, m_options.m_step_out_avoid_no_debug); 5650b57cec5SDimitry Andric } else if (m_step_type == eStepTypeScripted) { 5660b57cec5SDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepScripted( 567480093f4SDimitry Andric abort_other_plans, m_class_options.GetName().c_str(), 568480093f4SDimitry Andric m_class_options.GetStructuredData(), bool_stop_other_threads, 569480093f4SDimitry Andric new_plan_status); 5700b57cec5SDimitry Andric } else { 5710b57cec5SDimitry Andric result.AppendError("step type is not supported"); 5720b57cec5SDimitry Andric return false; 5730b57cec5SDimitry Andric } 5740b57cec5SDimitry Andric 575349cc55cSDimitry Andric // If we got a new plan, then set it to be a controlling plan (User level 576349cc55cSDimitry Andric // Plans should be controlling plans so that they can be interruptible). 577349cc55cSDimitry Andric // Then resume the process. 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric if (new_plan_sp) { 580349cc55cSDimitry Andric new_plan_sp->SetIsControllingPlan(true); 5810b57cec5SDimitry Andric new_plan_sp->SetOkayToDiscard(false); 5820b57cec5SDimitry Andric 5830b57cec5SDimitry Andric if (m_options.m_step_count > 1) { 5840b57cec5SDimitry Andric if (!new_plan_sp->SetIterationCount(m_options.m_step_count)) { 5850b57cec5SDimitry Andric result.AppendWarning( 5860b57cec5SDimitry Andric "step operation does not support iteration count."); 5870b57cec5SDimitry Andric } 5880b57cec5SDimitry Andric } 5890b57cec5SDimitry Andric 5900b57cec5SDimitry Andric process->GetThreadList().SetSelectedThreadByID(thread->GetID()); 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric const uint32_t iohandler_id = process->GetIOHandlerID(); 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric StreamString stream; 5950b57cec5SDimitry Andric Status error; 5960b57cec5SDimitry Andric if (synchronous_execution) 5970b57cec5SDimitry Andric error = process->ResumeSynchronous(&stream); 5980b57cec5SDimitry Andric else 5990b57cec5SDimitry Andric error = process->Resume(); 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric if (!error.Success()) { 6020b57cec5SDimitry Andric result.AppendMessage(error.AsCString()); 6030b57cec5SDimitry Andric return false; 6040b57cec5SDimitry Andric } 6050b57cec5SDimitry Andric 6060b57cec5SDimitry Andric // There is a race condition where this thread will return up the call 6070b57cec5SDimitry Andric // stack to the main command handler and show an (lldb) prompt before 6080b57cec5SDimitry Andric // HandlePrivateEvent (from PrivateStateThread) has a chance to call 6090b57cec5SDimitry Andric // PushProcessIOHandler(). 6100b57cec5SDimitry Andric process->SyncIOHandler(iohandler_id, std::chrono::seconds(2)); 6110b57cec5SDimitry Andric 6120b57cec5SDimitry Andric if (synchronous_execution) { 6130b57cec5SDimitry Andric // If any state changed events had anything to say, add that to the 6140b57cec5SDimitry Andric // result 6150b57cec5SDimitry Andric if (stream.GetSize() > 0) 6160b57cec5SDimitry Andric result.AppendMessage(stream.GetString()); 6170b57cec5SDimitry Andric 6180b57cec5SDimitry Andric process->GetThreadList().SetSelectedThreadByID(thread->GetID()); 6190b57cec5SDimitry Andric result.SetDidChangeProcessState(true); 6200b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 6210b57cec5SDimitry Andric } else { 6220b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessContinuingNoResult); 6230b57cec5SDimitry Andric } 6240b57cec5SDimitry Andric } else { 6250b57cec5SDimitry Andric result.SetError(new_plan_status); 6260b57cec5SDimitry Andric } 6270b57cec5SDimitry Andric return result.Succeeded(); 6280b57cec5SDimitry Andric } 6290b57cec5SDimitry Andric 6300b57cec5SDimitry Andric StepType m_step_type; 6310b57cec5SDimitry Andric StepScope m_step_scope; 6329dba64beSDimitry Andric ThreadStepScopeOptionGroup m_options; 6339dba64beSDimitry Andric OptionGroupPythonClassWithDict m_class_options; 6349dba64beSDimitry Andric OptionGroupOptions m_all_options; 6350b57cec5SDimitry Andric }; 6360b57cec5SDimitry Andric 6370b57cec5SDimitry Andric // CommandObjectThreadContinue 6380b57cec5SDimitry Andric 6390b57cec5SDimitry Andric class CommandObjectThreadContinue : public CommandObjectParsed { 6400b57cec5SDimitry Andric public: 6410b57cec5SDimitry Andric CommandObjectThreadContinue(CommandInterpreter &interpreter) 6420b57cec5SDimitry Andric : CommandObjectParsed( 6430b57cec5SDimitry Andric interpreter, "thread continue", 6440b57cec5SDimitry Andric "Continue execution of the current target process. One " 6450b57cec5SDimitry Andric "or more threads may be specified, by default all " 6460b57cec5SDimitry Andric "threads continue.", 6470b57cec5SDimitry Andric nullptr, 6480b57cec5SDimitry Andric eCommandRequiresThread | eCommandTryTargetAPILock | 6490b57cec5SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { 6500b57cec5SDimitry Andric CommandArgumentEntry arg; 6510b57cec5SDimitry Andric CommandArgumentData thread_idx_arg; 6520b57cec5SDimitry Andric 6530b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 6540b57cec5SDimitry Andric thread_idx_arg.arg_type = eArgTypeThreadIndex; 6550b57cec5SDimitry Andric thread_idx_arg.arg_repetition = eArgRepeatPlus; 6560b57cec5SDimitry Andric 6570b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 6580b57cec5SDimitry Andric // argument entry. 6590b57cec5SDimitry Andric arg.push_back(thread_idx_arg); 6600b57cec5SDimitry Andric 6610b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 6620b57cec5SDimitry Andric m_arguments.push_back(arg); 6630b57cec5SDimitry Andric } 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric ~CommandObjectThreadContinue() override = default; 6660b57cec5SDimitry Andric 667e8d8bef9SDimitry Andric void 668e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 669e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override { 670*fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 671*fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request, 672*fe013be4SDimitry Andric nullptr); 673e8d8bef9SDimitry Andric } 674e8d8bef9SDimitry Andric 6750b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 6760b57cec5SDimitry Andric bool synchronous_execution = m_interpreter.GetSynchronous(); 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr(); 6790b57cec5SDimitry Andric if (process == nullptr) { 6800b57cec5SDimitry Andric result.AppendError("no process exists. Cannot continue"); 6810b57cec5SDimitry Andric return false; 6820b57cec5SDimitry Andric } 6830b57cec5SDimitry Andric 6840b57cec5SDimitry Andric StateType state = process->GetState(); 6850b57cec5SDimitry Andric if ((state == eStateCrashed) || (state == eStateStopped) || 6860b57cec5SDimitry Andric (state == eStateSuspended)) { 6870b57cec5SDimitry Andric const size_t argc = command.GetArgumentCount(); 6880b57cec5SDimitry Andric if (argc > 0) { 6890b57cec5SDimitry Andric // These two lines appear at the beginning of both blocks in this 6900b57cec5SDimitry Andric // if..else, but that is because we need to release the lock before 6910b57cec5SDimitry Andric // calling process->Resume below. 6920b57cec5SDimitry Andric std::lock_guard<std::recursive_mutex> guard( 6930b57cec5SDimitry Andric process->GetThreadList().GetMutex()); 6940b57cec5SDimitry Andric const uint32_t num_threads = process->GetThreadList().GetSize(); 6950b57cec5SDimitry Andric std::vector<Thread *> resume_threads; 6960b57cec5SDimitry Andric for (auto &entry : command.entries()) { 6970b57cec5SDimitry Andric uint32_t thread_idx; 6989dba64beSDimitry Andric if (entry.ref().getAsInteger(0, thread_idx)) { 6990b57cec5SDimitry Andric result.AppendErrorWithFormat( 7000b57cec5SDimitry Andric "invalid thread index argument: \"%s\".\n", entry.c_str()); 7010b57cec5SDimitry Andric return false; 7020b57cec5SDimitry Andric } 7030b57cec5SDimitry Andric Thread *thread = 7040b57cec5SDimitry Andric process->GetThreadList().FindThreadByIndexID(thread_idx).get(); 7050b57cec5SDimitry Andric 7060b57cec5SDimitry Andric if (thread) { 7070b57cec5SDimitry Andric resume_threads.push_back(thread); 7080b57cec5SDimitry Andric } else { 7090b57cec5SDimitry Andric result.AppendErrorWithFormat("invalid thread index %u.\n", 7100b57cec5SDimitry Andric thread_idx); 7110b57cec5SDimitry Andric return false; 7120b57cec5SDimitry Andric } 7130b57cec5SDimitry Andric } 7140b57cec5SDimitry Andric 7150b57cec5SDimitry Andric if (resume_threads.empty()) { 7160b57cec5SDimitry Andric result.AppendError("no valid thread indexes were specified"); 7170b57cec5SDimitry Andric return false; 7180b57cec5SDimitry Andric } else { 7190b57cec5SDimitry Andric if (resume_threads.size() == 1) 7200b57cec5SDimitry Andric result.AppendMessageWithFormat("Resuming thread: "); 7210b57cec5SDimitry Andric else 7220b57cec5SDimitry Andric result.AppendMessageWithFormat("Resuming threads: "); 7230b57cec5SDimitry Andric 7240b57cec5SDimitry Andric for (uint32_t idx = 0; idx < num_threads; ++idx) { 7250b57cec5SDimitry Andric Thread *thread = 7260b57cec5SDimitry Andric process->GetThreadList().GetThreadAtIndex(idx).get(); 7270b57cec5SDimitry Andric std::vector<Thread *>::iterator this_thread_pos = 7280b57cec5SDimitry Andric find(resume_threads.begin(), resume_threads.end(), thread); 7290b57cec5SDimitry Andric 7300b57cec5SDimitry Andric if (this_thread_pos != resume_threads.end()) { 7310b57cec5SDimitry Andric resume_threads.erase(this_thread_pos); 7320b57cec5SDimitry Andric if (!resume_threads.empty()) 7330b57cec5SDimitry Andric result.AppendMessageWithFormat("%u, ", thread->GetIndexID()); 7340b57cec5SDimitry Andric else 7350b57cec5SDimitry Andric result.AppendMessageWithFormat("%u ", thread->GetIndexID()); 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric const bool override_suspend = true; 7380b57cec5SDimitry Andric thread->SetResumeState(eStateRunning, override_suspend); 7390b57cec5SDimitry Andric } else { 7400b57cec5SDimitry Andric thread->SetResumeState(eStateSuspended); 7410b57cec5SDimitry Andric } 7420b57cec5SDimitry Andric } 7430b57cec5SDimitry Andric result.AppendMessageWithFormat("in process %" PRIu64 "\n", 7440b57cec5SDimitry Andric process->GetID()); 7450b57cec5SDimitry Andric } 7460b57cec5SDimitry Andric } else { 7470b57cec5SDimitry Andric // These two lines appear at the beginning of both blocks in this 7480b57cec5SDimitry Andric // if..else, but that is because we need to release the lock before 7490b57cec5SDimitry Andric // calling process->Resume below. 7500b57cec5SDimitry Andric std::lock_guard<std::recursive_mutex> guard( 7510b57cec5SDimitry Andric process->GetThreadList().GetMutex()); 7520b57cec5SDimitry Andric const uint32_t num_threads = process->GetThreadList().GetSize(); 7530b57cec5SDimitry Andric Thread *current_thread = GetDefaultThread(); 7540b57cec5SDimitry Andric if (current_thread == nullptr) { 7550b57cec5SDimitry Andric result.AppendError("the process doesn't have a current thread"); 7560b57cec5SDimitry Andric return false; 7570b57cec5SDimitry Andric } 7580b57cec5SDimitry Andric // Set the actions that the threads should each take when resuming 7590b57cec5SDimitry Andric for (uint32_t idx = 0; idx < num_threads; ++idx) { 7600b57cec5SDimitry Andric Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get(); 7610b57cec5SDimitry Andric if (thread == current_thread) { 7620b57cec5SDimitry Andric result.AppendMessageWithFormat("Resuming thread 0x%4.4" PRIx64 7630b57cec5SDimitry Andric " in process %" PRIu64 "\n", 7640b57cec5SDimitry Andric thread->GetID(), process->GetID()); 7650b57cec5SDimitry Andric const bool override_suspend = true; 7660b57cec5SDimitry Andric thread->SetResumeState(eStateRunning, override_suspend); 7670b57cec5SDimitry Andric } else { 7680b57cec5SDimitry Andric thread->SetResumeState(eStateSuspended); 7690b57cec5SDimitry Andric } 7700b57cec5SDimitry Andric } 7710b57cec5SDimitry Andric } 7720b57cec5SDimitry Andric 7730b57cec5SDimitry Andric StreamString stream; 7740b57cec5SDimitry Andric Status error; 7750b57cec5SDimitry Andric if (synchronous_execution) 7760b57cec5SDimitry Andric error = process->ResumeSynchronous(&stream); 7770b57cec5SDimitry Andric else 7780b57cec5SDimitry Andric error = process->Resume(); 7790b57cec5SDimitry Andric 7800b57cec5SDimitry Andric // We should not be holding the thread list lock when we do this. 7810b57cec5SDimitry Andric if (error.Success()) { 7820b57cec5SDimitry Andric result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n", 7830b57cec5SDimitry Andric process->GetID()); 7840b57cec5SDimitry Andric if (synchronous_execution) { 7850b57cec5SDimitry Andric // If any state changed events had anything to say, add that to the 7860b57cec5SDimitry Andric // result 7870b57cec5SDimitry Andric if (stream.GetSize() > 0) 7880b57cec5SDimitry Andric result.AppendMessage(stream.GetString()); 7890b57cec5SDimitry Andric 7900b57cec5SDimitry Andric result.SetDidChangeProcessState(true); 7910b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 7920b57cec5SDimitry Andric } else { 7930b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessContinuingNoResult); 7940b57cec5SDimitry Andric } 7950b57cec5SDimitry Andric } else { 7960b57cec5SDimitry Andric result.AppendErrorWithFormat("Failed to resume process: %s\n", 7970b57cec5SDimitry Andric error.AsCString()); 7980b57cec5SDimitry Andric } 7990b57cec5SDimitry Andric } else { 8000b57cec5SDimitry Andric result.AppendErrorWithFormat( 8010b57cec5SDimitry Andric "Process cannot be continued from its current state (%s).\n", 8020b57cec5SDimitry Andric StateAsCString(state)); 8030b57cec5SDimitry Andric } 8040b57cec5SDimitry Andric 8050b57cec5SDimitry Andric return result.Succeeded(); 8060b57cec5SDimitry Andric } 8070b57cec5SDimitry Andric }; 8080b57cec5SDimitry Andric 8090b57cec5SDimitry Andric // CommandObjectThreadUntil 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_until 8120b57cec5SDimitry Andric #include "CommandOptions.inc" 8130b57cec5SDimitry Andric 8140b57cec5SDimitry Andric class CommandObjectThreadUntil : public CommandObjectParsed { 8150b57cec5SDimitry Andric public: 8160b57cec5SDimitry Andric class CommandOptions : public Options { 8170b57cec5SDimitry Andric public: 818fe6060f1SDimitry Andric uint32_t m_thread_idx = LLDB_INVALID_THREAD_ID; 819fe6060f1SDimitry Andric uint32_t m_frame_idx = LLDB_INVALID_FRAME_ID; 8200b57cec5SDimitry Andric 82104eeddc0SDimitry Andric CommandOptions() { 8220b57cec5SDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 8230b57cec5SDimitry Andric // () 8240b57cec5SDimitry Andric OptionParsingStarting(nullptr); 8250b57cec5SDimitry Andric } 8260b57cec5SDimitry Andric 8270b57cec5SDimitry Andric ~CommandOptions() override = default; 8280b57cec5SDimitry Andric 8290b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 8300b57cec5SDimitry Andric ExecutionContext *execution_context) override { 8310b57cec5SDimitry Andric Status error; 8320b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 8330b57cec5SDimitry Andric 8340b57cec5SDimitry Andric switch (short_option) { 8350b57cec5SDimitry Andric case 'a': { 8360b57cec5SDimitry Andric lldb::addr_t tmp_addr = OptionArgParser::ToAddress( 8370b57cec5SDimitry Andric execution_context, option_arg, LLDB_INVALID_ADDRESS, &error); 8380b57cec5SDimitry Andric if (error.Success()) 8390b57cec5SDimitry Andric m_until_addrs.push_back(tmp_addr); 8400b57cec5SDimitry Andric } break; 8410b57cec5SDimitry Andric case 't': 8420b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_thread_idx)) { 8430b57cec5SDimitry Andric m_thread_idx = LLDB_INVALID_INDEX32; 8440b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid thread index '%s'", 8450b57cec5SDimitry Andric option_arg.str().c_str()); 8460b57cec5SDimitry Andric } 8470b57cec5SDimitry Andric break; 8480b57cec5SDimitry Andric case 'f': 8490b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_frame_idx)) { 8500b57cec5SDimitry Andric m_frame_idx = LLDB_INVALID_FRAME_ID; 8510b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid frame index '%s'", 8520b57cec5SDimitry Andric option_arg.str().c_str()); 8530b57cec5SDimitry Andric } 8540b57cec5SDimitry Andric break; 8550b57cec5SDimitry Andric case 'm': { 8560b57cec5SDimitry Andric auto enum_values = GetDefinitions()[option_idx].enum_values; 8570b57cec5SDimitry Andric lldb::RunMode run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum( 8580b57cec5SDimitry Andric option_arg, enum_values, eOnlyDuringStepping, error); 8590b57cec5SDimitry Andric 8600b57cec5SDimitry Andric if (error.Success()) { 8610b57cec5SDimitry Andric if (run_mode == eAllThreads) 8620b57cec5SDimitry Andric m_stop_others = false; 8630b57cec5SDimitry Andric else 8640b57cec5SDimitry Andric m_stop_others = true; 8650b57cec5SDimitry Andric } 8660b57cec5SDimitry Andric } break; 8670b57cec5SDimitry Andric default: 8689dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 8690b57cec5SDimitry Andric } 8700b57cec5SDimitry Andric return error; 8710b57cec5SDimitry Andric } 8720b57cec5SDimitry Andric 8730b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 8740b57cec5SDimitry Andric m_thread_idx = LLDB_INVALID_THREAD_ID; 8750b57cec5SDimitry Andric m_frame_idx = 0; 8760b57cec5SDimitry Andric m_stop_others = false; 8770b57cec5SDimitry Andric m_until_addrs.clear(); 8780b57cec5SDimitry Andric } 8790b57cec5SDimitry Andric 8800b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 881bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_until_options); 8820b57cec5SDimitry Andric } 8830b57cec5SDimitry Andric 884fcaf7f86SDimitry Andric uint32_t m_step_thread_idx = LLDB_INVALID_THREAD_ID; 885fcaf7f86SDimitry Andric bool m_stop_others = false; 8860b57cec5SDimitry Andric std::vector<lldb::addr_t> m_until_addrs; 8870b57cec5SDimitry Andric 8880b57cec5SDimitry Andric // Instance variables to hold the values for command options. 8890b57cec5SDimitry Andric }; 8900b57cec5SDimitry Andric 8910b57cec5SDimitry Andric CommandObjectThreadUntil(CommandInterpreter &interpreter) 8920b57cec5SDimitry Andric : CommandObjectParsed( 8930b57cec5SDimitry Andric interpreter, "thread until", 8940b57cec5SDimitry Andric "Continue until a line number or address is reached by the " 8950b57cec5SDimitry Andric "current or specified thread. Stops when returning from " 8960b57cec5SDimitry Andric "the current function as a safety measure. " 897480093f4SDimitry Andric "The target line number(s) are given as arguments, and if more " 898480093f4SDimitry Andric "than one" 8990b57cec5SDimitry Andric " is provided, stepping will stop when the first one is hit.", 9000b57cec5SDimitry Andric nullptr, 9010b57cec5SDimitry Andric eCommandRequiresThread | eCommandTryTargetAPILock | 90204eeddc0SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { 9030b57cec5SDimitry Andric CommandArgumentEntry arg; 9040b57cec5SDimitry Andric CommandArgumentData line_num_arg; 9050b57cec5SDimitry Andric 9060b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 9070b57cec5SDimitry Andric line_num_arg.arg_type = eArgTypeLineNum; 9080b57cec5SDimitry Andric line_num_arg.arg_repetition = eArgRepeatPlain; 9090b57cec5SDimitry Andric 9100b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 9110b57cec5SDimitry Andric // argument entry. 9120b57cec5SDimitry Andric arg.push_back(line_num_arg); 9130b57cec5SDimitry Andric 9140b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 9150b57cec5SDimitry Andric m_arguments.push_back(arg); 9160b57cec5SDimitry Andric } 9170b57cec5SDimitry Andric 9180b57cec5SDimitry Andric ~CommandObjectThreadUntil() override = default; 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 9210b57cec5SDimitry Andric 9220b57cec5SDimitry Andric protected: 9230b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 9240b57cec5SDimitry Andric bool synchronous_execution = m_interpreter.GetSynchronous(); 9250b57cec5SDimitry Andric 9269dba64beSDimitry Andric Target *target = &GetSelectedTarget(); 9270b57cec5SDimitry Andric 9280b57cec5SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr(); 9290b57cec5SDimitry Andric if (process == nullptr) { 9300b57cec5SDimitry Andric result.AppendError("need a valid process to step"); 9310b57cec5SDimitry Andric } else { 9320b57cec5SDimitry Andric Thread *thread = nullptr; 9330b57cec5SDimitry Andric std::vector<uint32_t> line_numbers; 9340b57cec5SDimitry Andric 9350b57cec5SDimitry Andric if (command.GetArgumentCount() >= 1) { 9360b57cec5SDimitry Andric size_t num_args = command.GetArgumentCount(); 9370b57cec5SDimitry Andric for (size_t i = 0; i < num_args; i++) { 9380b57cec5SDimitry Andric uint32_t line_number; 9395ffd83dbSDimitry Andric if (!llvm::to_integer(command.GetArgumentAtIndex(i), line_number)) { 9400b57cec5SDimitry Andric result.AppendErrorWithFormat("invalid line number: '%s'.\n", 9410b57cec5SDimitry Andric command.GetArgumentAtIndex(i)); 9420b57cec5SDimitry Andric return false; 9430b57cec5SDimitry Andric } else 9440b57cec5SDimitry Andric line_numbers.push_back(line_number); 9450b57cec5SDimitry Andric } 9460b57cec5SDimitry Andric } else if (m_options.m_until_addrs.empty()) { 9470b57cec5SDimitry Andric result.AppendErrorWithFormat("No line number or address provided:\n%s", 9480b57cec5SDimitry Andric GetSyntax().str().c_str()); 9490b57cec5SDimitry Andric return false; 9500b57cec5SDimitry Andric } 9510b57cec5SDimitry Andric 9520b57cec5SDimitry Andric if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) { 9530b57cec5SDimitry Andric thread = GetDefaultThread(); 9540b57cec5SDimitry Andric } else { 9550b57cec5SDimitry Andric thread = process->GetThreadList() 9560b57cec5SDimitry Andric .FindThreadByIndexID(m_options.m_thread_idx) 9570b57cec5SDimitry Andric .get(); 9580b57cec5SDimitry Andric } 9590b57cec5SDimitry Andric 9600b57cec5SDimitry Andric if (thread == nullptr) { 9610b57cec5SDimitry Andric const uint32_t num_threads = process->GetThreadList().GetSize(); 9620b57cec5SDimitry Andric result.AppendErrorWithFormat( 9630b57cec5SDimitry Andric "Thread index %u is out of range (valid values are 0 - %u).\n", 9640b57cec5SDimitry Andric m_options.m_thread_idx, num_threads); 9650b57cec5SDimitry Andric return false; 9660b57cec5SDimitry Andric } 9670b57cec5SDimitry Andric 9680b57cec5SDimitry Andric const bool abort_other_plans = false; 9690b57cec5SDimitry Andric 9700b57cec5SDimitry Andric StackFrame *frame = 9710b57cec5SDimitry Andric thread->GetStackFrameAtIndex(m_options.m_frame_idx).get(); 9720b57cec5SDimitry Andric if (frame == nullptr) { 9730b57cec5SDimitry Andric result.AppendErrorWithFormat( 97481ad6265SDimitry Andric "Frame index %u is out of range for thread id %" PRIu64 ".\n", 97581ad6265SDimitry Andric m_options.m_frame_idx, thread->GetID()); 9760b57cec5SDimitry Andric return false; 9770b57cec5SDimitry Andric } 9780b57cec5SDimitry Andric 9790b57cec5SDimitry Andric ThreadPlanSP new_plan_sp; 9800b57cec5SDimitry Andric Status new_plan_status; 9810b57cec5SDimitry Andric 9820b57cec5SDimitry Andric if (frame->HasDebugInformation()) { 9830b57cec5SDimitry Andric // Finally we got here... Translate the given line number to a bunch 9840b57cec5SDimitry Andric // of addresses: 9850b57cec5SDimitry Andric SymbolContext sc(frame->GetSymbolContext(eSymbolContextCompUnit)); 9860b57cec5SDimitry Andric LineTable *line_table = nullptr; 9870b57cec5SDimitry Andric if (sc.comp_unit) 9880b57cec5SDimitry Andric line_table = sc.comp_unit->GetLineTable(); 9890b57cec5SDimitry Andric 9900b57cec5SDimitry Andric if (line_table == nullptr) { 9910b57cec5SDimitry Andric result.AppendErrorWithFormat("Failed to resolve the line table for " 99281ad6265SDimitry Andric "frame %u of thread id %" PRIu64 ".\n", 99381ad6265SDimitry Andric m_options.m_frame_idx, thread->GetID()); 9940b57cec5SDimitry Andric return false; 9950b57cec5SDimitry Andric } 9960b57cec5SDimitry Andric 9970b57cec5SDimitry Andric LineEntry function_start; 998bdd1243dSDimitry Andric uint32_t index_ptr = 0, end_ptr = UINT32_MAX; 9990b57cec5SDimitry Andric std::vector<addr_t> address_list; 10000b57cec5SDimitry Andric 100181ad6265SDimitry Andric // Find the beginning & end index of the function, but first make 100281ad6265SDimitry Andric // sure it is valid: 100381ad6265SDimitry Andric if (!sc.function) { 100481ad6265SDimitry Andric result.AppendErrorWithFormat("Have debug information but no " 100581ad6265SDimitry Andric "function info - can't get until range."); 100681ad6265SDimitry Andric return false; 100781ad6265SDimitry Andric } 100881ad6265SDimitry Andric 10090b57cec5SDimitry Andric AddressRange fun_addr_range = sc.function->GetAddressRange(); 10100b57cec5SDimitry Andric Address fun_start_addr = fun_addr_range.GetBaseAddress(); 10110b57cec5SDimitry Andric line_table->FindLineEntryByAddress(fun_start_addr, function_start, 10120b57cec5SDimitry Andric &index_ptr); 10130b57cec5SDimitry Andric 10140b57cec5SDimitry Andric Address fun_end_addr(fun_start_addr.GetSection(), 10150b57cec5SDimitry Andric fun_start_addr.GetOffset() + 10160b57cec5SDimitry Andric fun_addr_range.GetByteSize()); 10170b57cec5SDimitry Andric 10180b57cec5SDimitry Andric bool all_in_function = true; 10190b57cec5SDimitry Andric 10200b57cec5SDimitry Andric line_table->FindLineEntryByAddress(fun_end_addr, function_start, 10210b57cec5SDimitry Andric &end_ptr); 10220b57cec5SDimitry Andric 1023753f127fSDimitry Andric // Since not all source lines will contribute code, check if we are 1024753f127fSDimitry Andric // setting the breakpoint on the exact line number or the nearest 1025753f127fSDimitry Andric // subsequent line number and set breakpoints at all the line table 1026753f127fSDimitry Andric // entries of the chosen line number (exact or nearest subsequent). 10270b57cec5SDimitry Andric for (uint32_t line_number : line_numbers) { 10280b57cec5SDimitry Andric LineEntry line_entry; 1029753f127fSDimitry Andric bool exact = false; 1030753f127fSDimitry Andric uint32_t start_idx_ptr = index_ptr; 1031753f127fSDimitry Andric start_idx_ptr = sc.comp_unit->FindLineEntry( 1032753f127fSDimitry Andric index_ptr, line_number, nullptr, exact, &line_entry); 1033753f127fSDimitry Andric if (start_idx_ptr != UINT32_MAX) 1034753f127fSDimitry Andric line_number = line_entry.line; 1035753f127fSDimitry Andric exact = true; 1036753f127fSDimitry Andric start_idx_ptr = index_ptr; 1037753f127fSDimitry Andric while (start_idx_ptr <= end_ptr) { 10380b57cec5SDimitry Andric start_idx_ptr = sc.comp_unit->FindLineEntry( 1039480093f4SDimitry Andric start_idx_ptr, line_number, nullptr, exact, &line_entry); 10400b57cec5SDimitry Andric if (start_idx_ptr == UINT32_MAX) 10410b57cec5SDimitry Andric break; 10420b57cec5SDimitry Andric 10430b57cec5SDimitry Andric addr_t address = 10440b57cec5SDimitry Andric line_entry.range.GetBaseAddress().GetLoadAddress(target); 10450b57cec5SDimitry Andric if (address != LLDB_INVALID_ADDRESS) { 10460b57cec5SDimitry Andric if (fun_addr_range.ContainsLoadAddress(address, target)) 10470b57cec5SDimitry Andric address_list.push_back(address); 10480b57cec5SDimitry Andric else 10490b57cec5SDimitry Andric all_in_function = false; 10500b57cec5SDimitry Andric } 10510b57cec5SDimitry Andric start_idx_ptr++; 10520b57cec5SDimitry Andric } 10530b57cec5SDimitry Andric } 10540b57cec5SDimitry Andric 10550b57cec5SDimitry Andric for (lldb::addr_t address : m_options.m_until_addrs) { 10560b57cec5SDimitry Andric if (fun_addr_range.ContainsLoadAddress(address, target)) 10570b57cec5SDimitry Andric address_list.push_back(address); 10580b57cec5SDimitry Andric else 10590b57cec5SDimitry Andric all_in_function = false; 10600b57cec5SDimitry Andric } 10610b57cec5SDimitry Andric 10620b57cec5SDimitry Andric if (address_list.empty()) { 10630b57cec5SDimitry Andric if (all_in_function) 10640b57cec5SDimitry Andric result.AppendErrorWithFormat( 10650b57cec5SDimitry Andric "No line entries matching until target.\n"); 10660b57cec5SDimitry Andric else 10670b57cec5SDimitry Andric result.AppendErrorWithFormat( 10680b57cec5SDimitry Andric "Until target outside of the current function.\n"); 10690b57cec5SDimitry Andric 10700b57cec5SDimitry Andric return false; 10710b57cec5SDimitry Andric } 10720b57cec5SDimitry Andric 10730b57cec5SDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepUntil( 10740b57cec5SDimitry Andric abort_other_plans, &address_list.front(), address_list.size(), 10750b57cec5SDimitry Andric m_options.m_stop_others, m_options.m_frame_idx, new_plan_status); 10760b57cec5SDimitry Andric if (new_plan_sp) { 1077349cc55cSDimitry Andric // User level plans should be controlling plans so they can be 1078349cc55cSDimitry Andric // interrupted 10790b57cec5SDimitry Andric // (e.g. by hitting a breakpoint) and other plans executed by the 10800b57cec5SDimitry Andric // user (stepping around the breakpoint) and then a "continue" will 10810b57cec5SDimitry Andric // resume the original plan. 1082349cc55cSDimitry Andric new_plan_sp->SetIsControllingPlan(true); 10830b57cec5SDimitry Andric new_plan_sp->SetOkayToDiscard(false); 10840b57cec5SDimitry Andric } else { 10850b57cec5SDimitry Andric result.SetError(new_plan_status); 10860b57cec5SDimitry Andric return false; 10870b57cec5SDimitry Andric } 10880b57cec5SDimitry Andric } else { 108981ad6265SDimitry Andric result.AppendErrorWithFormat("Frame index %u of thread id %" PRIu64 109081ad6265SDimitry Andric " has no debug information.\n", 109181ad6265SDimitry Andric m_options.m_frame_idx, thread->GetID()); 10920b57cec5SDimitry Andric return false; 10930b57cec5SDimitry Andric } 10940b57cec5SDimitry Andric 109581ad6265SDimitry Andric if (!process->GetThreadList().SetSelectedThreadByID(thread->GetID())) { 109681ad6265SDimitry Andric result.AppendErrorWithFormat( 109781ad6265SDimitry Andric "Failed to set the selected thread to thread id %" PRIu64 ".\n", 109881ad6265SDimitry Andric thread->GetID()); 109981ad6265SDimitry Andric return false; 110081ad6265SDimitry Andric } 11010b57cec5SDimitry Andric 11020b57cec5SDimitry Andric StreamString stream; 11030b57cec5SDimitry Andric Status error; 11040b57cec5SDimitry Andric if (synchronous_execution) 11050b57cec5SDimitry Andric error = process->ResumeSynchronous(&stream); 11060b57cec5SDimitry Andric else 11070b57cec5SDimitry Andric error = process->Resume(); 11080b57cec5SDimitry Andric 11090b57cec5SDimitry Andric if (error.Success()) { 11100b57cec5SDimitry Andric result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n", 11110b57cec5SDimitry Andric process->GetID()); 11120b57cec5SDimitry Andric if (synchronous_execution) { 11130b57cec5SDimitry Andric // If any state changed events had anything to say, add that to the 11140b57cec5SDimitry Andric // result 11150b57cec5SDimitry Andric if (stream.GetSize() > 0) 11160b57cec5SDimitry Andric result.AppendMessage(stream.GetString()); 11170b57cec5SDimitry Andric 11180b57cec5SDimitry Andric result.SetDidChangeProcessState(true); 11190b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 11200b57cec5SDimitry Andric } else { 11210b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessContinuingNoResult); 11220b57cec5SDimitry Andric } 11230b57cec5SDimitry Andric } else { 11240b57cec5SDimitry Andric result.AppendErrorWithFormat("Failed to resume process: %s.\n", 11250b57cec5SDimitry Andric error.AsCString()); 11260b57cec5SDimitry Andric } 11270b57cec5SDimitry Andric } 11280b57cec5SDimitry Andric return result.Succeeded(); 11290b57cec5SDimitry Andric } 11300b57cec5SDimitry Andric 11310b57cec5SDimitry Andric CommandOptions m_options; 11320b57cec5SDimitry Andric }; 11330b57cec5SDimitry Andric 11340b57cec5SDimitry Andric // CommandObjectThreadSelect 11350b57cec5SDimitry Andric 11360b57cec5SDimitry Andric class CommandObjectThreadSelect : public CommandObjectParsed { 11370b57cec5SDimitry Andric public: 11380b57cec5SDimitry Andric CommandObjectThreadSelect(CommandInterpreter &interpreter) 11390b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "thread select", 11400b57cec5SDimitry Andric "Change the currently selected thread.", nullptr, 11410b57cec5SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 11420b57cec5SDimitry Andric eCommandProcessMustBeLaunched | 11430b57cec5SDimitry Andric eCommandProcessMustBePaused) { 11440b57cec5SDimitry Andric CommandArgumentEntry arg; 11450b57cec5SDimitry Andric CommandArgumentData thread_idx_arg; 11460b57cec5SDimitry Andric 11470b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 11480b57cec5SDimitry Andric thread_idx_arg.arg_type = eArgTypeThreadIndex; 11490b57cec5SDimitry Andric thread_idx_arg.arg_repetition = eArgRepeatPlain; 11500b57cec5SDimitry Andric 11510b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 11520b57cec5SDimitry Andric // argument entry. 11530b57cec5SDimitry Andric arg.push_back(thread_idx_arg); 11540b57cec5SDimitry Andric 11550b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 11560b57cec5SDimitry Andric m_arguments.push_back(arg); 11570b57cec5SDimitry Andric } 11580b57cec5SDimitry Andric 11590b57cec5SDimitry Andric ~CommandObjectThreadSelect() override = default; 11600b57cec5SDimitry Andric 1161e8d8bef9SDimitry Andric void 1162e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 1163e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override { 1164e8d8bef9SDimitry Andric if (request.GetCursorIndex()) 1165e8d8bef9SDimitry Andric return; 1166e8d8bef9SDimitry Andric 1167*fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 1168*fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request, 1169*fe013be4SDimitry Andric nullptr); 1170e8d8bef9SDimitry Andric } 1171e8d8bef9SDimitry Andric 11720b57cec5SDimitry Andric protected: 11730b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 11740b57cec5SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr(); 11750b57cec5SDimitry Andric if (process == nullptr) { 11760b57cec5SDimitry Andric result.AppendError("no process"); 11770b57cec5SDimitry Andric return false; 11780b57cec5SDimitry Andric } else if (command.GetArgumentCount() != 1) { 11790b57cec5SDimitry Andric result.AppendErrorWithFormat( 11800b57cec5SDimitry Andric "'%s' takes exactly one thread index argument:\nUsage: %s\n", 11810b57cec5SDimitry Andric m_cmd_name.c_str(), m_cmd_syntax.c_str()); 11820b57cec5SDimitry Andric return false; 11830b57cec5SDimitry Andric } 11840b57cec5SDimitry Andric 11855ffd83dbSDimitry Andric uint32_t index_id; 11865ffd83dbSDimitry Andric if (!llvm::to_integer(command.GetArgumentAtIndex(0), index_id)) { 11875ffd83dbSDimitry Andric result.AppendErrorWithFormat("Invalid thread index '%s'", 11885ffd83dbSDimitry Andric command.GetArgumentAtIndex(0)); 11895ffd83dbSDimitry Andric return false; 11905ffd83dbSDimitry Andric } 11910b57cec5SDimitry Andric 11920b57cec5SDimitry Andric Thread *new_thread = 11930b57cec5SDimitry Andric process->GetThreadList().FindThreadByIndexID(index_id).get(); 11940b57cec5SDimitry Andric if (new_thread == nullptr) { 11950b57cec5SDimitry Andric result.AppendErrorWithFormat("invalid thread #%s.\n", 11960b57cec5SDimitry Andric command.GetArgumentAtIndex(0)); 11970b57cec5SDimitry Andric return false; 11980b57cec5SDimitry Andric } 11990b57cec5SDimitry Andric 12000b57cec5SDimitry Andric process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true); 12010b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 12020b57cec5SDimitry Andric 12030b57cec5SDimitry Andric return result.Succeeded(); 12040b57cec5SDimitry Andric } 12050b57cec5SDimitry Andric }; 12060b57cec5SDimitry Andric 12070b57cec5SDimitry Andric // CommandObjectThreadList 12080b57cec5SDimitry Andric 12090b57cec5SDimitry Andric class CommandObjectThreadList : public CommandObjectParsed { 12100b57cec5SDimitry Andric public: 12110b57cec5SDimitry Andric CommandObjectThreadList(CommandInterpreter &interpreter) 12120b57cec5SDimitry Andric : CommandObjectParsed( 12130b57cec5SDimitry Andric interpreter, "thread list", 12140b57cec5SDimitry Andric "Show a summary of each thread in the current target process. " 12150b57cec5SDimitry Andric "Use 'settings set thread-format' to customize the individual " 12160b57cec5SDimitry Andric "thread listings.", 12170b57cec5SDimitry Andric "thread list", 12180b57cec5SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 12190b57cec5SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 12200b57cec5SDimitry Andric 12210b57cec5SDimitry Andric ~CommandObjectThreadList() override = default; 12220b57cec5SDimitry Andric 12230b57cec5SDimitry Andric protected: 12240b57cec5SDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 12250b57cec5SDimitry Andric Stream &strm = result.GetOutputStream(); 12260b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 12270b57cec5SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr(); 12280b57cec5SDimitry Andric const bool only_threads_with_stop_reason = false; 12290b57cec5SDimitry Andric const uint32_t start_frame = 0; 12300b57cec5SDimitry Andric const uint32_t num_frames = 0; 12310b57cec5SDimitry Andric const uint32_t num_frames_with_source = 0; 12320b57cec5SDimitry Andric process->GetStatus(strm); 12330b57cec5SDimitry Andric process->GetThreadStatus(strm, only_threads_with_stop_reason, start_frame, 12340b57cec5SDimitry Andric num_frames, num_frames_with_source, false); 12350b57cec5SDimitry Andric return result.Succeeded(); 12360b57cec5SDimitry Andric } 12370b57cec5SDimitry Andric }; 12380b57cec5SDimitry Andric 12390b57cec5SDimitry Andric // CommandObjectThreadInfo 12400b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_info 12410b57cec5SDimitry Andric #include "CommandOptions.inc" 12420b57cec5SDimitry Andric 12430b57cec5SDimitry Andric class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { 12440b57cec5SDimitry Andric public: 12450b57cec5SDimitry Andric class CommandOptions : public Options { 12460b57cec5SDimitry Andric public: 124704eeddc0SDimitry Andric CommandOptions() { OptionParsingStarting(nullptr); } 12480b57cec5SDimitry Andric 12490b57cec5SDimitry Andric ~CommandOptions() override = default; 12500b57cec5SDimitry Andric 12510b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 12520b57cec5SDimitry Andric m_json_thread = false; 12530b57cec5SDimitry Andric m_json_stopinfo = false; 12540b57cec5SDimitry Andric } 12550b57cec5SDimitry Andric 12560b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 12570b57cec5SDimitry Andric ExecutionContext *execution_context) override { 12580b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 12590b57cec5SDimitry Andric Status error; 12600b57cec5SDimitry Andric 12610b57cec5SDimitry Andric switch (short_option) { 12620b57cec5SDimitry Andric case 'j': 12630b57cec5SDimitry Andric m_json_thread = true; 12640b57cec5SDimitry Andric break; 12650b57cec5SDimitry Andric 12660b57cec5SDimitry Andric case 's': 12670b57cec5SDimitry Andric m_json_stopinfo = true; 12680b57cec5SDimitry Andric break; 12690b57cec5SDimitry Andric 12700b57cec5SDimitry Andric default: 12719dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 12720b57cec5SDimitry Andric } 12730b57cec5SDimitry Andric return error; 12740b57cec5SDimitry Andric } 12750b57cec5SDimitry Andric 12760b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1277bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_info_options); 12780b57cec5SDimitry Andric } 12790b57cec5SDimitry Andric 12800b57cec5SDimitry Andric bool m_json_thread; 12810b57cec5SDimitry Andric bool m_json_stopinfo; 12820b57cec5SDimitry Andric }; 12830b57cec5SDimitry Andric 12840b57cec5SDimitry Andric CommandObjectThreadInfo(CommandInterpreter &interpreter) 12850b57cec5SDimitry Andric : CommandObjectIterateOverThreads( 1286480093f4SDimitry Andric interpreter, "thread info", 1287480093f4SDimitry Andric "Show an extended summary of one or " 12880b57cec5SDimitry Andric "more threads. Defaults to the " 12890b57cec5SDimitry Andric "current thread.", 12900b57cec5SDimitry Andric "thread info", 12910b57cec5SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 129204eeddc0SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { 12930b57cec5SDimitry Andric m_add_return = false; 12940b57cec5SDimitry Andric } 12950b57cec5SDimitry Andric 12960b57cec5SDimitry Andric ~CommandObjectThreadInfo() override = default; 12970b57cec5SDimitry Andric 1298e8d8bef9SDimitry Andric void 1299e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 1300e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override { 1301*fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 1302*fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request, 1303*fe013be4SDimitry Andric nullptr); 1304e8d8bef9SDimitry Andric } 1305e8d8bef9SDimitry Andric 13060b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 13070b57cec5SDimitry Andric 13080b57cec5SDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 13090b57cec5SDimitry Andric ThreadSP thread_sp = 13100b57cec5SDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 13110b57cec5SDimitry Andric if (!thread_sp) { 13120b57cec5SDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", 13130b57cec5SDimitry Andric tid); 13140b57cec5SDimitry Andric return false; 13150b57cec5SDimitry Andric } 13160b57cec5SDimitry Andric 13170b57cec5SDimitry Andric Thread *thread = thread_sp.get(); 13180b57cec5SDimitry Andric 13190b57cec5SDimitry Andric Stream &strm = result.GetOutputStream(); 13200b57cec5SDimitry Andric if (!thread->GetDescription(strm, eDescriptionLevelFull, 13210b57cec5SDimitry Andric m_options.m_json_thread, 13220b57cec5SDimitry Andric m_options.m_json_stopinfo)) { 13230b57cec5SDimitry Andric result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n", 13240b57cec5SDimitry Andric thread->GetIndexID()); 13250b57cec5SDimitry Andric return false; 13260b57cec5SDimitry Andric } 13270b57cec5SDimitry Andric return true; 13280b57cec5SDimitry Andric } 13290b57cec5SDimitry Andric 13300b57cec5SDimitry Andric CommandOptions m_options; 13310b57cec5SDimitry Andric }; 13320b57cec5SDimitry Andric 13330b57cec5SDimitry Andric // CommandObjectThreadException 13340b57cec5SDimitry Andric 13350b57cec5SDimitry Andric class CommandObjectThreadException : public CommandObjectIterateOverThreads { 13360b57cec5SDimitry Andric public: 13370b57cec5SDimitry Andric CommandObjectThreadException(CommandInterpreter &interpreter) 13380b57cec5SDimitry Andric : CommandObjectIterateOverThreads( 13390b57cec5SDimitry Andric interpreter, "thread exception", 13400b57cec5SDimitry Andric "Display the current exception object for a thread. Defaults to " 13410b57cec5SDimitry Andric "the current thread.", 13420b57cec5SDimitry Andric "thread exception", 13430b57cec5SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 13440b57cec5SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 13450b57cec5SDimitry Andric 13460b57cec5SDimitry Andric ~CommandObjectThreadException() override = default; 13470b57cec5SDimitry Andric 1348e8d8bef9SDimitry Andric void 1349e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 1350e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override { 1351*fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 1352*fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request, 1353*fe013be4SDimitry Andric nullptr); 1354e8d8bef9SDimitry Andric } 1355e8d8bef9SDimitry Andric 13560b57cec5SDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 13570b57cec5SDimitry Andric ThreadSP thread_sp = 13580b57cec5SDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 13590b57cec5SDimitry Andric if (!thread_sp) { 13600b57cec5SDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", 13610b57cec5SDimitry Andric tid); 13620b57cec5SDimitry Andric return false; 13630b57cec5SDimitry Andric } 13640b57cec5SDimitry Andric 13650b57cec5SDimitry Andric Stream &strm = result.GetOutputStream(); 13660b57cec5SDimitry Andric ValueObjectSP exception_object_sp = thread_sp->GetCurrentException(); 13670b57cec5SDimitry Andric if (exception_object_sp) { 13680b57cec5SDimitry Andric exception_object_sp->Dump(strm); 13690b57cec5SDimitry Andric } 13700b57cec5SDimitry Andric 13710b57cec5SDimitry Andric ThreadSP exception_thread_sp = thread_sp->GetCurrentExceptionBacktrace(); 13720b57cec5SDimitry Andric if (exception_thread_sp && exception_thread_sp->IsValid()) { 13730b57cec5SDimitry Andric const uint32_t num_frames_with_source = 0; 13740b57cec5SDimitry Andric const bool stop_format = false; 13750b57cec5SDimitry Andric exception_thread_sp->GetStatus(strm, 0, UINT32_MAX, 13760b57cec5SDimitry Andric num_frames_with_source, stop_format); 13770b57cec5SDimitry Andric } 13780b57cec5SDimitry Andric 13790b57cec5SDimitry Andric return true; 13800b57cec5SDimitry Andric } 13810b57cec5SDimitry Andric }; 13820b57cec5SDimitry Andric 1383d56accc7SDimitry Andric class CommandObjectThreadSiginfo : public CommandObjectIterateOverThreads { 1384d56accc7SDimitry Andric public: 1385d56accc7SDimitry Andric CommandObjectThreadSiginfo(CommandInterpreter &interpreter) 1386d56accc7SDimitry Andric : CommandObjectIterateOverThreads( 1387d56accc7SDimitry Andric interpreter, "thread siginfo", 1388d56accc7SDimitry Andric "Display the current siginfo object for a thread. Defaults to " 1389d56accc7SDimitry Andric "the current thread.", 1390d56accc7SDimitry Andric "thread siginfo", 1391d56accc7SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 1392d56accc7SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 1393d56accc7SDimitry Andric 1394d56accc7SDimitry Andric ~CommandObjectThreadSiginfo() override = default; 1395d56accc7SDimitry Andric 1396d56accc7SDimitry Andric void 1397d56accc7SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 1398d56accc7SDimitry Andric OptionElementVector &opt_element_vector) override { 1399*fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 1400*fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request, 1401*fe013be4SDimitry Andric nullptr); 1402d56accc7SDimitry Andric } 1403d56accc7SDimitry Andric 1404d56accc7SDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 1405d56accc7SDimitry Andric ThreadSP thread_sp = 1406d56accc7SDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 1407d56accc7SDimitry Andric if (!thread_sp) { 1408d56accc7SDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", 1409d56accc7SDimitry Andric tid); 1410d56accc7SDimitry Andric return false; 1411d56accc7SDimitry Andric } 1412d56accc7SDimitry Andric 1413d56accc7SDimitry Andric Stream &strm = result.GetOutputStream(); 1414d56accc7SDimitry Andric if (!thread_sp->GetDescription(strm, eDescriptionLevelFull, false, false)) { 1415d56accc7SDimitry Andric result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n", 1416d56accc7SDimitry Andric thread_sp->GetIndexID()); 1417d56accc7SDimitry Andric return false; 1418d56accc7SDimitry Andric } 1419d56accc7SDimitry Andric ValueObjectSP exception_object_sp = thread_sp->GetSiginfoValue(); 1420d56accc7SDimitry Andric if (exception_object_sp) 1421d56accc7SDimitry Andric exception_object_sp->Dump(strm); 1422d56accc7SDimitry Andric else 1423d56accc7SDimitry Andric strm.Printf("(no siginfo)\n"); 1424d56accc7SDimitry Andric strm.PutChar('\n'); 1425d56accc7SDimitry Andric 1426d56accc7SDimitry Andric return true; 1427d56accc7SDimitry Andric } 1428d56accc7SDimitry Andric }; 1429d56accc7SDimitry Andric 14300b57cec5SDimitry Andric // CommandObjectThreadReturn 14310b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_return 14320b57cec5SDimitry Andric #include "CommandOptions.inc" 14330b57cec5SDimitry Andric 14340b57cec5SDimitry Andric class CommandObjectThreadReturn : public CommandObjectRaw { 14350b57cec5SDimitry Andric public: 14360b57cec5SDimitry Andric class CommandOptions : public Options { 14370b57cec5SDimitry Andric public: 143804eeddc0SDimitry Andric CommandOptions() { 14390b57cec5SDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 14400b57cec5SDimitry Andric // () 14410b57cec5SDimitry Andric OptionParsingStarting(nullptr); 14420b57cec5SDimitry Andric } 14430b57cec5SDimitry Andric 14440b57cec5SDimitry Andric ~CommandOptions() override = default; 14450b57cec5SDimitry Andric 14460b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 14470b57cec5SDimitry Andric ExecutionContext *execution_context) override { 14480b57cec5SDimitry Andric Status error; 14490b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 14500b57cec5SDimitry Andric 14510b57cec5SDimitry Andric switch (short_option) { 14520b57cec5SDimitry Andric case 'x': { 14530b57cec5SDimitry Andric bool success; 14540b57cec5SDimitry Andric bool tmp_value = 14550b57cec5SDimitry Andric OptionArgParser::ToBoolean(option_arg, false, &success); 14560b57cec5SDimitry Andric if (success) 14570b57cec5SDimitry Andric m_from_expression = tmp_value; 14580b57cec5SDimitry Andric else { 14590b57cec5SDimitry Andric error.SetErrorStringWithFormat( 14600b57cec5SDimitry Andric "invalid boolean value '%s' for 'x' option", 14610b57cec5SDimitry Andric option_arg.str().c_str()); 14620b57cec5SDimitry Andric } 14630b57cec5SDimitry Andric } break; 14640b57cec5SDimitry Andric default: 14659dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 14660b57cec5SDimitry Andric } 14670b57cec5SDimitry Andric return error; 14680b57cec5SDimitry Andric } 14690b57cec5SDimitry Andric 14700b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 14710b57cec5SDimitry Andric m_from_expression = false; 14720b57cec5SDimitry Andric } 14730b57cec5SDimitry Andric 14740b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1475bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_return_options); 14760b57cec5SDimitry Andric } 14770b57cec5SDimitry Andric 1478fe6060f1SDimitry Andric bool m_from_expression = false; 14790b57cec5SDimitry Andric 14800b57cec5SDimitry Andric // Instance variables to hold the values for command options. 14810b57cec5SDimitry Andric }; 14820b57cec5SDimitry Andric 14830b57cec5SDimitry Andric CommandObjectThreadReturn(CommandInterpreter &interpreter) 14840b57cec5SDimitry Andric : CommandObjectRaw(interpreter, "thread return", 14850b57cec5SDimitry Andric "Prematurely return from a stack frame, " 14860b57cec5SDimitry Andric "short-circuiting execution of newer frames " 14870b57cec5SDimitry Andric "and optionally yielding a specified value. Defaults " 14880b57cec5SDimitry Andric "to the exiting the current stack " 14890b57cec5SDimitry Andric "frame.", 14900b57cec5SDimitry Andric "thread return", 14910b57cec5SDimitry Andric eCommandRequiresFrame | eCommandTryTargetAPILock | 14920b57cec5SDimitry Andric eCommandProcessMustBeLaunched | 149304eeddc0SDimitry Andric eCommandProcessMustBePaused) { 14940b57cec5SDimitry Andric CommandArgumentEntry arg; 14950b57cec5SDimitry Andric CommandArgumentData expression_arg; 14960b57cec5SDimitry Andric 14970b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 14980b57cec5SDimitry Andric expression_arg.arg_type = eArgTypeExpression; 14990b57cec5SDimitry Andric expression_arg.arg_repetition = eArgRepeatOptional; 15000b57cec5SDimitry Andric 15010b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 15020b57cec5SDimitry Andric // argument entry. 15030b57cec5SDimitry Andric arg.push_back(expression_arg); 15040b57cec5SDimitry Andric 15050b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 15060b57cec5SDimitry Andric m_arguments.push_back(arg); 15070b57cec5SDimitry Andric } 15080b57cec5SDimitry Andric 15090b57cec5SDimitry Andric ~CommandObjectThreadReturn() override = default; 15100b57cec5SDimitry Andric 15110b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 15120b57cec5SDimitry Andric 15130b57cec5SDimitry Andric protected: 15140b57cec5SDimitry Andric bool DoExecute(llvm::StringRef command, 15150b57cec5SDimitry Andric CommandReturnObject &result) override { 15160b57cec5SDimitry Andric // I am going to handle this by hand, because I don't want you to have to 15170b57cec5SDimitry Andric // say: 15180b57cec5SDimitry Andric // "thread return -- -5". 15190b57cec5SDimitry Andric if (command.startswith("-x")) { 15200b57cec5SDimitry Andric if (command.size() != 2U) 15210b57cec5SDimitry Andric result.AppendWarning("Return values ignored when returning from user " 15220b57cec5SDimitry Andric "called expressions"); 15230b57cec5SDimitry Andric 15240b57cec5SDimitry Andric Thread *thread = m_exe_ctx.GetThreadPtr(); 15250b57cec5SDimitry Andric Status error; 15260b57cec5SDimitry Andric error = thread->UnwindInnermostExpression(); 15270b57cec5SDimitry Andric if (!error.Success()) { 15280b57cec5SDimitry Andric result.AppendErrorWithFormat("Unwinding expression failed - %s.", 15290b57cec5SDimitry Andric error.AsCString()); 15300b57cec5SDimitry Andric } else { 15310b57cec5SDimitry Andric bool success = 15320b57cec5SDimitry Andric thread->SetSelectedFrameByIndexNoisily(0, result.GetOutputStream()); 15330b57cec5SDimitry Andric if (success) { 1534*fe013be4SDimitry Andric m_exe_ctx.SetFrameSP( 1535*fe013be4SDimitry Andric thread->GetSelectedFrame(DoNoSelectMostRelevantFrame)); 15360b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 15370b57cec5SDimitry Andric } else { 15380b57cec5SDimitry Andric result.AppendErrorWithFormat( 15390b57cec5SDimitry Andric "Could not select 0th frame after unwinding expression."); 15400b57cec5SDimitry Andric } 15410b57cec5SDimitry Andric } 15420b57cec5SDimitry Andric return result.Succeeded(); 15430b57cec5SDimitry Andric } 15440b57cec5SDimitry Andric 15450b57cec5SDimitry Andric ValueObjectSP return_valobj_sp; 15460b57cec5SDimitry Andric 15470b57cec5SDimitry Andric StackFrameSP frame_sp = m_exe_ctx.GetFrameSP(); 15480b57cec5SDimitry Andric uint32_t frame_idx = frame_sp->GetFrameIndex(); 15490b57cec5SDimitry Andric 15500b57cec5SDimitry Andric if (frame_sp->IsInlined()) { 15510b57cec5SDimitry Andric result.AppendError("Don't know how to return from inlined frames."); 15520b57cec5SDimitry Andric return false; 15530b57cec5SDimitry Andric } 15540b57cec5SDimitry Andric 15550b57cec5SDimitry Andric if (!command.empty()) { 15560b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 15570b57cec5SDimitry Andric EvaluateExpressionOptions options; 15580b57cec5SDimitry Andric 15590b57cec5SDimitry Andric options.SetUnwindOnError(true); 15600b57cec5SDimitry Andric options.SetUseDynamic(eNoDynamicValues); 15610b57cec5SDimitry Andric 15620b57cec5SDimitry Andric ExpressionResults exe_results = eExpressionSetupError; 15630b57cec5SDimitry Andric exe_results = target->EvaluateExpression(command, frame_sp.get(), 15640b57cec5SDimitry Andric return_valobj_sp, options); 15650b57cec5SDimitry Andric if (exe_results != eExpressionCompleted) { 15660b57cec5SDimitry Andric if (return_valobj_sp) 15670b57cec5SDimitry Andric result.AppendErrorWithFormat( 15680b57cec5SDimitry Andric "Error evaluating result expression: %s", 15690b57cec5SDimitry Andric return_valobj_sp->GetError().AsCString()); 15700b57cec5SDimitry Andric else 15710b57cec5SDimitry Andric result.AppendErrorWithFormat( 15720b57cec5SDimitry Andric "Unknown error evaluating result expression."); 15730b57cec5SDimitry Andric return false; 15740b57cec5SDimitry Andric } 15750b57cec5SDimitry Andric } 15760b57cec5SDimitry Andric 15770b57cec5SDimitry Andric Status error; 15780b57cec5SDimitry Andric ThreadSP thread_sp = m_exe_ctx.GetThreadSP(); 15790b57cec5SDimitry Andric const bool broadcast = true; 15800b57cec5SDimitry Andric error = thread_sp->ReturnFromFrame(frame_sp, return_valobj_sp, broadcast); 15810b57cec5SDimitry Andric if (!error.Success()) { 15820b57cec5SDimitry Andric result.AppendErrorWithFormat( 15830b57cec5SDimitry Andric "Error returning from frame %d of thread %d: %s.", frame_idx, 15840b57cec5SDimitry Andric thread_sp->GetIndexID(), error.AsCString()); 15850b57cec5SDimitry Andric return false; 15860b57cec5SDimitry Andric } 15870b57cec5SDimitry Andric 15880b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 15890b57cec5SDimitry Andric return true; 15900b57cec5SDimitry Andric } 15910b57cec5SDimitry Andric 15920b57cec5SDimitry Andric CommandOptions m_options; 15930b57cec5SDimitry Andric }; 15940b57cec5SDimitry Andric 15950b57cec5SDimitry Andric // CommandObjectThreadJump 15960b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_jump 15970b57cec5SDimitry Andric #include "CommandOptions.inc" 15980b57cec5SDimitry Andric 15990b57cec5SDimitry Andric class CommandObjectThreadJump : public CommandObjectParsed { 16000b57cec5SDimitry Andric public: 16010b57cec5SDimitry Andric class CommandOptions : public Options { 16020b57cec5SDimitry Andric public: 160304eeddc0SDimitry Andric CommandOptions() { OptionParsingStarting(nullptr); } 16040b57cec5SDimitry Andric 16050b57cec5SDimitry Andric ~CommandOptions() override = default; 16060b57cec5SDimitry Andric 16070b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 16080b57cec5SDimitry Andric m_filenames.Clear(); 16090b57cec5SDimitry Andric m_line_num = 0; 16100b57cec5SDimitry Andric m_line_offset = 0; 16110b57cec5SDimitry Andric m_load_addr = LLDB_INVALID_ADDRESS; 16120b57cec5SDimitry Andric m_force = false; 16130b57cec5SDimitry Andric } 16140b57cec5SDimitry Andric 16150b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 16160b57cec5SDimitry Andric ExecutionContext *execution_context) override { 16170b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 16180b57cec5SDimitry Andric Status error; 16190b57cec5SDimitry Andric 16200b57cec5SDimitry Andric switch (short_option) { 16210b57cec5SDimitry Andric case 'f': 16220b57cec5SDimitry Andric m_filenames.AppendIfUnique(FileSpec(option_arg)); 16230b57cec5SDimitry Andric if (m_filenames.GetSize() > 1) 16240b57cec5SDimitry Andric return Status("only one source file expected."); 16250b57cec5SDimitry Andric break; 16260b57cec5SDimitry Andric case 'l': 16270b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_line_num)) 16280b57cec5SDimitry Andric return Status("invalid line number: '%s'.", option_arg.str().c_str()); 16290b57cec5SDimitry Andric break; 16300b57cec5SDimitry Andric case 'b': 16310b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_line_offset)) 16320b57cec5SDimitry Andric return Status("invalid line offset: '%s'.", option_arg.str().c_str()); 16330b57cec5SDimitry Andric break; 16340b57cec5SDimitry Andric case 'a': 16350b57cec5SDimitry Andric m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg, 16360b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &error); 16370b57cec5SDimitry Andric break; 16380b57cec5SDimitry Andric case 'r': 16390b57cec5SDimitry Andric m_force = true; 16400b57cec5SDimitry Andric break; 16410b57cec5SDimitry Andric default: 16429dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 16430b57cec5SDimitry Andric } 16440b57cec5SDimitry Andric return error; 16450b57cec5SDimitry Andric } 16460b57cec5SDimitry Andric 16470b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1648bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_jump_options); 16490b57cec5SDimitry Andric } 16500b57cec5SDimitry Andric 16510b57cec5SDimitry Andric FileSpecList m_filenames; 16520b57cec5SDimitry Andric uint32_t m_line_num; 16530b57cec5SDimitry Andric int32_t m_line_offset; 16540b57cec5SDimitry Andric lldb::addr_t m_load_addr; 16550b57cec5SDimitry Andric bool m_force; 16560b57cec5SDimitry Andric }; 16570b57cec5SDimitry Andric 16580b57cec5SDimitry Andric CommandObjectThreadJump(CommandInterpreter &interpreter) 16590b57cec5SDimitry Andric : CommandObjectParsed( 16600b57cec5SDimitry Andric interpreter, "thread jump", 16610b57cec5SDimitry Andric "Sets the program counter to a new address.", "thread jump", 16620b57cec5SDimitry Andric eCommandRequiresFrame | eCommandTryTargetAPILock | 166304eeddc0SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 16640b57cec5SDimitry Andric 16650b57cec5SDimitry Andric ~CommandObjectThreadJump() override = default; 16660b57cec5SDimitry Andric 16670b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 16680b57cec5SDimitry Andric 16690b57cec5SDimitry Andric protected: 16700b57cec5SDimitry Andric bool DoExecute(Args &args, CommandReturnObject &result) override { 16710b57cec5SDimitry Andric RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext(); 16720b57cec5SDimitry Andric StackFrame *frame = m_exe_ctx.GetFramePtr(); 16730b57cec5SDimitry Andric Thread *thread = m_exe_ctx.GetThreadPtr(); 16740b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr(); 16750b57cec5SDimitry Andric const SymbolContext &sym_ctx = 16760b57cec5SDimitry Andric frame->GetSymbolContext(eSymbolContextLineEntry); 16770b57cec5SDimitry Andric 16780b57cec5SDimitry Andric if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) { 16790b57cec5SDimitry Andric // Use this address directly. 16800b57cec5SDimitry Andric Address dest = Address(m_options.m_load_addr); 16810b57cec5SDimitry Andric 16820b57cec5SDimitry Andric lldb::addr_t callAddr = dest.GetCallableLoadAddress(target); 16830b57cec5SDimitry Andric if (callAddr == LLDB_INVALID_ADDRESS) { 16840b57cec5SDimitry Andric result.AppendErrorWithFormat("Invalid destination address."); 16850b57cec5SDimitry Andric return false; 16860b57cec5SDimitry Andric } 16870b57cec5SDimitry Andric 16880b57cec5SDimitry Andric if (!reg_ctx->SetPC(callAddr)) { 16890b57cec5SDimitry Andric result.AppendErrorWithFormat("Error changing PC value for thread %d.", 16900b57cec5SDimitry Andric thread->GetIndexID()); 16910b57cec5SDimitry Andric return false; 16920b57cec5SDimitry Andric } 16930b57cec5SDimitry Andric } else { 16940b57cec5SDimitry Andric // Pick either the absolute line, or work out a relative one. 16950b57cec5SDimitry Andric int32_t line = (int32_t)m_options.m_line_num; 16960b57cec5SDimitry Andric if (line == 0) 16970b57cec5SDimitry Andric line = sym_ctx.line_entry.line + m_options.m_line_offset; 16980b57cec5SDimitry Andric 16990b57cec5SDimitry Andric // Try the current file, but override if asked. 17000b57cec5SDimitry Andric FileSpec file = sym_ctx.line_entry.file; 17010b57cec5SDimitry Andric if (m_options.m_filenames.GetSize() == 1) 17020b57cec5SDimitry Andric file = m_options.m_filenames.GetFileSpecAtIndex(0); 17030b57cec5SDimitry Andric 17040b57cec5SDimitry Andric if (!file) { 17050b57cec5SDimitry Andric result.AppendErrorWithFormat( 17060b57cec5SDimitry Andric "No source file available for the current location."); 17070b57cec5SDimitry Andric return false; 17080b57cec5SDimitry Andric } 17090b57cec5SDimitry Andric 17100b57cec5SDimitry Andric std::string warnings; 17110b57cec5SDimitry Andric Status err = thread->JumpToLine(file, line, m_options.m_force, &warnings); 17120b57cec5SDimitry Andric 17130b57cec5SDimitry Andric if (err.Fail()) { 17140b57cec5SDimitry Andric result.SetError(err); 17150b57cec5SDimitry Andric return false; 17160b57cec5SDimitry Andric } 17170b57cec5SDimitry Andric 17180b57cec5SDimitry Andric if (!warnings.empty()) 17190b57cec5SDimitry Andric result.AppendWarning(warnings.c_str()); 17200b57cec5SDimitry Andric } 17210b57cec5SDimitry Andric 17220b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 17230b57cec5SDimitry Andric return true; 17240b57cec5SDimitry Andric } 17250b57cec5SDimitry Andric 17260b57cec5SDimitry Andric CommandOptions m_options; 17270b57cec5SDimitry Andric }; 17280b57cec5SDimitry Andric 17290b57cec5SDimitry Andric // Next are the subcommands of CommandObjectMultiwordThreadPlan 17300b57cec5SDimitry Andric 17310b57cec5SDimitry Andric // CommandObjectThreadPlanList 17320b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_plan_list 17330b57cec5SDimitry Andric #include "CommandOptions.inc" 17340b57cec5SDimitry Andric 17350b57cec5SDimitry Andric class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads { 17360b57cec5SDimitry Andric public: 17370b57cec5SDimitry Andric class CommandOptions : public Options { 17380b57cec5SDimitry Andric public: 173904eeddc0SDimitry Andric CommandOptions() { 17400b57cec5SDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 17410b57cec5SDimitry Andric // () 17420b57cec5SDimitry Andric OptionParsingStarting(nullptr); 17430b57cec5SDimitry Andric } 17440b57cec5SDimitry Andric 17450b57cec5SDimitry Andric ~CommandOptions() override = default; 17460b57cec5SDimitry Andric 17470b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 17480b57cec5SDimitry Andric ExecutionContext *execution_context) override { 17490b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 17500b57cec5SDimitry Andric 17510b57cec5SDimitry Andric switch (short_option) { 17520b57cec5SDimitry Andric case 'i': 17530b57cec5SDimitry Andric m_internal = true; 17540b57cec5SDimitry Andric break; 17555ffd83dbSDimitry Andric case 't': 17565ffd83dbSDimitry Andric lldb::tid_t tid; 17575ffd83dbSDimitry Andric if (option_arg.getAsInteger(0, tid)) 17585ffd83dbSDimitry Andric return Status("invalid tid: '%s'.", option_arg.str().c_str()); 17595ffd83dbSDimitry Andric m_tids.push_back(tid); 17605ffd83dbSDimitry Andric break; 17615ffd83dbSDimitry Andric case 'u': 17625ffd83dbSDimitry Andric m_unreported = false; 17635ffd83dbSDimitry Andric break; 17640b57cec5SDimitry Andric case 'v': 17650b57cec5SDimitry Andric m_verbose = true; 17660b57cec5SDimitry Andric break; 17670b57cec5SDimitry Andric default: 17689dba64beSDimitry Andric llvm_unreachable("Unimplemented option"); 17690b57cec5SDimitry Andric } 17705ffd83dbSDimitry Andric return {}; 17710b57cec5SDimitry Andric } 17720b57cec5SDimitry Andric 17730b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 17740b57cec5SDimitry Andric m_verbose = false; 17750b57cec5SDimitry Andric m_internal = false; 17765ffd83dbSDimitry Andric m_unreported = true; // The variable is "skip unreported" and we want to 17775ffd83dbSDimitry Andric // skip unreported by default. 17785ffd83dbSDimitry Andric m_tids.clear(); 17790b57cec5SDimitry Andric } 17800b57cec5SDimitry Andric 17810b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1782bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_plan_list_options); 17830b57cec5SDimitry Andric } 17840b57cec5SDimitry Andric 17850b57cec5SDimitry Andric // Instance variables to hold the values for command options. 17860b57cec5SDimitry Andric bool m_verbose; 17870b57cec5SDimitry Andric bool m_internal; 17885ffd83dbSDimitry Andric bool m_unreported; 17895ffd83dbSDimitry Andric std::vector<lldb::tid_t> m_tids; 17900b57cec5SDimitry Andric }; 17910b57cec5SDimitry Andric 17920b57cec5SDimitry Andric CommandObjectThreadPlanList(CommandInterpreter &interpreter) 17930b57cec5SDimitry Andric : CommandObjectIterateOverThreads( 17940b57cec5SDimitry Andric interpreter, "thread plan list", 17950b57cec5SDimitry Andric "Show thread plans for one or more threads. If no threads are " 17960b57cec5SDimitry Andric "specified, show the " 17970b57cec5SDimitry Andric "current thread. Use the thread-index \"all\" to see all threads.", 17980b57cec5SDimitry Andric nullptr, 17990b57cec5SDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 18000b57cec5SDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 180104eeddc0SDimitry Andric eCommandProcessMustBePaused) {} 18020b57cec5SDimitry Andric 18030b57cec5SDimitry Andric ~CommandObjectThreadPlanList() override = default; 18040b57cec5SDimitry Andric 18050b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; } 18060b57cec5SDimitry Andric 18075ffd83dbSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 18085ffd83dbSDimitry Andric // If we are reporting all threads, dispatch to the Process to do that: 18095ffd83dbSDimitry Andric if (command.GetArgumentCount() == 0 && m_options.m_tids.empty()) { 18105ffd83dbSDimitry Andric Stream &strm = result.GetOutputStream(); 18115ffd83dbSDimitry Andric DescriptionLevel desc_level = m_options.m_verbose 18125ffd83dbSDimitry Andric ? eDescriptionLevelVerbose 18135ffd83dbSDimitry Andric : eDescriptionLevelFull; 18145ffd83dbSDimitry Andric m_exe_ctx.GetProcessPtr()->DumpThreadPlans( 18155ffd83dbSDimitry Andric strm, desc_level, m_options.m_internal, true, m_options.m_unreported); 18165ffd83dbSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 18175ffd83dbSDimitry Andric return true; 18185ffd83dbSDimitry Andric } else { 18195ffd83dbSDimitry Andric // Do any TID's that the user may have specified as TID, then do any 18205ffd83dbSDimitry Andric // Thread Indexes... 18215ffd83dbSDimitry Andric if (!m_options.m_tids.empty()) { 18225ffd83dbSDimitry Andric Process *process = m_exe_ctx.GetProcessPtr(); 18235ffd83dbSDimitry Andric StreamString tmp_strm; 18245ffd83dbSDimitry Andric for (lldb::tid_t tid : m_options.m_tids) { 18255ffd83dbSDimitry Andric bool success = process->DumpThreadPlansForTID( 18265ffd83dbSDimitry Andric tmp_strm, tid, eDescriptionLevelFull, m_options.m_internal, 18275ffd83dbSDimitry Andric true /* condense_trivial */, m_options.m_unreported); 18285ffd83dbSDimitry Andric // If we didn't find a TID, stop here and return an error. 18295ffd83dbSDimitry Andric if (!success) { 1830fe6060f1SDimitry Andric result.AppendError("Error dumping plans:"); 18315ffd83dbSDimitry Andric result.AppendError(tmp_strm.GetString()); 18320b57cec5SDimitry Andric return false; 18330b57cec5SDimitry Andric } 18345ffd83dbSDimitry Andric // Otherwise, add our data to the output: 18355ffd83dbSDimitry Andric result.GetOutputStream() << tmp_strm.GetString(); 18365ffd83dbSDimitry Andric } 18375ffd83dbSDimitry Andric } 18385ffd83dbSDimitry Andric return CommandObjectIterateOverThreads::DoExecute(command, result); 18395ffd83dbSDimitry Andric } 18405ffd83dbSDimitry Andric } 18410b57cec5SDimitry Andric 18425ffd83dbSDimitry Andric protected: 18435ffd83dbSDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 18445ffd83dbSDimitry Andric // If we have already handled this from a -t option, skip it here. 1845e8d8bef9SDimitry Andric if (llvm::is_contained(m_options.m_tids, tid)) 18465ffd83dbSDimitry Andric return true; 18475ffd83dbSDimitry Andric 18485ffd83dbSDimitry Andric Process *process = m_exe_ctx.GetProcessPtr(); 18490b57cec5SDimitry Andric 18500b57cec5SDimitry Andric Stream &strm = result.GetOutputStream(); 18510b57cec5SDimitry Andric DescriptionLevel desc_level = eDescriptionLevelFull; 18520b57cec5SDimitry Andric if (m_options.m_verbose) 18530b57cec5SDimitry Andric desc_level = eDescriptionLevelVerbose; 18540b57cec5SDimitry Andric 18555ffd83dbSDimitry Andric process->DumpThreadPlansForTID(strm, tid, desc_level, m_options.m_internal, 18565ffd83dbSDimitry Andric true /* condense_trivial */, 18575ffd83dbSDimitry Andric m_options.m_unreported); 18580b57cec5SDimitry Andric return true; 18590b57cec5SDimitry Andric } 18600b57cec5SDimitry Andric 18610b57cec5SDimitry Andric CommandOptions m_options; 18620b57cec5SDimitry Andric }; 18630b57cec5SDimitry Andric 18640b57cec5SDimitry Andric class CommandObjectThreadPlanDiscard : public CommandObjectParsed { 18650b57cec5SDimitry Andric public: 18660b57cec5SDimitry Andric CommandObjectThreadPlanDiscard(CommandInterpreter &interpreter) 18670b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "thread plan discard", 18680b57cec5SDimitry Andric "Discards thread plans up to and including the " 18690b57cec5SDimitry Andric "specified index (see 'thread plan list'.) " 18700b57cec5SDimitry Andric "Only user visible plans can be discarded.", 18710b57cec5SDimitry Andric nullptr, 18720b57cec5SDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 18730b57cec5SDimitry Andric eCommandTryTargetAPILock | 18740b57cec5SDimitry Andric eCommandProcessMustBeLaunched | 18750b57cec5SDimitry Andric eCommandProcessMustBePaused) { 18760b57cec5SDimitry Andric CommandArgumentEntry arg; 18770b57cec5SDimitry Andric CommandArgumentData plan_index_arg; 18780b57cec5SDimitry Andric 18790b57cec5SDimitry Andric // Define the first (and only) variant of this arg. 18800b57cec5SDimitry Andric plan_index_arg.arg_type = eArgTypeUnsignedInteger; 18810b57cec5SDimitry Andric plan_index_arg.arg_repetition = eArgRepeatPlain; 18820b57cec5SDimitry Andric 18830b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the 18840b57cec5SDimitry Andric // argument entry. 18850b57cec5SDimitry Andric arg.push_back(plan_index_arg); 18860b57cec5SDimitry Andric 18870b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector. 18880b57cec5SDimitry Andric m_arguments.push_back(arg); 18890b57cec5SDimitry Andric } 18900b57cec5SDimitry Andric 18910b57cec5SDimitry Andric ~CommandObjectThreadPlanDiscard() override = default; 18920b57cec5SDimitry Andric 1893e8d8bef9SDimitry Andric void 1894e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request, 1895e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override { 1896e8d8bef9SDimitry Andric if (!m_exe_ctx.HasThreadScope() || request.GetCursorIndex()) 1897e8d8bef9SDimitry Andric return; 1898e8d8bef9SDimitry Andric 1899e8d8bef9SDimitry Andric m_exe_ctx.GetThreadPtr()->AutoCompleteThreadPlans(request); 1900e8d8bef9SDimitry Andric } 1901e8d8bef9SDimitry Andric 19020b57cec5SDimitry Andric bool DoExecute(Args &args, CommandReturnObject &result) override { 19030b57cec5SDimitry Andric Thread *thread = m_exe_ctx.GetThreadPtr(); 19040b57cec5SDimitry Andric if (args.GetArgumentCount() != 1) { 19050b57cec5SDimitry Andric result.AppendErrorWithFormat("Too many arguments, expected one - the " 19060b57cec5SDimitry Andric "thread plan index - but got %zu.", 19070b57cec5SDimitry Andric args.GetArgumentCount()); 19080b57cec5SDimitry Andric return false; 19090b57cec5SDimitry Andric } 19100b57cec5SDimitry Andric 19115ffd83dbSDimitry Andric uint32_t thread_plan_idx; 19125ffd83dbSDimitry Andric if (!llvm::to_integer(args.GetArgumentAtIndex(0), thread_plan_idx)) { 19130b57cec5SDimitry Andric result.AppendErrorWithFormat( 19140b57cec5SDimitry Andric "Invalid thread index: \"%s\" - should be unsigned int.", 19150b57cec5SDimitry Andric args.GetArgumentAtIndex(0)); 19160b57cec5SDimitry Andric return false; 19170b57cec5SDimitry Andric } 19180b57cec5SDimitry Andric 19190b57cec5SDimitry Andric if (thread_plan_idx == 0) { 19200b57cec5SDimitry Andric result.AppendErrorWithFormat( 19210b57cec5SDimitry Andric "You wouldn't really want me to discard the base thread plan."); 19220b57cec5SDimitry Andric return false; 19230b57cec5SDimitry Andric } 19240b57cec5SDimitry Andric 19250b57cec5SDimitry Andric if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) { 19260b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 19270b57cec5SDimitry Andric return true; 19280b57cec5SDimitry Andric } else { 19290b57cec5SDimitry Andric result.AppendErrorWithFormat( 19300b57cec5SDimitry Andric "Could not find User thread plan with index %s.", 19310b57cec5SDimitry Andric args.GetArgumentAtIndex(0)); 19320b57cec5SDimitry Andric return false; 19330b57cec5SDimitry Andric } 19340b57cec5SDimitry Andric } 19350b57cec5SDimitry Andric }; 19360b57cec5SDimitry Andric 19375ffd83dbSDimitry Andric class CommandObjectThreadPlanPrune : public CommandObjectParsed { 19385ffd83dbSDimitry Andric public: 19395ffd83dbSDimitry Andric CommandObjectThreadPlanPrune(CommandInterpreter &interpreter) 19405ffd83dbSDimitry Andric : CommandObjectParsed(interpreter, "thread plan prune", 19415ffd83dbSDimitry Andric "Removes any thread plans associated with " 19425ffd83dbSDimitry Andric "currently unreported threads. " 19435ffd83dbSDimitry Andric "Specify one or more TID's to remove, or if no " 19445ffd83dbSDimitry Andric "TID's are provides, remove threads for all " 19455ffd83dbSDimitry Andric "unreported threads", 19465ffd83dbSDimitry Andric nullptr, 19475ffd83dbSDimitry Andric eCommandRequiresProcess | 19485ffd83dbSDimitry Andric eCommandTryTargetAPILock | 19495ffd83dbSDimitry Andric eCommandProcessMustBeLaunched | 19505ffd83dbSDimitry Andric eCommandProcessMustBePaused) { 19515ffd83dbSDimitry Andric CommandArgumentEntry arg; 19525ffd83dbSDimitry Andric CommandArgumentData tid_arg; 19535ffd83dbSDimitry Andric 19545ffd83dbSDimitry Andric // Define the first (and only) variant of this arg. 19555ffd83dbSDimitry Andric tid_arg.arg_type = eArgTypeThreadID; 19565ffd83dbSDimitry Andric tid_arg.arg_repetition = eArgRepeatStar; 19575ffd83dbSDimitry Andric 19585ffd83dbSDimitry Andric // There is only one variant this argument could be; put it into the 19595ffd83dbSDimitry Andric // argument entry. 19605ffd83dbSDimitry Andric arg.push_back(tid_arg); 19615ffd83dbSDimitry Andric 19625ffd83dbSDimitry Andric // Push the data for the first argument into the m_arguments vector. 19635ffd83dbSDimitry Andric m_arguments.push_back(arg); 19645ffd83dbSDimitry Andric } 19655ffd83dbSDimitry Andric 19665ffd83dbSDimitry Andric ~CommandObjectThreadPlanPrune() override = default; 19675ffd83dbSDimitry Andric 19685ffd83dbSDimitry Andric bool DoExecute(Args &args, CommandReturnObject &result) override { 19695ffd83dbSDimitry Andric Process *process = m_exe_ctx.GetProcessPtr(); 19705ffd83dbSDimitry Andric 19715ffd83dbSDimitry Andric if (args.GetArgumentCount() == 0) { 19725ffd83dbSDimitry Andric process->PruneThreadPlans(); 19735ffd83dbSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 19745ffd83dbSDimitry Andric return true; 19755ffd83dbSDimitry Andric } 19765ffd83dbSDimitry Andric 19775ffd83dbSDimitry Andric const size_t num_args = args.GetArgumentCount(); 19785ffd83dbSDimitry Andric 19795ffd83dbSDimitry Andric std::lock_guard<std::recursive_mutex> guard( 19805ffd83dbSDimitry Andric process->GetThreadList().GetMutex()); 19815ffd83dbSDimitry Andric 19825ffd83dbSDimitry Andric for (size_t i = 0; i < num_args; i++) { 19835ffd83dbSDimitry Andric lldb::tid_t tid; 19845ffd83dbSDimitry Andric if (!llvm::to_integer(args.GetArgumentAtIndex(i), tid)) { 19855ffd83dbSDimitry Andric result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", 19865ffd83dbSDimitry Andric args.GetArgumentAtIndex(i)); 19875ffd83dbSDimitry Andric return false; 19885ffd83dbSDimitry Andric } 19895ffd83dbSDimitry Andric if (!process->PruneThreadPlansForTID(tid)) { 19905ffd83dbSDimitry Andric result.AppendErrorWithFormat("Could not find unreported tid: \"%s\"\n", 19915ffd83dbSDimitry Andric args.GetArgumentAtIndex(i)); 19925ffd83dbSDimitry Andric return false; 19935ffd83dbSDimitry Andric } 19945ffd83dbSDimitry Andric } 19955ffd83dbSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult); 19965ffd83dbSDimitry Andric return true; 19975ffd83dbSDimitry Andric } 19985ffd83dbSDimitry Andric }; 19995ffd83dbSDimitry Andric 20000b57cec5SDimitry Andric // CommandObjectMultiwordThreadPlan 20010b57cec5SDimitry Andric 20020b57cec5SDimitry Andric class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword { 20030b57cec5SDimitry Andric public: 20040b57cec5SDimitry Andric CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter) 20050b57cec5SDimitry Andric : CommandObjectMultiword( 20060b57cec5SDimitry Andric interpreter, "plan", 20070b57cec5SDimitry Andric "Commands for managing thread plans that control execution.", 20080b57cec5SDimitry Andric "thread plan <subcommand> [<subcommand objects]") { 20090b57cec5SDimitry Andric LoadSubCommand( 20100b57cec5SDimitry Andric "list", CommandObjectSP(new CommandObjectThreadPlanList(interpreter))); 20110b57cec5SDimitry Andric LoadSubCommand( 20120b57cec5SDimitry Andric "discard", 20130b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadPlanDiscard(interpreter))); 20145ffd83dbSDimitry Andric LoadSubCommand( 20155ffd83dbSDimitry Andric "prune", 20165ffd83dbSDimitry Andric CommandObjectSP(new CommandObjectThreadPlanPrune(interpreter))); 20170b57cec5SDimitry Andric } 20180b57cec5SDimitry Andric 20190b57cec5SDimitry Andric ~CommandObjectMultiwordThreadPlan() override = default; 20200b57cec5SDimitry Andric }; 20210b57cec5SDimitry Andric 2022e8d8bef9SDimitry Andric // Next are the subcommands of CommandObjectMultiwordTrace 2023e8d8bef9SDimitry Andric 2024fe6060f1SDimitry Andric // CommandObjectTraceExport 2025fe6060f1SDimitry Andric 2026fe6060f1SDimitry Andric class CommandObjectTraceExport : public CommandObjectMultiword { 2027fe6060f1SDimitry Andric public: 2028fe6060f1SDimitry Andric CommandObjectTraceExport(CommandInterpreter &interpreter) 2029fe6060f1SDimitry Andric : CommandObjectMultiword( 2030fe6060f1SDimitry Andric interpreter, "trace thread export", 2031fe6060f1SDimitry Andric "Commands for exporting traces of the threads in the current " 2032fe6060f1SDimitry Andric "process to different formats.", 2033fe6060f1SDimitry Andric "thread trace export <export-plugin> [<subcommand objects>]") { 2034fe6060f1SDimitry Andric 2035349cc55cSDimitry Andric unsigned i = 0; 2036349cc55cSDimitry Andric for (llvm::StringRef plugin_name = 203781ad6265SDimitry Andric PluginManager::GetTraceExporterPluginNameAtIndex(i); 2038349cc55cSDimitry Andric !plugin_name.empty(); 2039349cc55cSDimitry Andric plugin_name = PluginManager::GetTraceExporterPluginNameAtIndex(i++)) { 2040fe6060f1SDimitry Andric if (ThreadTraceExportCommandCreator command_creator = 2041fe6060f1SDimitry Andric PluginManager::GetThreadTraceExportCommandCreatorAtIndex(i)) { 2042fe6060f1SDimitry Andric LoadSubCommand(plugin_name, command_creator(interpreter)); 2043fe6060f1SDimitry Andric } 2044fe6060f1SDimitry Andric } 2045fe6060f1SDimitry Andric } 2046fe6060f1SDimitry Andric }; 2047fe6060f1SDimitry Andric 2048e8d8bef9SDimitry Andric // CommandObjectTraceStart 2049e8d8bef9SDimitry Andric 2050fe6060f1SDimitry Andric class CommandObjectTraceStart : public CommandObjectTraceProxy { 2051e8d8bef9SDimitry Andric public: 2052e8d8bef9SDimitry Andric CommandObjectTraceStart(CommandInterpreter &interpreter) 2053fe6060f1SDimitry Andric : CommandObjectTraceProxy( 2054fe6060f1SDimitry Andric /*live_debug_session_only=*/true, interpreter, "thread trace start", 2055e8d8bef9SDimitry Andric "Start tracing threads with the corresponding trace " 2056e8d8bef9SDimitry Andric "plug-in for the current process.", 2057e8d8bef9SDimitry Andric "thread trace start [<trace-options>]") {} 2058e8d8bef9SDimitry Andric 2059e8d8bef9SDimitry Andric protected: 2060fe6060f1SDimitry Andric lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override { 2061fe6060f1SDimitry Andric return trace.GetThreadTraceStartCommand(m_interpreter); 2062e8d8bef9SDimitry Andric } 2063e8d8bef9SDimitry Andric }; 2064e8d8bef9SDimitry Andric 2065e8d8bef9SDimitry Andric // CommandObjectTraceStop 2066e8d8bef9SDimitry Andric 2067fe6060f1SDimitry Andric class CommandObjectTraceStop : public CommandObjectMultipleThreads { 2068e8d8bef9SDimitry Andric public: 2069e8d8bef9SDimitry Andric CommandObjectTraceStop(CommandInterpreter &interpreter) 2070fe6060f1SDimitry Andric : CommandObjectMultipleThreads( 2071e8d8bef9SDimitry Andric interpreter, "thread trace stop", 2072fe6060f1SDimitry Andric "Stop tracing threads, including the ones traced with the " 2073fe6060f1SDimitry Andric "\"process trace start\" command." 2074e8d8bef9SDimitry Andric "Defaults to the current thread. Thread indices can be " 2075fe6060f1SDimitry Andric "specified as arguments.\n Use the thread-index \"all\" to stop " 2076fe6060f1SDimitry Andric "tracing " 2077fe6060f1SDimitry Andric "for all existing threads.", 2078e8d8bef9SDimitry Andric "thread trace stop [<thread-index> <thread-index> ...]", 2079e8d8bef9SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 2080e8d8bef9SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | 2081e8d8bef9SDimitry Andric eCommandProcessMustBeTraced) {} 2082e8d8bef9SDimitry Andric 2083e8d8bef9SDimitry Andric ~CommandObjectTraceStop() override = default; 2084e8d8bef9SDimitry Andric 2085fe6060f1SDimitry Andric bool DoExecuteOnThreads(Args &command, CommandReturnObject &result, 2086fe6060f1SDimitry Andric llvm::ArrayRef<lldb::tid_t> tids) override { 2087fe6060f1SDimitry Andric ProcessSP process_sp = m_exe_ctx.GetProcessSP(); 2088e8d8bef9SDimitry Andric 2089fe6060f1SDimitry Andric TraceSP trace_sp = process_sp->GetTarget().GetTrace(); 2090e8d8bef9SDimitry Andric 2091fe6060f1SDimitry Andric if (llvm::Error err = trace_sp->Stop(tids)) 2092fe6060f1SDimitry Andric result.AppendError(toString(std::move(err))); 2093fe6060f1SDimitry Andric else 2094fe6060f1SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult); 2095fe6060f1SDimitry Andric 2096fe6060f1SDimitry Andric return result.Succeeded(); 2097e8d8bef9SDimitry Andric } 2098e8d8bef9SDimitry Andric }; 2099e8d8bef9SDimitry Andric 2100bdd1243dSDimitry Andric static ThreadSP GetSingleThreadFromArgs(ExecutionContext &exe_ctx, Args &args, 2101bdd1243dSDimitry Andric CommandReturnObject &result) { 2102bdd1243dSDimitry Andric if (args.GetArgumentCount() == 0) 2103bdd1243dSDimitry Andric return exe_ctx.GetThreadSP(); 2104bdd1243dSDimitry Andric 2105bdd1243dSDimitry Andric const char *arg = args.GetArgumentAtIndex(0); 2106bdd1243dSDimitry Andric uint32_t thread_idx; 2107bdd1243dSDimitry Andric 2108bdd1243dSDimitry Andric if (!llvm::to_integer(arg, thread_idx)) { 2109bdd1243dSDimitry Andric result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", arg); 2110bdd1243dSDimitry Andric return nullptr; 2111bdd1243dSDimitry Andric } 2112bdd1243dSDimitry Andric ThreadSP thread_sp = 2113bdd1243dSDimitry Andric exe_ctx.GetProcessRef().GetThreadList().FindThreadByIndexID(thread_idx); 2114bdd1243dSDimitry Andric if (!thread_sp) 2115bdd1243dSDimitry Andric result.AppendErrorWithFormat("no thread with index: \"%s\"\n", arg); 2116bdd1243dSDimitry Andric return thread_sp; 2117bdd1243dSDimitry Andric } 2118bdd1243dSDimitry Andric 2119bdd1243dSDimitry Andric // CommandObjectTraceDumpFunctionCalls 2120bdd1243dSDimitry Andric #define LLDB_OPTIONS_thread_trace_dump_function_calls 2121bdd1243dSDimitry Andric #include "CommandOptions.inc" 2122bdd1243dSDimitry Andric 2123bdd1243dSDimitry Andric class CommandObjectTraceDumpFunctionCalls : public CommandObjectParsed { 2124bdd1243dSDimitry Andric public: 2125bdd1243dSDimitry Andric class CommandOptions : public Options { 2126bdd1243dSDimitry Andric public: 2127bdd1243dSDimitry Andric CommandOptions() { OptionParsingStarting(nullptr); } 2128bdd1243dSDimitry Andric 2129bdd1243dSDimitry Andric ~CommandOptions() override = default; 2130bdd1243dSDimitry Andric 2131bdd1243dSDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2132bdd1243dSDimitry Andric ExecutionContext *execution_context) override { 2133bdd1243dSDimitry Andric Status error; 2134bdd1243dSDimitry Andric const int short_option = m_getopt_table[option_idx].val; 2135bdd1243dSDimitry Andric 2136bdd1243dSDimitry Andric switch (short_option) { 2137bdd1243dSDimitry Andric case 'j': { 2138bdd1243dSDimitry Andric m_dumper_options.json = true; 2139bdd1243dSDimitry Andric break; 2140bdd1243dSDimitry Andric } 2141bdd1243dSDimitry Andric case 'J': { 2142bdd1243dSDimitry Andric m_dumper_options.json = true; 2143bdd1243dSDimitry Andric m_dumper_options.pretty_print_json = true; 2144bdd1243dSDimitry Andric break; 2145bdd1243dSDimitry Andric } 2146bdd1243dSDimitry Andric case 'F': { 2147bdd1243dSDimitry Andric m_output_file.emplace(option_arg); 2148bdd1243dSDimitry Andric break; 2149bdd1243dSDimitry Andric } 2150bdd1243dSDimitry Andric default: 2151bdd1243dSDimitry Andric llvm_unreachable("Unimplemented option"); 2152bdd1243dSDimitry Andric } 2153bdd1243dSDimitry Andric return error; 2154bdd1243dSDimitry Andric } 2155bdd1243dSDimitry Andric 2156bdd1243dSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 2157bdd1243dSDimitry Andric m_dumper_options = {}; 2158bdd1243dSDimitry Andric m_output_file = std::nullopt; 2159bdd1243dSDimitry Andric } 2160bdd1243dSDimitry Andric 2161bdd1243dSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2162bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_trace_dump_function_calls_options); 2163bdd1243dSDimitry Andric } 2164bdd1243dSDimitry Andric 2165bdd1243dSDimitry Andric static const size_t kDefaultCount = 20; 2166bdd1243dSDimitry Andric 2167bdd1243dSDimitry Andric // Instance variables to hold the values for command options. 2168bdd1243dSDimitry Andric TraceDumperOptions m_dumper_options; 2169bdd1243dSDimitry Andric std::optional<FileSpec> m_output_file; 2170bdd1243dSDimitry Andric }; 2171bdd1243dSDimitry Andric 2172bdd1243dSDimitry Andric CommandObjectTraceDumpFunctionCalls(CommandInterpreter &interpreter) 2173bdd1243dSDimitry Andric : CommandObjectParsed( 2174bdd1243dSDimitry Andric interpreter, "thread trace dump function-calls", 2175bdd1243dSDimitry Andric "Dump the traced function-calls for one thread. If no " 2176bdd1243dSDimitry Andric "thread is specified, the current thread is used.", 2177bdd1243dSDimitry Andric nullptr, 2178bdd1243dSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 2179bdd1243dSDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 2180bdd1243dSDimitry Andric eCommandProcessMustBePaused | eCommandProcessMustBeTraced) { 2181bdd1243dSDimitry Andric CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatOptional}; 2182bdd1243dSDimitry Andric m_arguments.push_back({thread_arg}); 2183bdd1243dSDimitry Andric } 2184bdd1243dSDimitry Andric 2185bdd1243dSDimitry Andric ~CommandObjectTraceDumpFunctionCalls() override = default; 2186bdd1243dSDimitry Andric 2187bdd1243dSDimitry Andric Options *GetOptions() override { return &m_options; } 2188bdd1243dSDimitry Andric 2189bdd1243dSDimitry Andric protected: 2190bdd1243dSDimitry Andric bool DoExecute(Args &args, CommandReturnObject &result) override { 2191bdd1243dSDimitry Andric ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result); 2192bdd1243dSDimitry Andric if (!thread_sp) { 2193bdd1243dSDimitry Andric result.AppendError("invalid thread\n"); 2194bdd1243dSDimitry Andric return false; 2195bdd1243dSDimitry Andric } 2196bdd1243dSDimitry Andric 2197bdd1243dSDimitry Andric llvm::Expected<TraceCursorSP> cursor_or_error = 2198bdd1243dSDimitry Andric m_exe_ctx.GetTargetSP()->GetTrace()->CreateNewCursor(*thread_sp); 2199bdd1243dSDimitry Andric 2200bdd1243dSDimitry Andric if (!cursor_or_error) { 2201bdd1243dSDimitry Andric result.AppendError(llvm::toString(cursor_or_error.takeError())); 2202bdd1243dSDimitry Andric return false; 2203bdd1243dSDimitry Andric } 2204bdd1243dSDimitry Andric TraceCursorSP &cursor_sp = *cursor_or_error; 2205bdd1243dSDimitry Andric 2206bdd1243dSDimitry Andric std::optional<StreamFile> out_file; 2207bdd1243dSDimitry Andric if (m_options.m_output_file) { 2208bdd1243dSDimitry Andric out_file.emplace(m_options.m_output_file->GetPath().c_str(), 2209bdd1243dSDimitry Andric File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate | 2210bdd1243dSDimitry Andric File::eOpenOptionTruncate); 2211bdd1243dSDimitry Andric } 2212bdd1243dSDimitry Andric 2213bdd1243dSDimitry Andric m_options.m_dumper_options.forwards = true; 2214bdd1243dSDimitry Andric 2215bdd1243dSDimitry Andric TraceDumper dumper(std::move(cursor_sp), 2216bdd1243dSDimitry Andric out_file ? *out_file : result.GetOutputStream(), 2217bdd1243dSDimitry Andric m_options.m_dumper_options); 2218bdd1243dSDimitry Andric 2219bdd1243dSDimitry Andric dumper.DumpFunctionCalls(); 2220bdd1243dSDimitry Andric return true; 2221bdd1243dSDimitry Andric } 2222bdd1243dSDimitry Andric 2223bdd1243dSDimitry Andric CommandOptions m_options; 2224bdd1243dSDimitry Andric }; 2225bdd1243dSDimitry Andric 2226e8d8bef9SDimitry Andric // CommandObjectTraceDumpInstructions 2227e8d8bef9SDimitry Andric #define LLDB_OPTIONS_thread_trace_dump_instructions 2228e8d8bef9SDimitry Andric #include "CommandOptions.inc" 2229e8d8bef9SDimitry Andric 223081ad6265SDimitry Andric class CommandObjectTraceDumpInstructions : public CommandObjectParsed { 2231e8d8bef9SDimitry Andric public: 2232e8d8bef9SDimitry Andric class CommandOptions : public Options { 2233e8d8bef9SDimitry Andric public: 223404eeddc0SDimitry Andric CommandOptions() { OptionParsingStarting(nullptr); } 2235e8d8bef9SDimitry Andric 2236e8d8bef9SDimitry Andric ~CommandOptions() override = default; 2237e8d8bef9SDimitry Andric 2238e8d8bef9SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2239e8d8bef9SDimitry Andric ExecutionContext *execution_context) override { 2240e8d8bef9SDimitry Andric Status error; 2241e8d8bef9SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 2242e8d8bef9SDimitry Andric 2243e8d8bef9SDimitry Andric switch (short_option) { 2244e8d8bef9SDimitry Andric case 'c': { 2245e8d8bef9SDimitry Andric int32_t count; 2246e8d8bef9SDimitry Andric if (option_arg.empty() || option_arg.getAsInteger(0, count) || 2247e8d8bef9SDimitry Andric count < 0) 2248e8d8bef9SDimitry Andric error.SetErrorStringWithFormat( 2249e8d8bef9SDimitry Andric "invalid integer value for option '%s'", 2250e8d8bef9SDimitry Andric option_arg.str().c_str()); 2251e8d8bef9SDimitry Andric else 2252e8d8bef9SDimitry Andric m_count = count; 2253e8d8bef9SDimitry Andric break; 2254e8d8bef9SDimitry Andric } 225581ad6265SDimitry Andric case 'a': { 225681ad6265SDimitry Andric m_count = std::numeric_limits<decltype(m_count)>::max(); 225781ad6265SDimitry Andric break; 225881ad6265SDimitry Andric } 2259fe6060f1SDimitry Andric case 's': { 2260fe6060f1SDimitry Andric int32_t skip; 2261fe6060f1SDimitry Andric if (option_arg.empty() || option_arg.getAsInteger(0, skip) || skip < 0) 2262e8d8bef9SDimitry Andric error.SetErrorStringWithFormat( 2263e8d8bef9SDimitry Andric "invalid integer value for option '%s'", 2264e8d8bef9SDimitry Andric option_arg.str().c_str()); 2265e8d8bef9SDimitry Andric else 226681ad6265SDimitry Andric m_dumper_options.skip = skip; 226781ad6265SDimitry Andric break; 226881ad6265SDimitry Andric } 226981ad6265SDimitry Andric case 'i': { 227081ad6265SDimitry Andric uint64_t id; 227181ad6265SDimitry Andric if (option_arg.empty() || option_arg.getAsInteger(0, id)) 227281ad6265SDimitry Andric error.SetErrorStringWithFormat( 227381ad6265SDimitry Andric "invalid integer value for option '%s'", 227481ad6265SDimitry Andric option_arg.str().c_str()); 227581ad6265SDimitry Andric else 227681ad6265SDimitry Andric m_dumper_options.id = id; 227781ad6265SDimitry Andric break; 227881ad6265SDimitry Andric } 227981ad6265SDimitry Andric case 'F': { 228081ad6265SDimitry Andric m_output_file.emplace(option_arg); 2281e8d8bef9SDimitry Andric break; 2282e8d8bef9SDimitry Andric } 2283e8d8bef9SDimitry Andric case 'r': { 228481ad6265SDimitry Andric m_dumper_options.raw = true; 2285e8d8bef9SDimitry Andric break; 2286e8d8bef9SDimitry Andric } 2287fe6060f1SDimitry Andric case 'f': { 228881ad6265SDimitry Andric m_dumper_options.forwards = true; 2289fe6060f1SDimitry Andric break; 2290fe6060f1SDimitry Andric } 2291753f127fSDimitry Andric case 'k': { 2292753f127fSDimitry Andric m_dumper_options.show_control_flow_kind = true; 2293753f127fSDimitry Andric break; 2294753f127fSDimitry Andric } 2295fe6060f1SDimitry Andric case 't': { 2296972a253aSDimitry Andric m_dumper_options.show_timestamps = true; 229781ad6265SDimitry Andric break; 229881ad6265SDimitry Andric } 229981ad6265SDimitry Andric case 'e': { 230081ad6265SDimitry Andric m_dumper_options.show_events = true; 230181ad6265SDimitry Andric break; 230281ad6265SDimitry Andric } 230381ad6265SDimitry Andric case 'j': { 230481ad6265SDimitry Andric m_dumper_options.json = true; 230581ad6265SDimitry Andric break; 230681ad6265SDimitry Andric } 230781ad6265SDimitry Andric case 'J': { 230881ad6265SDimitry Andric m_dumper_options.pretty_print_json = true; 230981ad6265SDimitry Andric m_dumper_options.json = true; 231081ad6265SDimitry Andric break; 231181ad6265SDimitry Andric } 2312bdd1243dSDimitry Andric case 'E': { 2313bdd1243dSDimitry Andric m_dumper_options.only_events = true; 2314bdd1243dSDimitry Andric m_dumper_options.show_events = true; 2315bdd1243dSDimitry Andric break; 2316bdd1243dSDimitry Andric } 231781ad6265SDimitry Andric case 'C': { 231881ad6265SDimitry Andric m_continue = true; 2319fe6060f1SDimitry Andric break; 2320fe6060f1SDimitry Andric } 2321e8d8bef9SDimitry Andric default: 2322e8d8bef9SDimitry Andric llvm_unreachable("Unimplemented option"); 2323e8d8bef9SDimitry Andric } 2324e8d8bef9SDimitry Andric return error; 2325e8d8bef9SDimitry Andric } 2326e8d8bef9SDimitry Andric 2327e8d8bef9SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 2328e8d8bef9SDimitry Andric m_count = kDefaultCount; 232981ad6265SDimitry Andric m_continue = false; 2330bdd1243dSDimitry Andric m_output_file = std::nullopt; 233181ad6265SDimitry Andric m_dumper_options = {}; 2332e8d8bef9SDimitry Andric } 2333e8d8bef9SDimitry Andric 2334e8d8bef9SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2335bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_trace_dump_instructions_options); 2336e8d8bef9SDimitry Andric } 2337e8d8bef9SDimitry Andric 2338e8d8bef9SDimitry Andric static const size_t kDefaultCount = 20; 2339e8d8bef9SDimitry Andric 2340e8d8bef9SDimitry Andric // Instance variables to hold the values for command options. 2341e8d8bef9SDimitry Andric size_t m_count; 234281ad6265SDimitry Andric size_t m_continue; 2343bdd1243dSDimitry Andric std::optional<FileSpec> m_output_file; 234481ad6265SDimitry Andric TraceDumperOptions m_dumper_options; 2345e8d8bef9SDimitry Andric }; 2346e8d8bef9SDimitry Andric 2347e8d8bef9SDimitry Andric CommandObjectTraceDumpInstructions(CommandInterpreter &interpreter) 234881ad6265SDimitry Andric : CommandObjectParsed( 2349e8d8bef9SDimitry Andric interpreter, "thread trace dump instructions", 235081ad6265SDimitry Andric "Dump the traced instructions for one thread. If no " 235181ad6265SDimitry Andric "thread is specified, show the current thread.", 2352e8d8bef9SDimitry Andric nullptr, 235381ad6265SDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 235481ad6265SDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 235581ad6265SDimitry Andric eCommandProcessMustBePaused | eCommandProcessMustBeTraced) { 235681ad6265SDimitry Andric CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatOptional}; 235781ad6265SDimitry Andric m_arguments.push_back({thread_arg}); 235881ad6265SDimitry Andric } 2359e8d8bef9SDimitry Andric 2360e8d8bef9SDimitry Andric ~CommandObjectTraceDumpInstructions() override = default; 2361e8d8bef9SDimitry Andric 2362e8d8bef9SDimitry Andric Options *GetOptions() override { return &m_options; } 2363e8d8bef9SDimitry Andric 2364bdd1243dSDimitry Andric std::optional<std::string> GetRepeatCommand(Args ¤t_command_args, 2365e8d8bef9SDimitry Andric uint32_t index) override { 236681ad6265SDimitry Andric std::string cmd; 236781ad6265SDimitry Andric current_command_args.GetCommandString(cmd); 236881ad6265SDimitry Andric if (cmd.find(" --continue") == std::string::npos) 236981ad6265SDimitry Andric cmd += " --continue"; 237081ad6265SDimitry Andric return cmd; 2371e8d8bef9SDimitry Andric } 2372e8d8bef9SDimitry Andric 2373e8d8bef9SDimitry Andric protected: 237481ad6265SDimitry Andric bool DoExecute(Args &args, CommandReturnObject &result) override { 2375bdd1243dSDimitry Andric ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result); 237681ad6265SDimitry Andric if (!thread_sp) { 237781ad6265SDimitry Andric result.AppendError("invalid thread\n"); 237881ad6265SDimitry Andric return false; 237981ad6265SDimitry Andric } 238081ad6265SDimitry Andric 238181ad6265SDimitry Andric if (m_options.m_continue && m_last_id) { 238281ad6265SDimitry Andric // We set up the options to continue one instruction past where 238381ad6265SDimitry Andric // the previous iteration stopped. 238481ad6265SDimitry Andric m_options.m_dumper_options.skip = 1; 238581ad6265SDimitry Andric m_options.m_dumper_options.id = m_last_id; 238681ad6265SDimitry Andric } 238781ad6265SDimitry Andric 2388bdd1243dSDimitry Andric llvm::Expected<TraceCursorSP> cursor_or_error = 238981ad6265SDimitry Andric m_exe_ctx.GetTargetSP()->GetTrace()->CreateNewCursor(*thread_sp); 239081ad6265SDimitry Andric 239181ad6265SDimitry Andric if (!cursor_or_error) { 239281ad6265SDimitry Andric result.AppendError(llvm::toString(cursor_or_error.takeError())); 239381ad6265SDimitry Andric return false; 239481ad6265SDimitry Andric } 2395bdd1243dSDimitry Andric TraceCursorSP &cursor_sp = *cursor_or_error; 239681ad6265SDimitry Andric 239781ad6265SDimitry Andric if (m_options.m_dumper_options.id && 2398bdd1243dSDimitry Andric !cursor_sp->HasId(*m_options.m_dumper_options.id)) { 239981ad6265SDimitry Andric result.AppendError("invalid instruction id\n"); 240081ad6265SDimitry Andric return false; 240181ad6265SDimitry Andric } 240281ad6265SDimitry Andric 2403bdd1243dSDimitry Andric std::optional<StreamFile> out_file; 240481ad6265SDimitry Andric if (m_options.m_output_file) { 240581ad6265SDimitry Andric out_file.emplace(m_options.m_output_file->GetPath().c_str(), 2406bdd1243dSDimitry Andric File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate | 2407bdd1243dSDimitry Andric File::eOpenOptionTruncate); 240881ad6265SDimitry Andric } 240981ad6265SDimitry Andric 241081ad6265SDimitry Andric if (m_options.m_continue && !m_last_id) { 241181ad6265SDimitry Andric // We need to stop processing data when we already ran out of instructions 241281ad6265SDimitry Andric // in a previous command. We can fake this by setting the cursor past the 241381ad6265SDimitry Andric // end of the trace. 2414bdd1243dSDimitry Andric cursor_sp->Seek(1, lldb::eTraceCursorSeekTypeEnd); 241581ad6265SDimitry Andric } 241681ad6265SDimitry Andric 2417bdd1243dSDimitry Andric TraceDumper dumper(std::move(cursor_sp), 241881ad6265SDimitry Andric out_file ? *out_file : result.GetOutputStream(), 241981ad6265SDimitry Andric m_options.m_dumper_options); 242081ad6265SDimitry Andric 242181ad6265SDimitry Andric m_last_id = dumper.DumpInstructions(m_options.m_count); 2422e8d8bef9SDimitry Andric return true; 2423e8d8bef9SDimitry Andric } 2424e8d8bef9SDimitry Andric 2425e8d8bef9SDimitry Andric CommandOptions m_options; 2426*fe013be4SDimitry Andric // Last traversed id used to continue a repeat command. std::nullopt means 242781ad6265SDimitry Andric // that all the trace has been consumed. 2428bdd1243dSDimitry Andric std::optional<lldb::user_id_t> m_last_id; 2429fe6060f1SDimitry Andric }; 2430fe6060f1SDimitry Andric 2431fe6060f1SDimitry Andric // CommandObjectTraceDumpInfo 2432fe6060f1SDimitry Andric #define LLDB_OPTIONS_thread_trace_dump_info 2433fe6060f1SDimitry Andric #include "CommandOptions.inc" 2434fe6060f1SDimitry Andric 2435fe6060f1SDimitry Andric class CommandObjectTraceDumpInfo : public CommandObjectIterateOverThreads { 2436fe6060f1SDimitry Andric public: 2437fe6060f1SDimitry Andric class CommandOptions : public Options { 2438fe6060f1SDimitry Andric public: 243904eeddc0SDimitry Andric CommandOptions() { OptionParsingStarting(nullptr); } 2440fe6060f1SDimitry Andric 2441fe6060f1SDimitry Andric ~CommandOptions() override = default; 2442fe6060f1SDimitry Andric 2443fe6060f1SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2444fe6060f1SDimitry Andric ExecutionContext *execution_context) override { 2445fe6060f1SDimitry Andric Status error; 2446fe6060f1SDimitry Andric const int short_option = m_getopt_table[option_idx].val; 2447fe6060f1SDimitry Andric 2448fe6060f1SDimitry Andric switch (short_option) { 2449fe6060f1SDimitry Andric case 'v': { 2450fe6060f1SDimitry Andric m_verbose = true; 2451fe6060f1SDimitry Andric break; 2452fe6060f1SDimitry Andric } 2453753f127fSDimitry Andric case 'j': { 2454753f127fSDimitry Andric m_json = true; 2455753f127fSDimitry Andric break; 2456753f127fSDimitry Andric } 2457fe6060f1SDimitry Andric default: 2458fe6060f1SDimitry Andric llvm_unreachable("Unimplemented option"); 2459fe6060f1SDimitry Andric } 2460fe6060f1SDimitry Andric return error; 2461fe6060f1SDimitry Andric } 2462fe6060f1SDimitry Andric 2463fe6060f1SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 2464fe6060f1SDimitry Andric m_verbose = false; 2465753f127fSDimitry Andric m_json = false; 2466fe6060f1SDimitry Andric } 2467fe6060f1SDimitry Andric 2468fe6060f1SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2469bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_trace_dump_info_options); 2470fe6060f1SDimitry Andric } 2471fe6060f1SDimitry Andric 2472fe6060f1SDimitry Andric // Instance variables to hold the values for command options. 2473fe6060f1SDimitry Andric bool m_verbose; 2474753f127fSDimitry Andric bool m_json; 2475fe6060f1SDimitry Andric }; 2476fe6060f1SDimitry Andric 2477fe6060f1SDimitry Andric CommandObjectTraceDumpInfo(CommandInterpreter &interpreter) 2478fe6060f1SDimitry Andric : CommandObjectIterateOverThreads( 2479fe6060f1SDimitry Andric interpreter, "thread trace dump info", 2480fe6060f1SDimitry Andric "Dump the traced information for one or more threads. If no " 2481fe6060f1SDimitry Andric "threads are specified, show the current thread. Use the " 2482fe6060f1SDimitry Andric "thread-index \"all\" to see all threads.", 2483fe6060f1SDimitry Andric nullptr, 2484fe6060f1SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 2485fe6060f1SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | 248604eeddc0SDimitry Andric eCommandProcessMustBeTraced) {} 2487fe6060f1SDimitry Andric 2488fe6060f1SDimitry Andric ~CommandObjectTraceDumpInfo() override = default; 2489fe6060f1SDimitry Andric 2490fe6060f1SDimitry Andric Options *GetOptions() override { return &m_options; } 2491fe6060f1SDimitry Andric 2492fe6060f1SDimitry Andric protected: 2493fe6060f1SDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 2494fe6060f1SDimitry Andric const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace(); 2495fe6060f1SDimitry Andric ThreadSP thread_sp = 2496fe6060f1SDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 2497fe6060f1SDimitry Andric trace_sp->DumpTraceInfo(*thread_sp, result.GetOutputStream(), 2498753f127fSDimitry Andric m_options.m_verbose, m_options.m_json); 2499fe6060f1SDimitry Andric return true; 2500fe6060f1SDimitry Andric } 2501fe6060f1SDimitry Andric 2502fe6060f1SDimitry Andric CommandOptions m_options; 2503e8d8bef9SDimitry Andric }; 2504e8d8bef9SDimitry Andric 2505e8d8bef9SDimitry Andric // CommandObjectMultiwordTraceDump 2506e8d8bef9SDimitry Andric class CommandObjectMultiwordTraceDump : public CommandObjectMultiword { 2507e8d8bef9SDimitry Andric public: 2508e8d8bef9SDimitry Andric CommandObjectMultiwordTraceDump(CommandInterpreter &interpreter) 2509e8d8bef9SDimitry Andric : CommandObjectMultiword( 2510e8d8bef9SDimitry Andric interpreter, "dump", 2511e8d8bef9SDimitry Andric "Commands for displaying trace information of the threads " 2512e8d8bef9SDimitry Andric "in the current process.", 2513e8d8bef9SDimitry Andric "thread trace dump <subcommand> [<subcommand objects>]") { 2514e8d8bef9SDimitry Andric LoadSubCommand( 2515e8d8bef9SDimitry Andric "instructions", 2516e8d8bef9SDimitry Andric CommandObjectSP(new CommandObjectTraceDumpInstructions(interpreter))); 2517fe6060f1SDimitry Andric LoadSubCommand( 2518bdd1243dSDimitry Andric "function-calls", 2519bdd1243dSDimitry Andric CommandObjectSP(new CommandObjectTraceDumpFunctionCalls(interpreter))); 2520bdd1243dSDimitry Andric LoadSubCommand( 2521fe6060f1SDimitry Andric "info", CommandObjectSP(new CommandObjectTraceDumpInfo(interpreter))); 2522e8d8bef9SDimitry Andric } 2523e8d8bef9SDimitry Andric ~CommandObjectMultiwordTraceDump() override = default; 2524e8d8bef9SDimitry Andric }; 2525e8d8bef9SDimitry Andric 2526e8d8bef9SDimitry Andric // CommandObjectMultiwordTrace 2527e8d8bef9SDimitry Andric class CommandObjectMultiwordTrace : public CommandObjectMultiword { 2528e8d8bef9SDimitry Andric public: 2529e8d8bef9SDimitry Andric CommandObjectMultiwordTrace(CommandInterpreter &interpreter) 2530e8d8bef9SDimitry Andric : CommandObjectMultiword( 2531e8d8bef9SDimitry Andric interpreter, "trace", 2532e8d8bef9SDimitry Andric "Commands for operating on traces of the threads in the current " 2533e8d8bef9SDimitry Andric "process.", 2534e8d8bef9SDimitry Andric "thread trace <subcommand> [<subcommand objects>]") { 2535e8d8bef9SDimitry Andric LoadSubCommand("dump", CommandObjectSP(new CommandObjectMultiwordTraceDump( 2536e8d8bef9SDimitry Andric interpreter))); 2537e8d8bef9SDimitry Andric LoadSubCommand("start", 2538e8d8bef9SDimitry Andric CommandObjectSP(new CommandObjectTraceStart(interpreter))); 2539e8d8bef9SDimitry Andric LoadSubCommand("stop", 2540e8d8bef9SDimitry Andric CommandObjectSP(new CommandObjectTraceStop(interpreter))); 2541fe6060f1SDimitry Andric LoadSubCommand("export", 2542fe6060f1SDimitry Andric CommandObjectSP(new CommandObjectTraceExport(interpreter))); 2543e8d8bef9SDimitry Andric } 2544e8d8bef9SDimitry Andric 2545e8d8bef9SDimitry Andric ~CommandObjectMultiwordTrace() override = default; 2546e8d8bef9SDimitry Andric }; 2547e8d8bef9SDimitry Andric 25480b57cec5SDimitry Andric // CommandObjectMultiwordThread 25490b57cec5SDimitry Andric 25500b57cec5SDimitry Andric CommandObjectMultiwordThread::CommandObjectMultiwordThread( 25510b57cec5SDimitry Andric CommandInterpreter &interpreter) 2552480093f4SDimitry Andric : CommandObjectMultiword(interpreter, "thread", 2553480093f4SDimitry Andric "Commands for operating on " 25540b57cec5SDimitry Andric "one or more threads in " 25550b57cec5SDimitry Andric "the current process.", 25560b57cec5SDimitry Andric "thread <subcommand> [<subcommand-options>]") { 25570b57cec5SDimitry Andric LoadSubCommand("backtrace", CommandObjectSP(new CommandObjectThreadBacktrace( 25580b57cec5SDimitry Andric interpreter))); 25590b57cec5SDimitry Andric LoadSubCommand("continue", 25600b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadContinue(interpreter))); 25610b57cec5SDimitry Andric LoadSubCommand("list", 25620b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadList(interpreter))); 25630b57cec5SDimitry Andric LoadSubCommand("return", 25640b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadReturn(interpreter))); 25650b57cec5SDimitry Andric LoadSubCommand("jump", 25660b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadJump(interpreter))); 25670b57cec5SDimitry Andric LoadSubCommand("select", 25680b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadSelect(interpreter))); 25690b57cec5SDimitry Andric LoadSubCommand("until", 25700b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadUntil(interpreter))); 25710b57cec5SDimitry Andric LoadSubCommand("info", 25720b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadInfo(interpreter))); 2573480093f4SDimitry Andric LoadSubCommand("exception", CommandObjectSP(new CommandObjectThreadException( 2574480093f4SDimitry Andric interpreter))); 2575d56accc7SDimitry Andric LoadSubCommand("siginfo", 2576d56accc7SDimitry Andric CommandObjectSP(new CommandObjectThreadSiginfo(interpreter))); 25770b57cec5SDimitry Andric LoadSubCommand("step-in", 25780b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 25790b57cec5SDimitry Andric interpreter, "thread step-in", 25800b57cec5SDimitry Andric "Source level single step, stepping into calls. Defaults " 25810b57cec5SDimitry Andric "to current thread unless specified.", 25820b57cec5SDimitry Andric nullptr, eStepTypeInto, eStepScopeSource))); 25830b57cec5SDimitry Andric 25840b57cec5SDimitry Andric LoadSubCommand("step-out", 25850b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 25860b57cec5SDimitry Andric interpreter, "thread step-out", 25870b57cec5SDimitry Andric "Finish executing the current stack frame and stop after " 25880b57cec5SDimitry Andric "returning. Defaults to current thread unless specified.", 25890b57cec5SDimitry Andric nullptr, eStepTypeOut, eStepScopeSource))); 25900b57cec5SDimitry Andric 25910b57cec5SDimitry Andric LoadSubCommand("step-over", 25920b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 25930b57cec5SDimitry Andric interpreter, "thread step-over", 25940b57cec5SDimitry Andric "Source level single step, stepping over calls. Defaults " 25950b57cec5SDimitry Andric "to current thread unless specified.", 25960b57cec5SDimitry Andric nullptr, eStepTypeOver, eStepScopeSource))); 25970b57cec5SDimitry Andric 25980b57cec5SDimitry Andric LoadSubCommand("step-inst", 25990b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 26000b57cec5SDimitry Andric interpreter, "thread step-inst", 26010b57cec5SDimitry Andric "Instruction level single step, stepping into calls. " 26020b57cec5SDimitry Andric "Defaults to current thread unless specified.", 26030b57cec5SDimitry Andric nullptr, eStepTypeTrace, eStepScopeInstruction))); 26040b57cec5SDimitry Andric 26050b57cec5SDimitry Andric LoadSubCommand("step-inst-over", 26060b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 26070b57cec5SDimitry Andric interpreter, "thread step-inst-over", 26080b57cec5SDimitry Andric "Instruction level single step, stepping over calls. " 26090b57cec5SDimitry Andric "Defaults to current thread unless specified.", 26100b57cec5SDimitry Andric nullptr, eStepTypeTraceOver, eStepScopeInstruction))); 26110b57cec5SDimitry Andric 26120b57cec5SDimitry Andric LoadSubCommand( 26130b57cec5SDimitry Andric "step-scripted", 26140b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 26150b57cec5SDimitry Andric interpreter, "thread step-scripted", 26169dba64beSDimitry Andric "Step as instructed by the script class passed in the -C option. " 26179dba64beSDimitry Andric "You can also specify a dictionary of key (-k) and value (-v) pairs " 26189dba64beSDimitry Andric "that will be used to populate an SBStructuredData Dictionary, which " 26199dba64beSDimitry Andric "will be passed to the constructor of the class implementing the " 26209dba64beSDimitry Andric "scripted step. See the Python Reference for more details.", 26210b57cec5SDimitry Andric nullptr, eStepTypeScripted, eStepScopeSource))); 26220b57cec5SDimitry Andric 26230b57cec5SDimitry Andric LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan( 26240b57cec5SDimitry Andric interpreter))); 2625e8d8bef9SDimitry Andric LoadSubCommand("trace", 2626e8d8bef9SDimitry Andric CommandObjectSP(new CommandObjectMultiwordTrace(interpreter))); 26270b57cec5SDimitry Andric } 26280b57cec5SDimitry Andric 26290b57cec5SDimitry Andric CommandObjectMultiwordThread::~CommandObjectMultiwordThread() = default; 2630