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:
CommandOptions()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
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)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
OptionParsingStarting(ExecutionContext * execution_context)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
GetDefinitions()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
CommandObjectThreadBacktrace(CommandInterpreter & interpreter)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
GetOptions()1260b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; }
1270b57cec5SDimitry Andric
GetRepeatCommand(Args & current_args,uint32_t idx)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();
148*c9157d92SDimitry Andric if (arg_string.equals("-c") || count_opt.starts_with(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;
155*c9157d92SDimitry Andric } else if (arg_string.equals("-s") || start_opt.starts_with(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:
DoExtendedBacktrace(Thread * thread,CommandReturnObject & result)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
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)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) {
232fe013be4SDimitry Andric if (!INTERRUPT_REQUESTED(GetDebugger(),
233fe013be4SDimitry Andric "Interrupt skipped extended backtrace")) {
2340b57cec5SDimitry Andric DoExtendedBacktrace(thread, result);
2350b57cec5SDimitry Andric }
236fe013be4SDimitry 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:
ThreadStepScopeOptionGroup()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
GetDefinitions()2599dba64beSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
260bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_step_scope_options);
2619dba64beSDimitry Andric }
2620b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)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
OptionParsingStarting(ExecutionContext * execution_context)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:
CommandObjectThreadStepWithTypeAndScope(CommandInterpreter & interpreter,const char * name,const char * help,const char * syntax,StepType step_type,StepScope step_scope)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
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)402e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
403e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override {
404e8d8bef9SDimitry Andric if (request.GetCursorIndex())
405e8d8bef9SDimitry Andric return;
406e8d8bef9SDimitry Andric
407fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
408fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,
409fe013be4SDimitry Andric nullptr);
410e8d8bef9SDimitry Andric }
411e8d8bef9SDimitry Andric
GetOptions()412480093f4SDimitry Andric Options *GetOptions() override { return &m_all_options; }
4130b57cec5SDimitry Andric
4140b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)415*c9157d92SDimitry Andric void 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");
427*c9157d92SDimitry Andric return;
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);
436*c9157d92SDimitry Andric return;
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);
444*c9157d92SDimitry Andric return;
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.");
451*c9157d92SDimitry Andric return;
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());
457*c9157d92SDimitry Andric return;
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");
465*c9157d92SDimitry Andric return;
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());
497*c9157d92SDimitry Andric return;
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.");
504*c9157d92SDimitry Andric return;
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.");
513*c9157d92SDimitry Andric return;
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,
562fe013be4SDimitry Andric eVoteNoOpinion,
563fe013be4SDimitry Andric thread->GetSelectedFrameIndex(DoNoSelectMostRelevantFrame),
564fe013be4SDimitry 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");
572*c9157d92SDimitry Andric return;
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());
603*c9157d92SDimitry Andric return;
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 }
6280b57cec5SDimitry Andric
6290b57cec5SDimitry Andric StepType m_step_type;
6300b57cec5SDimitry Andric StepScope m_step_scope;
6319dba64beSDimitry Andric ThreadStepScopeOptionGroup m_options;
6329dba64beSDimitry Andric OptionGroupPythonClassWithDict m_class_options;
6339dba64beSDimitry Andric OptionGroupOptions m_all_options;
6340b57cec5SDimitry Andric };
6350b57cec5SDimitry Andric
6360b57cec5SDimitry Andric // CommandObjectThreadContinue
6370b57cec5SDimitry Andric
6380b57cec5SDimitry Andric class CommandObjectThreadContinue : public CommandObjectParsed {
6390b57cec5SDimitry Andric public:
CommandObjectThreadContinue(CommandInterpreter & interpreter)6400b57cec5SDimitry Andric CommandObjectThreadContinue(CommandInterpreter &interpreter)
6410b57cec5SDimitry Andric : CommandObjectParsed(
6420b57cec5SDimitry Andric interpreter, "thread continue",
6430b57cec5SDimitry Andric "Continue execution of the current target process. One "
6440b57cec5SDimitry Andric "or more threads may be specified, by default all "
6450b57cec5SDimitry Andric "threads continue.",
6460b57cec5SDimitry Andric nullptr,
6470b57cec5SDimitry Andric eCommandRequiresThread | eCommandTryTargetAPILock |
6480b57cec5SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
6490b57cec5SDimitry Andric CommandArgumentEntry arg;
6500b57cec5SDimitry Andric CommandArgumentData thread_idx_arg;
6510b57cec5SDimitry Andric
6520b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
6530b57cec5SDimitry Andric thread_idx_arg.arg_type = eArgTypeThreadIndex;
6540b57cec5SDimitry Andric thread_idx_arg.arg_repetition = eArgRepeatPlus;
6550b57cec5SDimitry Andric
6560b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
6570b57cec5SDimitry Andric // argument entry.
6580b57cec5SDimitry Andric arg.push_back(thread_idx_arg);
6590b57cec5SDimitry Andric
6600b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
6610b57cec5SDimitry Andric m_arguments.push_back(arg);
6620b57cec5SDimitry Andric }
6630b57cec5SDimitry Andric
6640b57cec5SDimitry Andric ~CommandObjectThreadContinue() override = default;
6650b57cec5SDimitry Andric
666e8d8bef9SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)667e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
668e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override {
669fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
670fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,
671fe013be4SDimitry Andric nullptr);
672e8d8bef9SDimitry Andric }
673e8d8bef9SDimitry Andric
DoExecute(Args & command,CommandReturnObject & result)674*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
6750b57cec5SDimitry Andric bool synchronous_execution = m_interpreter.GetSynchronous();
6760b57cec5SDimitry Andric
6770b57cec5SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr();
6780b57cec5SDimitry Andric if (process == nullptr) {
6790b57cec5SDimitry Andric result.AppendError("no process exists. Cannot continue");
680*c9157d92SDimitry Andric return;
6810b57cec5SDimitry Andric }
6820b57cec5SDimitry Andric
6830b57cec5SDimitry Andric StateType state = process->GetState();
6840b57cec5SDimitry Andric if ((state == eStateCrashed) || (state == eStateStopped) ||
6850b57cec5SDimitry Andric (state == eStateSuspended)) {
6860b57cec5SDimitry Andric const size_t argc = command.GetArgumentCount();
6870b57cec5SDimitry Andric if (argc > 0) {
6880b57cec5SDimitry Andric // These two lines appear at the beginning of both blocks in this
6890b57cec5SDimitry Andric // if..else, but that is because we need to release the lock before
6900b57cec5SDimitry Andric // calling process->Resume below.
6910b57cec5SDimitry Andric std::lock_guard<std::recursive_mutex> guard(
6920b57cec5SDimitry Andric process->GetThreadList().GetMutex());
6930b57cec5SDimitry Andric const uint32_t num_threads = process->GetThreadList().GetSize();
6940b57cec5SDimitry Andric std::vector<Thread *> resume_threads;
6950b57cec5SDimitry Andric for (auto &entry : command.entries()) {
6960b57cec5SDimitry Andric uint32_t thread_idx;
6979dba64beSDimitry Andric if (entry.ref().getAsInteger(0, thread_idx)) {
6980b57cec5SDimitry Andric result.AppendErrorWithFormat(
6990b57cec5SDimitry Andric "invalid thread index argument: \"%s\".\n", entry.c_str());
700*c9157d92SDimitry Andric return;
7010b57cec5SDimitry Andric }
7020b57cec5SDimitry Andric Thread *thread =
7030b57cec5SDimitry Andric process->GetThreadList().FindThreadByIndexID(thread_idx).get();
7040b57cec5SDimitry Andric
7050b57cec5SDimitry Andric if (thread) {
7060b57cec5SDimitry Andric resume_threads.push_back(thread);
7070b57cec5SDimitry Andric } else {
7080b57cec5SDimitry Andric result.AppendErrorWithFormat("invalid thread index %u.\n",
7090b57cec5SDimitry Andric thread_idx);
710*c9157d92SDimitry Andric return;
7110b57cec5SDimitry Andric }
7120b57cec5SDimitry Andric }
7130b57cec5SDimitry Andric
7140b57cec5SDimitry Andric if (resume_threads.empty()) {
7150b57cec5SDimitry Andric result.AppendError("no valid thread indexes were specified");
716*c9157d92SDimitry Andric return;
7170b57cec5SDimitry Andric } else {
7180b57cec5SDimitry Andric if (resume_threads.size() == 1)
7190b57cec5SDimitry Andric result.AppendMessageWithFormat("Resuming thread: ");
7200b57cec5SDimitry Andric else
7210b57cec5SDimitry Andric result.AppendMessageWithFormat("Resuming threads: ");
7220b57cec5SDimitry Andric
7230b57cec5SDimitry Andric for (uint32_t idx = 0; idx < num_threads; ++idx) {
7240b57cec5SDimitry Andric Thread *thread =
7250b57cec5SDimitry Andric process->GetThreadList().GetThreadAtIndex(idx).get();
7260b57cec5SDimitry Andric std::vector<Thread *>::iterator this_thread_pos =
7270b57cec5SDimitry Andric find(resume_threads.begin(), resume_threads.end(), thread);
7280b57cec5SDimitry Andric
7290b57cec5SDimitry Andric if (this_thread_pos != resume_threads.end()) {
7300b57cec5SDimitry Andric resume_threads.erase(this_thread_pos);
7310b57cec5SDimitry Andric if (!resume_threads.empty())
7320b57cec5SDimitry Andric result.AppendMessageWithFormat("%u, ", thread->GetIndexID());
7330b57cec5SDimitry Andric else
7340b57cec5SDimitry Andric result.AppendMessageWithFormat("%u ", thread->GetIndexID());
7350b57cec5SDimitry Andric
7360b57cec5SDimitry Andric const bool override_suspend = true;
7370b57cec5SDimitry Andric thread->SetResumeState(eStateRunning, override_suspend);
7380b57cec5SDimitry Andric } else {
7390b57cec5SDimitry Andric thread->SetResumeState(eStateSuspended);
7400b57cec5SDimitry Andric }
7410b57cec5SDimitry Andric }
7420b57cec5SDimitry Andric result.AppendMessageWithFormat("in process %" PRIu64 "\n",
7430b57cec5SDimitry Andric process->GetID());
7440b57cec5SDimitry Andric }
7450b57cec5SDimitry Andric } else {
7460b57cec5SDimitry Andric // These two lines appear at the beginning of both blocks in this
7470b57cec5SDimitry Andric // if..else, but that is because we need to release the lock before
7480b57cec5SDimitry Andric // calling process->Resume below.
7490b57cec5SDimitry Andric std::lock_guard<std::recursive_mutex> guard(
7500b57cec5SDimitry Andric process->GetThreadList().GetMutex());
7510b57cec5SDimitry Andric const uint32_t num_threads = process->GetThreadList().GetSize();
7520b57cec5SDimitry Andric Thread *current_thread = GetDefaultThread();
7530b57cec5SDimitry Andric if (current_thread == nullptr) {
7540b57cec5SDimitry Andric result.AppendError("the process doesn't have a current thread");
755*c9157d92SDimitry Andric return;
7560b57cec5SDimitry Andric }
7570b57cec5SDimitry Andric // Set the actions that the threads should each take when resuming
7580b57cec5SDimitry Andric for (uint32_t idx = 0; idx < num_threads; ++idx) {
7590b57cec5SDimitry Andric Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
7600b57cec5SDimitry Andric if (thread == current_thread) {
7610b57cec5SDimitry Andric result.AppendMessageWithFormat("Resuming thread 0x%4.4" PRIx64
7620b57cec5SDimitry Andric " in process %" PRIu64 "\n",
7630b57cec5SDimitry Andric thread->GetID(), process->GetID());
7640b57cec5SDimitry Andric const bool override_suspend = true;
7650b57cec5SDimitry Andric thread->SetResumeState(eStateRunning, override_suspend);
7660b57cec5SDimitry Andric } else {
7670b57cec5SDimitry Andric thread->SetResumeState(eStateSuspended);
7680b57cec5SDimitry Andric }
7690b57cec5SDimitry Andric }
7700b57cec5SDimitry Andric }
7710b57cec5SDimitry Andric
7720b57cec5SDimitry Andric StreamString stream;
7730b57cec5SDimitry Andric Status error;
7740b57cec5SDimitry Andric if (synchronous_execution)
7750b57cec5SDimitry Andric error = process->ResumeSynchronous(&stream);
7760b57cec5SDimitry Andric else
7770b57cec5SDimitry Andric error = process->Resume();
7780b57cec5SDimitry Andric
7790b57cec5SDimitry Andric // We should not be holding the thread list lock when we do this.
7800b57cec5SDimitry Andric if (error.Success()) {
7810b57cec5SDimitry Andric result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",
7820b57cec5SDimitry Andric process->GetID());
7830b57cec5SDimitry Andric if (synchronous_execution) {
7840b57cec5SDimitry Andric // If any state changed events had anything to say, add that to the
7850b57cec5SDimitry Andric // result
7860b57cec5SDimitry Andric if (stream.GetSize() > 0)
7870b57cec5SDimitry Andric result.AppendMessage(stream.GetString());
7880b57cec5SDimitry Andric
7890b57cec5SDimitry Andric result.SetDidChangeProcessState(true);
7900b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
7910b57cec5SDimitry Andric } else {
7920b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessContinuingNoResult);
7930b57cec5SDimitry Andric }
7940b57cec5SDimitry Andric } else {
7950b57cec5SDimitry Andric result.AppendErrorWithFormat("Failed to resume process: %s\n",
7960b57cec5SDimitry Andric error.AsCString());
7970b57cec5SDimitry Andric }
7980b57cec5SDimitry Andric } else {
7990b57cec5SDimitry Andric result.AppendErrorWithFormat(
8000b57cec5SDimitry Andric "Process cannot be continued from its current state (%s).\n",
8010b57cec5SDimitry Andric StateAsCString(state));
8020b57cec5SDimitry Andric }
8030b57cec5SDimitry Andric }
8040b57cec5SDimitry Andric };
8050b57cec5SDimitry Andric
8060b57cec5SDimitry Andric // CommandObjectThreadUntil
8070b57cec5SDimitry Andric
8080b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_until
8090b57cec5SDimitry Andric #include "CommandOptions.inc"
8100b57cec5SDimitry Andric
8110b57cec5SDimitry Andric class CommandObjectThreadUntil : public CommandObjectParsed {
8120b57cec5SDimitry Andric public:
8130b57cec5SDimitry Andric class CommandOptions : public Options {
8140b57cec5SDimitry Andric public:
815fe6060f1SDimitry Andric uint32_t m_thread_idx = LLDB_INVALID_THREAD_ID;
816fe6060f1SDimitry Andric uint32_t m_frame_idx = LLDB_INVALID_FRAME_ID;
8170b57cec5SDimitry Andric
CommandOptions()81804eeddc0SDimitry Andric CommandOptions() {
8190b57cec5SDimitry Andric // Keep default values of all options in one place: OptionParsingStarting
8200b57cec5SDimitry Andric // ()
8210b57cec5SDimitry Andric OptionParsingStarting(nullptr);
8220b57cec5SDimitry Andric }
8230b57cec5SDimitry Andric
8240b57cec5SDimitry Andric ~CommandOptions() override = default;
8250b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)8260b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
8270b57cec5SDimitry Andric ExecutionContext *execution_context) override {
8280b57cec5SDimitry Andric Status error;
8290b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
8300b57cec5SDimitry Andric
8310b57cec5SDimitry Andric switch (short_option) {
8320b57cec5SDimitry Andric case 'a': {
8330b57cec5SDimitry Andric lldb::addr_t tmp_addr = OptionArgParser::ToAddress(
8340b57cec5SDimitry Andric execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
8350b57cec5SDimitry Andric if (error.Success())
8360b57cec5SDimitry Andric m_until_addrs.push_back(tmp_addr);
8370b57cec5SDimitry Andric } break;
8380b57cec5SDimitry Andric case 't':
8390b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_thread_idx)) {
8400b57cec5SDimitry Andric m_thread_idx = LLDB_INVALID_INDEX32;
8410b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid thread index '%s'",
8420b57cec5SDimitry Andric option_arg.str().c_str());
8430b57cec5SDimitry Andric }
8440b57cec5SDimitry Andric break;
8450b57cec5SDimitry Andric case 'f':
8460b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_frame_idx)) {
8470b57cec5SDimitry Andric m_frame_idx = LLDB_INVALID_FRAME_ID;
8480b57cec5SDimitry Andric error.SetErrorStringWithFormat("invalid frame index '%s'",
8490b57cec5SDimitry Andric option_arg.str().c_str());
8500b57cec5SDimitry Andric }
8510b57cec5SDimitry Andric break;
8520b57cec5SDimitry Andric case 'm': {
8530b57cec5SDimitry Andric auto enum_values = GetDefinitions()[option_idx].enum_values;
8540b57cec5SDimitry Andric lldb::RunMode run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(
8550b57cec5SDimitry Andric option_arg, enum_values, eOnlyDuringStepping, error);
8560b57cec5SDimitry Andric
8570b57cec5SDimitry Andric if (error.Success()) {
8580b57cec5SDimitry Andric if (run_mode == eAllThreads)
8590b57cec5SDimitry Andric m_stop_others = false;
8600b57cec5SDimitry Andric else
8610b57cec5SDimitry Andric m_stop_others = true;
8620b57cec5SDimitry Andric }
8630b57cec5SDimitry Andric } break;
8640b57cec5SDimitry Andric default:
8659dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
8660b57cec5SDimitry Andric }
8670b57cec5SDimitry Andric return error;
8680b57cec5SDimitry Andric }
8690b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)8700b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
8710b57cec5SDimitry Andric m_thread_idx = LLDB_INVALID_THREAD_ID;
8720b57cec5SDimitry Andric m_frame_idx = 0;
8730b57cec5SDimitry Andric m_stop_others = false;
8740b57cec5SDimitry Andric m_until_addrs.clear();
8750b57cec5SDimitry Andric }
8760b57cec5SDimitry Andric
GetDefinitions()8770b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
878bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_until_options);
8790b57cec5SDimitry Andric }
8800b57cec5SDimitry Andric
881fcaf7f86SDimitry Andric uint32_t m_step_thread_idx = LLDB_INVALID_THREAD_ID;
882fcaf7f86SDimitry Andric bool m_stop_others = false;
8830b57cec5SDimitry Andric std::vector<lldb::addr_t> m_until_addrs;
8840b57cec5SDimitry Andric
8850b57cec5SDimitry Andric // Instance variables to hold the values for command options.
8860b57cec5SDimitry Andric };
8870b57cec5SDimitry Andric
CommandObjectThreadUntil(CommandInterpreter & interpreter)8880b57cec5SDimitry Andric CommandObjectThreadUntil(CommandInterpreter &interpreter)
8890b57cec5SDimitry Andric : CommandObjectParsed(
8900b57cec5SDimitry Andric interpreter, "thread until",
8910b57cec5SDimitry Andric "Continue until a line number or address is reached by the "
8920b57cec5SDimitry Andric "current or specified thread. Stops when returning from "
8930b57cec5SDimitry Andric "the current function as a safety measure. "
894480093f4SDimitry Andric "The target line number(s) are given as arguments, and if more "
895480093f4SDimitry Andric "than one"
8960b57cec5SDimitry Andric " is provided, stepping will stop when the first one is hit.",
8970b57cec5SDimitry Andric nullptr,
8980b57cec5SDimitry Andric eCommandRequiresThread | eCommandTryTargetAPILock |
89904eeddc0SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
9000b57cec5SDimitry Andric CommandArgumentEntry arg;
9010b57cec5SDimitry Andric CommandArgumentData line_num_arg;
9020b57cec5SDimitry Andric
9030b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
9040b57cec5SDimitry Andric line_num_arg.arg_type = eArgTypeLineNum;
9050b57cec5SDimitry Andric line_num_arg.arg_repetition = eArgRepeatPlain;
9060b57cec5SDimitry Andric
9070b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
9080b57cec5SDimitry Andric // argument entry.
9090b57cec5SDimitry Andric arg.push_back(line_num_arg);
9100b57cec5SDimitry Andric
9110b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
9120b57cec5SDimitry Andric m_arguments.push_back(arg);
9130b57cec5SDimitry Andric }
9140b57cec5SDimitry Andric
9150b57cec5SDimitry Andric ~CommandObjectThreadUntil() override = default;
9160b57cec5SDimitry Andric
GetOptions()9170b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; }
9180b57cec5SDimitry Andric
9190b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)920*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
9210b57cec5SDimitry Andric bool synchronous_execution = m_interpreter.GetSynchronous();
9220b57cec5SDimitry Andric
9239dba64beSDimitry Andric Target *target = &GetSelectedTarget();
9240b57cec5SDimitry Andric
9250b57cec5SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr();
9260b57cec5SDimitry Andric if (process == nullptr) {
9270b57cec5SDimitry Andric result.AppendError("need a valid process to step");
9280b57cec5SDimitry Andric } else {
9290b57cec5SDimitry Andric Thread *thread = nullptr;
9300b57cec5SDimitry Andric std::vector<uint32_t> line_numbers;
9310b57cec5SDimitry Andric
9320b57cec5SDimitry Andric if (command.GetArgumentCount() >= 1) {
9330b57cec5SDimitry Andric size_t num_args = command.GetArgumentCount();
9340b57cec5SDimitry Andric for (size_t i = 0; i < num_args; i++) {
9350b57cec5SDimitry Andric uint32_t line_number;
9365ffd83dbSDimitry Andric if (!llvm::to_integer(command.GetArgumentAtIndex(i), line_number)) {
9370b57cec5SDimitry Andric result.AppendErrorWithFormat("invalid line number: '%s'.\n",
9380b57cec5SDimitry Andric command.GetArgumentAtIndex(i));
939*c9157d92SDimitry Andric return;
9400b57cec5SDimitry Andric } else
9410b57cec5SDimitry Andric line_numbers.push_back(line_number);
9420b57cec5SDimitry Andric }
9430b57cec5SDimitry Andric } else if (m_options.m_until_addrs.empty()) {
9440b57cec5SDimitry Andric result.AppendErrorWithFormat("No line number or address provided:\n%s",
9450b57cec5SDimitry Andric GetSyntax().str().c_str());
946*c9157d92SDimitry Andric return;
9470b57cec5SDimitry Andric }
9480b57cec5SDimitry Andric
9490b57cec5SDimitry Andric if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) {
9500b57cec5SDimitry Andric thread = GetDefaultThread();
9510b57cec5SDimitry Andric } else {
9520b57cec5SDimitry Andric thread = process->GetThreadList()
9530b57cec5SDimitry Andric .FindThreadByIndexID(m_options.m_thread_idx)
9540b57cec5SDimitry Andric .get();
9550b57cec5SDimitry Andric }
9560b57cec5SDimitry Andric
9570b57cec5SDimitry Andric if (thread == nullptr) {
9580b57cec5SDimitry Andric const uint32_t num_threads = process->GetThreadList().GetSize();
9590b57cec5SDimitry Andric result.AppendErrorWithFormat(
9600b57cec5SDimitry Andric "Thread index %u is out of range (valid values are 0 - %u).\n",
9610b57cec5SDimitry Andric m_options.m_thread_idx, num_threads);
962*c9157d92SDimitry Andric return;
9630b57cec5SDimitry Andric }
9640b57cec5SDimitry Andric
9650b57cec5SDimitry Andric const bool abort_other_plans = false;
9660b57cec5SDimitry Andric
9670b57cec5SDimitry Andric StackFrame *frame =
9680b57cec5SDimitry Andric thread->GetStackFrameAtIndex(m_options.m_frame_idx).get();
9690b57cec5SDimitry Andric if (frame == nullptr) {
9700b57cec5SDimitry Andric result.AppendErrorWithFormat(
97181ad6265SDimitry Andric "Frame index %u is out of range for thread id %" PRIu64 ".\n",
97281ad6265SDimitry Andric m_options.m_frame_idx, thread->GetID());
973*c9157d92SDimitry Andric return;
9740b57cec5SDimitry Andric }
9750b57cec5SDimitry Andric
9760b57cec5SDimitry Andric ThreadPlanSP new_plan_sp;
9770b57cec5SDimitry Andric Status new_plan_status;
9780b57cec5SDimitry Andric
9790b57cec5SDimitry Andric if (frame->HasDebugInformation()) {
9800b57cec5SDimitry Andric // Finally we got here... Translate the given line number to a bunch
9810b57cec5SDimitry Andric // of addresses:
9820b57cec5SDimitry Andric SymbolContext sc(frame->GetSymbolContext(eSymbolContextCompUnit));
9830b57cec5SDimitry Andric LineTable *line_table = nullptr;
9840b57cec5SDimitry Andric if (sc.comp_unit)
9850b57cec5SDimitry Andric line_table = sc.comp_unit->GetLineTable();
9860b57cec5SDimitry Andric
9870b57cec5SDimitry Andric if (line_table == nullptr) {
9880b57cec5SDimitry Andric result.AppendErrorWithFormat("Failed to resolve the line table for "
98981ad6265SDimitry Andric "frame %u of thread id %" PRIu64 ".\n",
99081ad6265SDimitry Andric m_options.m_frame_idx, thread->GetID());
991*c9157d92SDimitry Andric return;
9920b57cec5SDimitry Andric }
9930b57cec5SDimitry Andric
9940b57cec5SDimitry Andric LineEntry function_start;
995bdd1243dSDimitry Andric uint32_t index_ptr = 0, end_ptr = UINT32_MAX;
9960b57cec5SDimitry Andric std::vector<addr_t> address_list;
9970b57cec5SDimitry Andric
99881ad6265SDimitry Andric // Find the beginning & end index of the function, but first make
99981ad6265SDimitry Andric // sure it is valid:
100081ad6265SDimitry Andric if (!sc.function) {
100181ad6265SDimitry Andric result.AppendErrorWithFormat("Have debug information but no "
100281ad6265SDimitry Andric "function info - can't get until range.");
1003*c9157d92SDimitry Andric return;
100481ad6265SDimitry Andric }
100581ad6265SDimitry Andric
10060b57cec5SDimitry Andric AddressRange fun_addr_range = sc.function->GetAddressRange();
10070b57cec5SDimitry Andric Address fun_start_addr = fun_addr_range.GetBaseAddress();
10080b57cec5SDimitry Andric line_table->FindLineEntryByAddress(fun_start_addr, function_start,
10090b57cec5SDimitry Andric &index_ptr);
10100b57cec5SDimitry Andric
10110b57cec5SDimitry Andric Address fun_end_addr(fun_start_addr.GetSection(),
10120b57cec5SDimitry Andric fun_start_addr.GetOffset() +
10130b57cec5SDimitry Andric fun_addr_range.GetByteSize());
10140b57cec5SDimitry Andric
10150b57cec5SDimitry Andric bool all_in_function = true;
10160b57cec5SDimitry Andric
10170b57cec5SDimitry Andric line_table->FindLineEntryByAddress(fun_end_addr, function_start,
10180b57cec5SDimitry Andric &end_ptr);
10190b57cec5SDimitry Andric
1020753f127fSDimitry Andric // Since not all source lines will contribute code, check if we are
1021753f127fSDimitry Andric // setting the breakpoint on the exact line number or the nearest
1022753f127fSDimitry Andric // subsequent line number and set breakpoints at all the line table
1023753f127fSDimitry Andric // entries of the chosen line number (exact or nearest subsequent).
10240b57cec5SDimitry Andric for (uint32_t line_number : line_numbers) {
10250b57cec5SDimitry Andric LineEntry line_entry;
1026753f127fSDimitry Andric bool exact = false;
1027753f127fSDimitry Andric uint32_t start_idx_ptr = index_ptr;
1028753f127fSDimitry Andric start_idx_ptr = sc.comp_unit->FindLineEntry(
1029753f127fSDimitry Andric index_ptr, line_number, nullptr, exact, &line_entry);
1030753f127fSDimitry Andric if (start_idx_ptr != UINT32_MAX)
1031753f127fSDimitry Andric line_number = line_entry.line;
1032753f127fSDimitry Andric exact = true;
1033753f127fSDimitry Andric start_idx_ptr = index_ptr;
1034753f127fSDimitry Andric while (start_idx_ptr <= end_ptr) {
10350b57cec5SDimitry Andric start_idx_ptr = sc.comp_unit->FindLineEntry(
1036480093f4SDimitry Andric start_idx_ptr, line_number, nullptr, exact, &line_entry);
10370b57cec5SDimitry Andric if (start_idx_ptr == UINT32_MAX)
10380b57cec5SDimitry Andric break;
10390b57cec5SDimitry Andric
10400b57cec5SDimitry Andric addr_t address =
10410b57cec5SDimitry Andric line_entry.range.GetBaseAddress().GetLoadAddress(target);
10420b57cec5SDimitry Andric if (address != LLDB_INVALID_ADDRESS) {
10430b57cec5SDimitry Andric if (fun_addr_range.ContainsLoadAddress(address, target))
10440b57cec5SDimitry Andric address_list.push_back(address);
10450b57cec5SDimitry Andric else
10460b57cec5SDimitry Andric all_in_function = false;
10470b57cec5SDimitry Andric }
10480b57cec5SDimitry Andric start_idx_ptr++;
10490b57cec5SDimitry Andric }
10500b57cec5SDimitry Andric }
10510b57cec5SDimitry Andric
10520b57cec5SDimitry Andric for (lldb::addr_t address : m_options.m_until_addrs) {
10530b57cec5SDimitry Andric if (fun_addr_range.ContainsLoadAddress(address, target))
10540b57cec5SDimitry Andric address_list.push_back(address);
10550b57cec5SDimitry Andric else
10560b57cec5SDimitry Andric all_in_function = false;
10570b57cec5SDimitry Andric }
10580b57cec5SDimitry Andric
10590b57cec5SDimitry Andric if (address_list.empty()) {
10600b57cec5SDimitry Andric if (all_in_function)
10610b57cec5SDimitry Andric result.AppendErrorWithFormat(
10620b57cec5SDimitry Andric "No line entries matching until target.\n");
10630b57cec5SDimitry Andric else
10640b57cec5SDimitry Andric result.AppendErrorWithFormat(
10650b57cec5SDimitry Andric "Until target outside of the current function.\n");
10660b57cec5SDimitry Andric
1067*c9157d92SDimitry Andric return;
10680b57cec5SDimitry Andric }
10690b57cec5SDimitry Andric
10700b57cec5SDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepUntil(
10710b57cec5SDimitry Andric abort_other_plans, &address_list.front(), address_list.size(),
10720b57cec5SDimitry Andric m_options.m_stop_others, m_options.m_frame_idx, new_plan_status);
10730b57cec5SDimitry Andric if (new_plan_sp) {
1074349cc55cSDimitry Andric // User level plans should be controlling plans so they can be
1075349cc55cSDimitry Andric // interrupted
10760b57cec5SDimitry Andric // (e.g. by hitting a breakpoint) and other plans executed by the
10770b57cec5SDimitry Andric // user (stepping around the breakpoint) and then a "continue" will
10780b57cec5SDimitry Andric // resume the original plan.
1079349cc55cSDimitry Andric new_plan_sp->SetIsControllingPlan(true);
10800b57cec5SDimitry Andric new_plan_sp->SetOkayToDiscard(false);
10810b57cec5SDimitry Andric } else {
10820b57cec5SDimitry Andric result.SetError(new_plan_status);
1083*c9157d92SDimitry Andric return;
10840b57cec5SDimitry Andric }
10850b57cec5SDimitry Andric } else {
108681ad6265SDimitry Andric result.AppendErrorWithFormat("Frame index %u of thread id %" PRIu64
108781ad6265SDimitry Andric " has no debug information.\n",
108881ad6265SDimitry Andric m_options.m_frame_idx, thread->GetID());
1089*c9157d92SDimitry Andric return;
10900b57cec5SDimitry Andric }
10910b57cec5SDimitry Andric
109281ad6265SDimitry Andric if (!process->GetThreadList().SetSelectedThreadByID(thread->GetID())) {
109381ad6265SDimitry Andric result.AppendErrorWithFormat(
109481ad6265SDimitry Andric "Failed to set the selected thread to thread id %" PRIu64 ".\n",
109581ad6265SDimitry Andric thread->GetID());
1096*c9157d92SDimitry Andric return;
109781ad6265SDimitry Andric }
10980b57cec5SDimitry Andric
10990b57cec5SDimitry Andric StreamString stream;
11000b57cec5SDimitry Andric Status error;
11010b57cec5SDimitry Andric if (synchronous_execution)
11020b57cec5SDimitry Andric error = process->ResumeSynchronous(&stream);
11030b57cec5SDimitry Andric else
11040b57cec5SDimitry Andric error = process->Resume();
11050b57cec5SDimitry Andric
11060b57cec5SDimitry Andric if (error.Success()) {
11070b57cec5SDimitry Andric result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",
11080b57cec5SDimitry Andric process->GetID());
11090b57cec5SDimitry Andric if (synchronous_execution) {
11100b57cec5SDimitry Andric // If any state changed events had anything to say, add that to the
11110b57cec5SDimitry Andric // result
11120b57cec5SDimitry Andric if (stream.GetSize() > 0)
11130b57cec5SDimitry Andric result.AppendMessage(stream.GetString());
11140b57cec5SDimitry Andric
11150b57cec5SDimitry Andric result.SetDidChangeProcessState(true);
11160b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
11170b57cec5SDimitry Andric } else {
11180b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessContinuingNoResult);
11190b57cec5SDimitry Andric }
11200b57cec5SDimitry Andric } else {
11210b57cec5SDimitry Andric result.AppendErrorWithFormat("Failed to resume process: %s.\n",
11220b57cec5SDimitry Andric error.AsCString());
11230b57cec5SDimitry Andric }
11240b57cec5SDimitry Andric }
11250b57cec5SDimitry Andric }
11260b57cec5SDimitry Andric
11270b57cec5SDimitry Andric CommandOptions m_options;
11280b57cec5SDimitry Andric };
11290b57cec5SDimitry Andric
11300b57cec5SDimitry Andric // CommandObjectThreadSelect
11310b57cec5SDimitry Andric
1132*c9157d92SDimitry Andric #define LLDB_OPTIONS_thread_select
1133*c9157d92SDimitry Andric #include "CommandOptions.inc"
1134*c9157d92SDimitry Andric
11350b57cec5SDimitry Andric class CommandObjectThreadSelect : public CommandObjectParsed {
11360b57cec5SDimitry Andric public:
1137*c9157d92SDimitry Andric class OptionGroupThreadSelect : public OptionGroup {
1138*c9157d92SDimitry Andric public:
OptionGroupThreadSelect()1139*c9157d92SDimitry Andric OptionGroupThreadSelect() { OptionParsingStarting(nullptr); }
1140*c9157d92SDimitry Andric
1141*c9157d92SDimitry Andric ~OptionGroupThreadSelect() override = default;
1142*c9157d92SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)1143*c9157d92SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
1144*c9157d92SDimitry Andric m_thread_id = LLDB_INVALID_THREAD_ID;
1145*c9157d92SDimitry Andric }
1146*c9157d92SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1147*c9157d92SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1148*c9157d92SDimitry Andric ExecutionContext *execution_context) override {
1149*c9157d92SDimitry Andric const int short_option = g_thread_select_options[option_idx].short_option;
1150*c9157d92SDimitry Andric switch (short_option) {
1151*c9157d92SDimitry Andric case 't': {
1152*c9157d92SDimitry Andric if (option_arg.getAsInteger(0, m_thread_id)) {
1153*c9157d92SDimitry Andric m_thread_id = LLDB_INVALID_THREAD_ID;
1154*c9157d92SDimitry Andric return Status("Invalid thread ID: '%s'.", option_arg.str().c_str());
1155*c9157d92SDimitry Andric }
1156*c9157d92SDimitry Andric break;
1157*c9157d92SDimitry Andric }
1158*c9157d92SDimitry Andric
1159*c9157d92SDimitry Andric default:
1160*c9157d92SDimitry Andric llvm_unreachable("Unimplemented option");
1161*c9157d92SDimitry Andric }
1162*c9157d92SDimitry Andric
1163*c9157d92SDimitry Andric return {};
1164*c9157d92SDimitry Andric }
1165*c9157d92SDimitry Andric
GetDefinitions()1166*c9157d92SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1167*c9157d92SDimitry Andric return llvm::ArrayRef(g_thread_select_options);
1168*c9157d92SDimitry Andric }
1169*c9157d92SDimitry Andric
1170*c9157d92SDimitry Andric lldb::tid_t m_thread_id;
1171*c9157d92SDimitry Andric };
1172*c9157d92SDimitry Andric
CommandObjectThreadSelect(CommandInterpreter & interpreter)11730b57cec5SDimitry Andric CommandObjectThreadSelect(CommandInterpreter &interpreter)
11740b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "thread select",
1175*c9157d92SDimitry Andric "Change the currently selected thread.",
1176*c9157d92SDimitry Andric "thread select <thread-index> (or -t <thread-id>)",
11770b57cec5SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock |
11780b57cec5SDimitry Andric eCommandProcessMustBeLaunched |
11790b57cec5SDimitry Andric eCommandProcessMustBePaused) {
11800b57cec5SDimitry Andric CommandArgumentEntry arg;
11810b57cec5SDimitry Andric CommandArgumentData thread_idx_arg;
11820b57cec5SDimitry Andric
11830b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
11840b57cec5SDimitry Andric thread_idx_arg.arg_type = eArgTypeThreadIndex;
11850b57cec5SDimitry Andric thread_idx_arg.arg_repetition = eArgRepeatPlain;
1186*c9157d92SDimitry Andric thread_idx_arg.arg_opt_set_association = LLDB_OPT_SET_1;
11870b57cec5SDimitry Andric
11880b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
11890b57cec5SDimitry Andric // argument entry.
11900b57cec5SDimitry Andric arg.push_back(thread_idx_arg);
11910b57cec5SDimitry Andric
11920b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
11930b57cec5SDimitry Andric m_arguments.push_back(arg);
1194*c9157d92SDimitry Andric
1195*c9157d92SDimitry Andric m_option_group.Append(&m_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1196*c9157d92SDimitry Andric m_option_group.Finalize();
11970b57cec5SDimitry Andric }
11980b57cec5SDimitry Andric
11990b57cec5SDimitry Andric ~CommandObjectThreadSelect() override = default;
12000b57cec5SDimitry Andric
1201e8d8bef9SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1202e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
1203e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override {
1204e8d8bef9SDimitry Andric if (request.GetCursorIndex())
1205e8d8bef9SDimitry Andric return;
1206e8d8bef9SDimitry Andric
1207fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1208fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,
1209fe013be4SDimitry Andric nullptr);
1210e8d8bef9SDimitry Andric }
1211e8d8bef9SDimitry Andric
GetOptions()1212*c9157d92SDimitry Andric Options *GetOptions() override { return &m_option_group; }
1213*c9157d92SDimitry Andric
12140b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)1215*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
12160b57cec5SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr();
12170b57cec5SDimitry Andric if (process == nullptr) {
12180b57cec5SDimitry Andric result.AppendError("no process");
1219*c9157d92SDimitry Andric return;
1220*c9157d92SDimitry Andric } else if (m_options.m_thread_id == LLDB_INVALID_THREAD_ID &&
1221*c9157d92SDimitry Andric command.GetArgumentCount() != 1) {
12220b57cec5SDimitry Andric result.AppendErrorWithFormat(
1223*c9157d92SDimitry Andric "'%s' takes exactly one thread index argument, or a thread ID "
1224*c9157d92SDimitry Andric "option:\nUsage: %s\n",
12250b57cec5SDimitry Andric m_cmd_name.c_str(), m_cmd_syntax.c_str());
1226*c9157d92SDimitry Andric return;
1227*c9157d92SDimitry Andric } else if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID &&
1228*c9157d92SDimitry Andric command.GetArgumentCount() != 0) {
1229*c9157d92SDimitry Andric result.AppendErrorWithFormat("'%s' cannot take both a thread ID option "
1230*c9157d92SDimitry Andric "and a thread index argument:\nUsage: %s\n",
1231*c9157d92SDimitry Andric m_cmd_name.c_str(), m_cmd_syntax.c_str());
1232*c9157d92SDimitry Andric return;
12330b57cec5SDimitry Andric }
12340b57cec5SDimitry Andric
1235*c9157d92SDimitry Andric Thread *new_thread = nullptr;
1236*c9157d92SDimitry Andric if (command.GetArgumentCount() == 1) {
12375ffd83dbSDimitry Andric uint32_t index_id;
12385ffd83dbSDimitry Andric if (!llvm::to_integer(command.GetArgumentAtIndex(0), index_id)) {
12395ffd83dbSDimitry Andric result.AppendErrorWithFormat("Invalid thread index '%s'",
12405ffd83dbSDimitry Andric command.GetArgumentAtIndex(0));
1241*c9157d92SDimitry Andric return;
12425ffd83dbSDimitry Andric }
1243*c9157d92SDimitry Andric new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get();
12440b57cec5SDimitry Andric if (new_thread == nullptr) {
1245*c9157d92SDimitry Andric result.AppendErrorWithFormat("Invalid thread index #%s.\n",
12460b57cec5SDimitry Andric command.GetArgumentAtIndex(0));
1247*c9157d92SDimitry Andric return;
1248*c9157d92SDimitry Andric }
1249*c9157d92SDimitry Andric } else {
1250*c9157d92SDimitry Andric new_thread =
1251*c9157d92SDimitry Andric process->GetThreadList().FindThreadByID(m_options.m_thread_id).get();
1252*c9157d92SDimitry Andric if (new_thread == nullptr) {
1253*c9157d92SDimitry Andric result.AppendErrorWithFormat("Invalid thread ID %" PRIu64 ".\n",
1254*c9157d92SDimitry Andric m_options.m_thread_id);
1255*c9157d92SDimitry Andric return;
1256*c9157d92SDimitry Andric }
12570b57cec5SDimitry Andric }
12580b57cec5SDimitry Andric
12590b57cec5SDimitry Andric process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true);
12600b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
12610b57cec5SDimitry Andric }
1262*c9157d92SDimitry Andric
1263*c9157d92SDimitry Andric OptionGroupThreadSelect m_options;
1264*c9157d92SDimitry Andric OptionGroupOptions m_option_group;
12650b57cec5SDimitry Andric };
12660b57cec5SDimitry Andric
12670b57cec5SDimitry Andric // CommandObjectThreadList
12680b57cec5SDimitry Andric
12690b57cec5SDimitry Andric class CommandObjectThreadList : public CommandObjectParsed {
12700b57cec5SDimitry Andric public:
CommandObjectThreadList(CommandInterpreter & interpreter)12710b57cec5SDimitry Andric CommandObjectThreadList(CommandInterpreter &interpreter)
12720b57cec5SDimitry Andric : CommandObjectParsed(
12730b57cec5SDimitry Andric interpreter, "thread list",
12740b57cec5SDimitry Andric "Show a summary of each thread in the current target process. "
12750b57cec5SDimitry Andric "Use 'settings set thread-format' to customize the individual "
12760b57cec5SDimitry Andric "thread listings.",
12770b57cec5SDimitry Andric "thread list",
12780b57cec5SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock |
12790b57cec5SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
12800b57cec5SDimitry Andric
12810b57cec5SDimitry Andric ~CommandObjectThreadList() override = default;
12820b57cec5SDimitry Andric
12830b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)1284*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
12850b57cec5SDimitry Andric Stream &strm = result.GetOutputStream();
12860b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
12870b57cec5SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr();
12880b57cec5SDimitry Andric const bool only_threads_with_stop_reason = false;
12890b57cec5SDimitry Andric const uint32_t start_frame = 0;
12900b57cec5SDimitry Andric const uint32_t num_frames = 0;
12910b57cec5SDimitry Andric const uint32_t num_frames_with_source = 0;
12920b57cec5SDimitry Andric process->GetStatus(strm);
12930b57cec5SDimitry Andric process->GetThreadStatus(strm, only_threads_with_stop_reason, start_frame,
12940b57cec5SDimitry Andric num_frames, num_frames_with_source, false);
12950b57cec5SDimitry Andric }
12960b57cec5SDimitry Andric };
12970b57cec5SDimitry Andric
12980b57cec5SDimitry Andric // CommandObjectThreadInfo
12990b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_info
13000b57cec5SDimitry Andric #include "CommandOptions.inc"
13010b57cec5SDimitry Andric
13020b57cec5SDimitry Andric class CommandObjectThreadInfo : public CommandObjectIterateOverThreads {
13030b57cec5SDimitry Andric public:
13040b57cec5SDimitry Andric class CommandOptions : public Options {
13050b57cec5SDimitry Andric public:
CommandOptions()130604eeddc0SDimitry Andric CommandOptions() { OptionParsingStarting(nullptr); }
13070b57cec5SDimitry Andric
13080b57cec5SDimitry Andric ~CommandOptions() override = default;
13090b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)13100b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
13110b57cec5SDimitry Andric m_json_thread = false;
13120b57cec5SDimitry Andric m_json_stopinfo = false;
13130b57cec5SDimitry Andric }
13140b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)13150b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
13160b57cec5SDimitry Andric ExecutionContext *execution_context) override {
13170b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
13180b57cec5SDimitry Andric Status error;
13190b57cec5SDimitry Andric
13200b57cec5SDimitry Andric switch (short_option) {
13210b57cec5SDimitry Andric case 'j':
13220b57cec5SDimitry Andric m_json_thread = true;
13230b57cec5SDimitry Andric break;
13240b57cec5SDimitry Andric
13250b57cec5SDimitry Andric case 's':
13260b57cec5SDimitry Andric m_json_stopinfo = true;
13270b57cec5SDimitry Andric break;
13280b57cec5SDimitry Andric
13290b57cec5SDimitry Andric default:
13309dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
13310b57cec5SDimitry Andric }
13320b57cec5SDimitry Andric return error;
13330b57cec5SDimitry Andric }
13340b57cec5SDimitry Andric
GetDefinitions()13350b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1336bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_info_options);
13370b57cec5SDimitry Andric }
13380b57cec5SDimitry Andric
13390b57cec5SDimitry Andric bool m_json_thread;
13400b57cec5SDimitry Andric bool m_json_stopinfo;
13410b57cec5SDimitry Andric };
13420b57cec5SDimitry Andric
CommandObjectThreadInfo(CommandInterpreter & interpreter)13430b57cec5SDimitry Andric CommandObjectThreadInfo(CommandInterpreter &interpreter)
13440b57cec5SDimitry Andric : CommandObjectIterateOverThreads(
1345480093f4SDimitry Andric interpreter, "thread info",
1346480093f4SDimitry Andric "Show an extended summary of one or "
13470b57cec5SDimitry Andric "more threads. Defaults to the "
13480b57cec5SDimitry Andric "current thread.",
13490b57cec5SDimitry Andric "thread info",
13500b57cec5SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock |
135104eeddc0SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
13520b57cec5SDimitry Andric m_add_return = false;
13530b57cec5SDimitry Andric }
13540b57cec5SDimitry Andric
13550b57cec5SDimitry Andric ~CommandObjectThreadInfo() override = default;
13560b57cec5SDimitry Andric
1357e8d8bef9SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1358e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
1359e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override {
1360fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1361fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,
1362fe013be4SDimitry Andric nullptr);
1363e8d8bef9SDimitry Andric }
1364e8d8bef9SDimitry Andric
GetOptions()13650b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; }
13660b57cec5SDimitry Andric
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)13670b57cec5SDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
13680b57cec5SDimitry Andric ThreadSP thread_sp =
13690b57cec5SDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
13700b57cec5SDimitry Andric if (!thread_sp) {
13710b57cec5SDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
13720b57cec5SDimitry Andric tid);
13730b57cec5SDimitry Andric return false;
13740b57cec5SDimitry Andric }
13750b57cec5SDimitry Andric
13760b57cec5SDimitry Andric Thread *thread = thread_sp.get();
13770b57cec5SDimitry Andric
13780b57cec5SDimitry Andric Stream &strm = result.GetOutputStream();
13790b57cec5SDimitry Andric if (!thread->GetDescription(strm, eDescriptionLevelFull,
13800b57cec5SDimitry Andric m_options.m_json_thread,
13810b57cec5SDimitry Andric m_options.m_json_stopinfo)) {
13820b57cec5SDimitry Andric result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n",
13830b57cec5SDimitry Andric thread->GetIndexID());
13840b57cec5SDimitry Andric return false;
13850b57cec5SDimitry Andric }
13860b57cec5SDimitry Andric return true;
13870b57cec5SDimitry Andric }
13880b57cec5SDimitry Andric
13890b57cec5SDimitry Andric CommandOptions m_options;
13900b57cec5SDimitry Andric };
13910b57cec5SDimitry Andric
13920b57cec5SDimitry Andric // CommandObjectThreadException
13930b57cec5SDimitry Andric
13940b57cec5SDimitry Andric class CommandObjectThreadException : public CommandObjectIterateOverThreads {
13950b57cec5SDimitry Andric public:
CommandObjectThreadException(CommandInterpreter & interpreter)13960b57cec5SDimitry Andric CommandObjectThreadException(CommandInterpreter &interpreter)
13970b57cec5SDimitry Andric : CommandObjectIterateOverThreads(
13980b57cec5SDimitry Andric interpreter, "thread exception",
13990b57cec5SDimitry Andric "Display the current exception object for a thread. Defaults to "
14000b57cec5SDimitry Andric "the current thread.",
14010b57cec5SDimitry Andric "thread exception",
14020b57cec5SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock |
14030b57cec5SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
14040b57cec5SDimitry Andric
14050b57cec5SDimitry Andric ~CommandObjectThreadException() override = default;
14060b57cec5SDimitry Andric
1407e8d8bef9SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1408e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
1409e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override {
1410fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1411fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,
1412fe013be4SDimitry Andric nullptr);
1413e8d8bef9SDimitry Andric }
1414e8d8bef9SDimitry Andric
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)14150b57cec5SDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
14160b57cec5SDimitry Andric ThreadSP thread_sp =
14170b57cec5SDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
14180b57cec5SDimitry Andric if (!thread_sp) {
14190b57cec5SDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
14200b57cec5SDimitry Andric tid);
14210b57cec5SDimitry Andric return false;
14220b57cec5SDimitry Andric }
14230b57cec5SDimitry Andric
14240b57cec5SDimitry Andric Stream &strm = result.GetOutputStream();
14250b57cec5SDimitry Andric ValueObjectSP exception_object_sp = thread_sp->GetCurrentException();
14260b57cec5SDimitry Andric if (exception_object_sp) {
14270b57cec5SDimitry Andric exception_object_sp->Dump(strm);
14280b57cec5SDimitry Andric }
14290b57cec5SDimitry Andric
14300b57cec5SDimitry Andric ThreadSP exception_thread_sp = thread_sp->GetCurrentExceptionBacktrace();
14310b57cec5SDimitry Andric if (exception_thread_sp && exception_thread_sp->IsValid()) {
14320b57cec5SDimitry Andric const uint32_t num_frames_with_source = 0;
14330b57cec5SDimitry Andric const bool stop_format = false;
14340b57cec5SDimitry Andric exception_thread_sp->GetStatus(strm, 0, UINT32_MAX,
14350b57cec5SDimitry Andric num_frames_with_source, stop_format);
14360b57cec5SDimitry Andric }
14370b57cec5SDimitry Andric
14380b57cec5SDimitry Andric return true;
14390b57cec5SDimitry Andric }
14400b57cec5SDimitry Andric };
14410b57cec5SDimitry Andric
1442d56accc7SDimitry Andric class CommandObjectThreadSiginfo : public CommandObjectIterateOverThreads {
1443d56accc7SDimitry Andric public:
CommandObjectThreadSiginfo(CommandInterpreter & interpreter)1444d56accc7SDimitry Andric CommandObjectThreadSiginfo(CommandInterpreter &interpreter)
1445d56accc7SDimitry Andric : CommandObjectIterateOverThreads(
1446d56accc7SDimitry Andric interpreter, "thread siginfo",
1447d56accc7SDimitry Andric "Display the current siginfo object for a thread. Defaults to "
1448d56accc7SDimitry Andric "the current thread.",
1449d56accc7SDimitry Andric "thread siginfo",
1450d56accc7SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock |
1451d56accc7SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
1452d56accc7SDimitry Andric
1453d56accc7SDimitry Andric ~CommandObjectThreadSiginfo() override = default;
1454d56accc7SDimitry Andric
1455d56accc7SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1456d56accc7SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
1457d56accc7SDimitry Andric OptionElementVector &opt_element_vector) override {
1458fe013be4SDimitry Andric lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1459fe013be4SDimitry Andric GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,
1460fe013be4SDimitry Andric nullptr);
1461d56accc7SDimitry Andric }
1462d56accc7SDimitry Andric
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)1463d56accc7SDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
1464d56accc7SDimitry Andric ThreadSP thread_sp =
1465d56accc7SDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
1466d56accc7SDimitry Andric if (!thread_sp) {
1467d56accc7SDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
1468d56accc7SDimitry Andric tid);
1469d56accc7SDimitry Andric return false;
1470d56accc7SDimitry Andric }
1471d56accc7SDimitry Andric
1472d56accc7SDimitry Andric Stream &strm = result.GetOutputStream();
1473d56accc7SDimitry Andric if (!thread_sp->GetDescription(strm, eDescriptionLevelFull, false, false)) {
1474d56accc7SDimitry Andric result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n",
1475d56accc7SDimitry Andric thread_sp->GetIndexID());
1476d56accc7SDimitry Andric return false;
1477d56accc7SDimitry Andric }
1478d56accc7SDimitry Andric ValueObjectSP exception_object_sp = thread_sp->GetSiginfoValue();
1479d56accc7SDimitry Andric if (exception_object_sp)
1480d56accc7SDimitry Andric exception_object_sp->Dump(strm);
1481d56accc7SDimitry Andric else
1482d56accc7SDimitry Andric strm.Printf("(no siginfo)\n");
1483d56accc7SDimitry Andric strm.PutChar('\n');
1484d56accc7SDimitry Andric
1485d56accc7SDimitry Andric return true;
1486d56accc7SDimitry Andric }
1487d56accc7SDimitry Andric };
1488d56accc7SDimitry Andric
14890b57cec5SDimitry Andric // CommandObjectThreadReturn
14900b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_return
14910b57cec5SDimitry Andric #include "CommandOptions.inc"
14920b57cec5SDimitry Andric
14930b57cec5SDimitry Andric class CommandObjectThreadReturn : public CommandObjectRaw {
14940b57cec5SDimitry Andric public:
14950b57cec5SDimitry Andric class CommandOptions : public Options {
14960b57cec5SDimitry Andric public:
CommandOptions()149704eeddc0SDimitry Andric CommandOptions() {
14980b57cec5SDimitry Andric // Keep default values of all options in one place: OptionParsingStarting
14990b57cec5SDimitry Andric // ()
15000b57cec5SDimitry Andric OptionParsingStarting(nullptr);
15010b57cec5SDimitry Andric }
15020b57cec5SDimitry Andric
15030b57cec5SDimitry Andric ~CommandOptions() override = default;
15040b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)15050b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
15060b57cec5SDimitry Andric ExecutionContext *execution_context) override {
15070b57cec5SDimitry Andric Status error;
15080b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
15090b57cec5SDimitry Andric
15100b57cec5SDimitry Andric switch (short_option) {
15110b57cec5SDimitry Andric case 'x': {
15120b57cec5SDimitry Andric bool success;
15130b57cec5SDimitry Andric bool tmp_value =
15140b57cec5SDimitry Andric OptionArgParser::ToBoolean(option_arg, false, &success);
15150b57cec5SDimitry Andric if (success)
15160b57cec5SDimitry Andric m_from_expression = tmp_value;
15170b57cec5SDimitry Andric else {
15180b57cec5SDimitry Andric error.SetErrorStringWithFormat(
15190b57cec5SDimitry Andric "invalid boolean value '%s' for 'x' option",
15200b57cec5SDimitry Andric option_arg.str().c_str());
15210b57cec5SDimitry Andric }
15220b57cec5SDimitry Andric } break;
15230b57cec5SDimitry Andric default:
15249dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
15250b57cec5SDimitry Andric }
15260b57cec5SDimitry Andric return error;
15270b57cec5SDimitry Andric }
15280b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)15290b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
15300b57cec5SDimitry Andric m_from_expression = false;
15310b57cec5SDimitry Andric }
15320b57cec5SDimitry Andric
GetDefinitions()15330b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1534bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_return_options);
15350b57cec5SDimitry Andric }
15360b57cec5SDimitry Andric
1537fe6060f1SDimitry Andric bool m_from_expression = false;
15380b57cec5SDimitry Andric
15390b57cec5SDimitry Andric // Instance variables to hold the values for command options.
15400b57cec5SDimitry Andric };
15410b57cec5SDimitry Andric
CommandObjectThreadReturn(CommandInterpreter & interpreter)15420b57cec5SDimitry Andric CommandObjectThreadReturn(CommandInterpreter &interpreter)
15430b57cec5SDimitry Andric : CommandObjectRaw(interpreter, "thread return",
15440b57cec5SDimitry Andric "Prematurely return from a stack frame, "
15450b57cec5SDimitry Andric "short-circuiting execution of newer frames "
15460b57cec5SDimitry Andric "and optionally yielding a specified value. Defaults "
15470b57cec5SDimitry Andric "to the exiting the current stack "
15480b57cec5SDimitry Andric "frame.",
15490b57cec5SDimitry Andric "thread return",
15500b57cec5SDimitry Andric eCommandRequiresFrame | eCommandTryTargetAPILock |
15510b57cec5SDimitry Andric eCommandProcessMustBeLaunched |
155204eeddc0SDimitry Andric eCommandProcessMustBePaused) {
15530b57cec5SDimitry Andric CommandArgumentEntry arg;
15540b57cec5SDimitry Andric CommandArgumentData expression_arg;
15550b57cec5SDimitry Andric
15560b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
15570b57cec5SDimitry Andric expression_arg.arg_type = eArgTypeExpression;
15580b57cec5SDimitry Andric expression_arg.arg_repetition = eArgRepeatOptional;
15590b57cec5SDimitry Andric
15600b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
15610b57cec5SDimitry Andric // argument entry.
15620b57cec5SDimitry Andric arg.push_back(expression_arg);
15630b57cec5SDimitry Andric
15640b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
15650b57cec5SDimitry Andric m_arguments.push_back(arg);
15660b57cec5SDimitry Andric }
15670b57cec5SDimitry Andric
15680b57cec5SDimitry Andric ~CommandObjectThreadReturn() override = default;
15690b57cec5SDimitry Andric
GetOptions()15700b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; }
15710b57cec5SDimitry Andric
15720b57cec5SDimitry Andric protected:
DoExecute(llvm::StringRef command,CommandReturnObject & result)1573*c9157d92SDimitry Andric void DoExecute(llvm::StringRef command,
15740b57cec5SDimitry Andric CommandReturnObject &result) override {
15750b57cec5SDimitry Andric // I am going to handle this by hand, because I don't want you to have to
15760b57cec5SDimitry Andric // say:
15770b57cec5SDimitry Andric // "thread return -- -5".
1578*c9157d92SDimitry Andric if (command.starts_with("-x")) {
15790b57cec5SDimitry Andric if (command.size() != 2U)
15800b57cec5SDimitry Andric result.AppendWarning("Return values ignored when returning from user "
15810b57cec5SDimitry Andric "called expressions");
15820b57cec5SDimitry Andric
15830b57cec5SDimitry Andric Thread *thread = m_exe_ctx.GetThreadPtr();
15840b57cec5SDimitry Andric Status error;
15850b57cec5SDimitry Andric error = thread->UnwindInnermostExpression();
15860b57cec5SDimitry Andric if (!error.Success()) {
15870b57cec5SDimitry Andric result.AppendErrorWithFormat("Unwinding expression failed - %s.",
15880b57cec5SDimitry Andric error.AsCString());
15890b57cec5SDimitry Andric } else {
15900b57cec5SDimitry Andric bool success =
15910b57cec5SDimitry Andric thread->SetSelectedFrameByIndexNoisily(0, result.GetOutputStream());
15920b57cec5SDimitry Andric if (success) {
1593fe013be4SDimitry Andric m_exe_ctx.SetFrameSP(
1594fe013be4SDimitry Andric thread->GetSelectedFrame(DoNoSelectMostRelevantFrame));
15950b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
15960b57cec5SDimitry Andric } else {
15970b57cec5SDimitry Andric result.AppendErrorWithFormat(
15980b57cec5SDimitry Andric "Could not select 0th frame after unwinding expression.");
15990b57cec5SDimitry Andric }
16000b57cec5SDimitry Andric }
1601*c9157d92SDimitry Andric return;
16020b57cec5SDimitry Andric }
16030b57cec5SDimitry Andric
16040b57cec5SDimitry Andric ValueObjectSP return_valobj_sp;
16050b57cec5SDimitry Andric
16060b57cec5SDimitry Andric StackFrameSP frame_sp = m_exe_ctx.GetFrameSP();
16070b57cec5SDimitry Andric uint32_t frame_idx = frame_sp->GetFrameIndex();
16080b57cec5SDimitry Andric
16090b57cec5SDimitry Andric if (frame_sp->IsInlined()) {
16100b57cec5SDimitry Andric result.AppendError("Don't know how to return from inlined frames.");
1611*c9157d92SDimitry Andric return;
16120b57cec5SDimitry Andric }
16130b57cec5SDimitry Andric
16140b57cec5SDimitry Andric if (!command.empty()) {
16150b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr();
16160b57cec5SDimitry Andric EvaluateExpressionOptions options;
16170b57cec5SDimitry Andric
16180b57cec5SDimitry Andric options.SetUnwindOnError(true);
16190b57cec5SDimitry Andric options.SetUseDynamic(eNoDynamicValues);
16200b57cec5SDimitry Andric
16210b57cec5SDimitry Andric ExpressionResults exe_results = eExpressionSetupError;
16220b57cec5SDimitry Andric exe_results = target->EvaluateExpression(command, frame_sp.get(),
16230b57cec5SDimitry Andric return_valobj_sp, options);
16240b57cec5SDimitry Andric if (exe_results != eExpressionCompleted) {
16250b57cec5SDimitry Andric if (return_valobj_sp)
16260b57cec5SDimitry Andric result.AppendErrorWithFormat(
16270b57cec5SDimitry Andric "Error evaluating result expression: %s",
16280b57cec5SDimitry Andric return_valobj_sp->GetError().AsCString());
16290b57cec5SDimitry Andric else
16300b57cec5SDimitry Andric result.AppendErrorWithFormat(
16310b57cec5SDimitry Andric "Unknown error evaluating result expression.");
1632*c9157d92SDimitry Andric return;
16330b57cec5SDimitry Andric }
16340b57cec5SDimitry Andric }
16350b57cec5SDimitry Andric
16360b57cec5SDimitry Andric Status error;
16370b57cec5SDimitry Andric ThreadSP thread_sp = m_exe_ctx.GetThreadSP();
16380b57cec5SDimitry Andric const bool broadcast = true;
16390b57cec5SDimitry Andric error = thread_sp->ReturnFromFrame(frame_sp, return_valobj_sp, broadcast);
16400b57cec5SDimitry Andric if (!error.Success()) {
16410b57cec5SDimitry Andric result.AppendErrorWithFormat(
16420b57cec5SDimitry Andric "Error returning from frame %d of thread %d: %s.", frame_idx,
16430b57cec5SDimitry Andric thread_sp->GetIndexID(), error.AsCString());
1644*c9157d92SDimitry Andric return;
16450b57cec5SDimitry Andric }
16460b57cec5SDimitry Andric
16470b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
16480b57cec5SDimitry Andric }
16490b57cec5SDimitry Andric
16500b57cec5SDimitry Andric CommandOptions m_options;
16510b57cec5SDimitry Andric };
16520b57cec5SDimitry Andric
16530b57cec5SDimitry Andric // CommandObjectThreadJump
16540b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_jump
16550b57cec5SDimitry Andric #include "CommandOptions.inc"
16560b57cec5SDimitry Andric
16570b57cec5SDimitry Andric class CommandObjectThreadJump : public CommandObjectParsed {
16580b57cec5SDimitry Andric public:
16590b57cec5SDimitry Andric class CommandOptions : public Options {
16600b57cec5SDimitry Andric public:
CommandOptions()166104eeddc0SDimitry Andric CommandOptions() { OptionParsingStarting(nullptr); }
16620b57cec5SDimitry Andric
16630b57cec5SDimitry Andric ~CommandOptions() override = default;
16640b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)16650b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
16660b57cec5SDimitry Andric m_filenames.Clear();
16670b57cec5SDimitry Andric m_line_num = 0;
16680b57cec5SDimitry Andric m_line_offset = 0;
16690b57cec5SDimitry Andric m_load_addr = LLDB_INVALID_ADDRESS;
16700b57cec5SDimitry Andric m_force = false;
16710b57cec5SDimitry Andric }
16720b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)16730b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
16740b57cec5SDimitry Andric ExecutionContext *execution_context) override {
16750b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
16760b57cec5SDimitry Andric Status error;
16770b57cec5SDimitry Andric
16780b57cec5SDimitry Andric switch (short_option) {
16790b57cec5SDimitry Andric case 'f':
16800b57cec5SDimitry Andric m_filenames.AppendIfUnique(FileSpec(option_arg));
16810b57cec5SDimitry Andric if (m_filenames.GetSize() > 1)
16820b57cec5SDimitry Andric return Status("only one source file expected.");
16830b57cec5SDimitry Andric break;
16840b57cec5SDimitry Andric case 'l':
16850b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_line_num))
16860b57cec5SDimitry Andric return Status("invalid line number: '%s'.", option_arg.str().c_str());
16870b57cec5SDimitry Andric break;
16880b57cec5SDimitry Andric case 'b':
16890b57cec5SDimitry Andric if (option_arg.getAsInteger(0, m_line_offset))
16900b57cec5SDimitry Andric return Status("invalid line offset: '%s'.", option_arg.str().c_str());
16910b57cec5SDimitry Andric break;
16920b57cec5SDimitry Andric case 'a':
16930b57cec5SDimitry Andric m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg,
16940b57cec5SDimitry Andric LLDB_INVALID_ADDRESS, &error);
16950b57cec5SDimitry Andric break;
16960b57cec5SDimitry Andric case 'r':
16970b57cec5SDimitry Andric m_force = true;
16980b57cec5SDimitry Andric break;
16990b57cec5SDimitry Andric default:
17009dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
17010b57cec5SDimitry Andric }
17020b57cec5SDimitry Andric return error;
17030b57cec5SDimitry Andric }
17040b57cec5SDimitry Andric
GetDefinitions()17050b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1706bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_jump_options);
17070b57cec5SDimitry Andric }
17080b57cec5SDimitry Andric
17090b57cec5SDimitry Andric FileSpecList m_filenames;
17100b57cec5SDimitry Andric uint32_t m_line_num;
17110b57cec5SDimitry Andric int32_t m_line_offset;
17120b57cec5SDimitry Andric lldb::addr_t m_load_addr;
17130b57cec5SDimitry Andric bool m_force;
17140b57cec5SDimitry Andric };
17150b57cec5SDimitry Andric
CommandObjectThreadJump(CommandInterpreter & interpreter)17160b57cec5SDimitry Andric CommandObjectThreadJump(CommandInterpreter &interpreter)
17170b57cec5SDimitry Andric : CommandObjectParsed(
17180b57cec5SDimitry Andric interpreter, "thread jump",
17190b57cec5SDimitry Andric "Sets the program counter to a new address.", "thread jump",
17200b57cec5SDimitry Andric eCommandRequiresFrame | eCommandTryTargetAPILock |
172104eeddc0SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
17220b57cec5SDimitry Andric
17230b57cec5SDimitry Andric ~CommandObjectThreadJump() override = default;
17240b57cec5SDimitry Andric
GetOptions()17250b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; }
17260b57cec5SDimitry Andric
17270b57cec5SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)1728*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
17290b57cec5SDimitry Andric RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
17300b57cec5SDimitry Andric StackFrame *frame = m_exe_ctx.GetFramePtr();
17310b57cec5SDimitry Andric Thread *thread = m_exe_ctx.GetThreadPtr();
17320b57cec5SDimitry Andric Target *target = m_exe_ctx.GetTargetPtr();
17330b57cec5SDimitry Andric const SymbolContext &sym_ctx =
17340b57cec5SDimitry Andric frame->GetSymbolContext(eSymbolContextLineEntry);
17350b57cec5SDimitry Andric
17360b57cec5SDimitry Andric if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) {
17370b57cec5SDimitry Andric // Use this address directly.
17380b57cec5SDimitry Andric Address dest = Address(m_options.m_load_addr);
17390b57cec5SDimitry Andric
17400b57cec5SDimitry Andric lldb::addr_t callAddr = dest.GetCallableLoadAddress(target);
17410b57cec5SDimitry Andric if (callAddr == LLDB_INVALID_ADDRESS) {
17420b57cec5SDimitry Andric result.AppendErrorWithFormat("Invalid destination address.");
1743*c9157d92SDimitry Andric return;
17440b57cec5SDimitry Andric }
17450b57cec5SDimitry Andric
17460b57cec5SDimitry Andric if (!reg_ctx->SetPC(callAddr)) {
17470b57cec5SDimitry Andric result.AppendErrorWithFormat("Error changing PC value for thread %d.",
17480b57cec5SDimitry Andric thread->GetIndexID());
1749*c9157d92SDimitry Andric return;
17500b57cec5SDimitry Andric }
17510b57cec5SDimitry Andric } else {
17520b57cec5SDimitry Andric // Pick either the absolute line, or work out a relative one.
17530b57cec5SDimitry Andric int32_t line = (int32_t)m_options.m_line_num;
17540b57cec5SDimitry Andric if (line == 0)
17550b57cec5SDimitry Andric line = sym_ctx.line_entry.line + m_options.m_line_offset;
17560b57cec5SDimitry Andric
17570b57cec5SDimitry Andric // Try the current file, but override if asked.
17580b57cec5SDimitry Andric FileSpec file = sym_ctx.line_entry.file;
17590b57cec5SDimitry Andric if (m_options.m_filenames.GetSize() == 1)
17600b57cec5SDimitry Andric file = m_options.m_filenames.GetFileSpecAtIndex(0);
17610b57cec5SDimitry Andric
17620b57cec5SDimitry Andric if (!file) {
17630b57cec5SDimitry Andric result.AppendErrorWithFormat(
17640b57cec5SDimitry Andric "No source file available for the current location.");
1765*c9157d92SDimitry Andric return;
17660b57cec5SDimitry Andric }
17670b57cec5SDimitry Andric
17680b57cec5SDimitry Andric std::string warnings;
17690b57cec5SDimitry Andric Status err = thread->JumpToLine(file, line, m_options.m_force, &warnings);
17700b57cec5SDimitry Andric
17710b57cec5SDimitry Andric if (err.Fail()) {
17720b57cec5SDimitry Andric result.SetError(err);
1773*c9157d92SDimitry Andric return;
17740b57cec5SDimitry Andric }
17750b57cec5SDimitry Andric
17760b57cec5SDimitry Andric if (!warnings.empty())
17770b57cec5SDimitry Andric result.AppendWarning(warnings.c_str());
17780b57cec5SDimitry Andric }
17790b57cec5SDimitry Andric
17800b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
17810b57cec5SDimitry Andric }
17820b57cec5SDimitry Andric
17830b57cec5SDimitry Andric CommandOptions m_options;
17840b57cec5SDimitry Andric };
17850b57cec5SDimitry Andric
17860b57cec5SDimitry Andric // Next are the subcommands of CommandObjectMultiwordThreadPlan
17870b57cec5SDimitry Andric
17880b57cec5SDimitry Andric // CommandObjectThreadPlanList
17890b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_plan_list
17900b57cec5SDimitry Andric #include "CommandOptions.inc"
17910b57cec5SDimitry Andric
17920b57cec5SDimitry Andric class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads {
17930b57cec5SDimitry Andric public:
17940b57cec5SDimitry Andric class CommandOptions : public Options {
17950b57cec5SDimitry Andric public:
CommandOptions()179604eeddc0SDimitry Andric CommandOptions() {
17970b57cec5SDimitry Andric // Keep default values of all options in one place: OptionParsingStarting
17980b57cec5SDimitry Andric // ()
17990b57cec5SDimitry Andric OptionParsingStarting(nullptr);
18000b57cec5SDimitry Andric }
18010b57cec5SDimitry Andric
18020b57cec5SDimitry Andric ~CommandOptions() override = default;
18030b57cec5SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)18040b57cec5SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
18050b57cec5SDimitry Andric ExecutionContext *execution_context) override {
18060b57cec5SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
18070b57cec5SDimitry Andric
18080b57cec5SDimitry Andric switch (short_option) {
18090b57cec5SDimitry Andric case 'i':
18100b57cec5SDimitry Andric m_internal = true;
18110b57cec5SDimitry Andric break;
18125ffd83dbSDimitry Andric case 't':
18135ffd83dbSDimitry Andric lldb::tid_t tid;
18145ffd83dbSDimitry Andric if (option_arg.getAsInteger(0, tid))
18155ffd83dbSDimitry Andric return Status("invalid tid: '%s'.", option_arg.str().c_str());
18165ffd83dbSDimitry Andric m_tids.push_back(tid);
18175ffd83dbSDimitry Andric break;
18185ffd83dbSDimitry Andric case 'u':
18195ffd83dbSDimitry Andric m_unreported = false;
18205ffd83dbSDimitry Andric break;
18210b57cec5SDimitry Andric case 'v':
18220b57cec5SDimitry Andric m_verbose = true;
18230b57cec5SDimitry Andric break;
18240b57cec5SDimitry Andric default:
18259dba64beSDimitry Andric llvm_unreachable("Unimplemented option");
18260b57cec5SDimitry Andric }
18275ffd83dbSDimitry Andric return {};
18280b57cec5SDimitry Andric }
18290b57cec5SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)18300b57cec5SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
18310b57cec5SDimitry Andric m_verbose = false;
18320b57cec5SDimitry Andric m_internal = false;
18335ffd83dbSDimitry Andric m_unreported = true; // The variable is "skip unreported" and we want to
18345ffd83dbSDimitry Andric // skip unreported by default.
18355ffd83dbSDimitry Andric m_tids.clear();
18360b57cec5SDimitry Andric }
18370b57cec5SDimitry Andric
GetDefinitions()18380b57cec5SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1839bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_plan_list_options);
18400b57cec5SDimitry Andric }
18410b57cec5SDimitry Andric
18420b57cec5SDimitry Andric // Instance variables to hold the values for command options.
18430b57cec5SDimitry Andric bool m_verbose;
18440b57cec5SDimitry Andric bool m_internal;
18455ffd83dbSDimitry Andric bool m_unreported;
18465ffd83dbSDimitry Andric std::vector<lldb::tid_t> m_tids;
18470b57cec5SDimitry Andric };
18480b57cec5SDimitry Andric
CommandObjectThreadPlanList(CommandInterpreter & interpreter)18490b57cec5SDimitry Andric CommandObjectThreadPlanList(CommandInterpreter &interpreter)
18500b57cec5SDimitry Andric : CommandObjectIterateOverThreads(
18510b57cec5SDimitry Andric interpreter, "thread plan list",
18520b57cec5SDimitry Andric "Show thread plans for one or more threads. If no threads are "
18530b57cec5SDimitry Andric "specified, show the "
18540b57cec5SDimitry Andric "current thread. Use the thread-index \"all\" to see all threads.",
18550b57cec5SDimitry Andric nullptr,
18560b57cec5SDimitry Andric eCommandRequiresProcess | eCommandRequiresThread |
18570b57cec5SDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
185804eeddc0SDimitry Andric eCommandProcessMustBePaused) {}
18590b57cec5SDimitry Andric
18600b57cec5SDimitry Andric ~CommandObjectThreadPlanList() override = default;
18610b57cec5SDimitry Andric
GetOptions()18620b57cec5SDimitry Andric Options *GetOptions() override { return &m_options; }
18630b57cec5SDimitry Andric
DoExecute(Args & command,CommandReturnObject & result)1864*c9157d92SDimitry Andric void DoExecute(Args &command, CommandReturnObject &result) override {
18655ffd83dbSDimitry Andric // If we are reporting all threads, dispatch to the Process to do that:
18665ffd83dbSDimitry Andric if (command.GetArgumentCount() == 0 && m_options.m_tids.empty()) {
18675ffd83dbSDimitry Andric Stream &strm = result.GetOutputStream();
18685ffd83dbSDimitry Andric DescriptionLevel desc_level = m_options.m_verbose
18695ffd83dbSDimitry Andric ? eDescriptionLevelVerbose
18705ffd83dbSDimitry Andric : eDescriptionLevelFull;
18715ffd83dbSDimitry Andric m_exe_ctx.GetProcessPtr()->DumpThreadPlans(
18725ffd83dbSDimitry Andric strm, desc_level, m_options.m_internal, true, m_options.m_unreported);
18735ffd83dbSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
1874*c9157d92SDimitry Andric return;
18755ffd83dbSDimitry Andric } else {
18765ffd83dbSDimitry Andric // Do any TID's that the user may have specified as TID, then do any
18775ffd83dbSDimitry Andric // Thread Indexes...
18785ffd83dbSDimitry Andric if (!m_options.m_tids.empty()) {
18795ffd83dbSDimitry Andric Process *process = m_exe_ctx.GetProcessPtr();
18805ffd83dbSDimitry Andric StreamString tmp_strm;
18815ffd83dbSDimitry Andric for (lldb::tid_t tid : m_options.m_tids) {
18825ffd83dbSDimitry Andric bool success = process->DumpThreadPlansForTID(
18835ffd83dbSDimitry Andric tmp_strm, tid, eDescriptionLevelFull, m_options.m_internal,
18845ffd83dbSDimitry Andric true /* condense_trivial */, m_options.m_unreported);
18855ffd83dbSDimitry Andric // If we didn't find a TID, stop here and return an error.
18865ffd83dbSDimitry Andric if (!success) {
1887fe6060f1SDimitry Andric result.AppendError("Error dumping plans:");
18885ffd83dbSDimitry Andric result.AppendError(tmp_strm.GetString());
1889*c9157d92SDimitry Andric return;
18900b57cec5SDimitry Andric }
18915ffd83dbSDimitry Andric // Otherwise, add our data to the output:
18925ffd83dbSDimitry Andric result.GetOutputStream() << tmp_strm.GetString();
18935ffd83dbSDimitry Andric }
18945ffd83dbSDimitry Andric }
18955ffd83dbSDimitry Andric return CommandObjectIterateOverThreads::DoExecute(command, result);
18965ffd83dbSDimitry Andric }
18975ffd83dbSDimitry Andric }
18980b57cec5SDimitry Andric
18995ffd83dbSDimitry Andric protected:
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)19005ffd83dbSDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
19015ffd83dbSDimitry Andric // If we have already handled this from a -t option, skip it here.
1902e8d8bef9SDimitry Andric if (llvm::is_contained(m_options.m_tids, tid))
19035ffd83dbSDimitry Andric return true;
19045ffd83dbSDimitry Andric
19055ffd83dbSDimitry Andric Process *process = m_exe_ctx.GetProcessPtr();
19060b57cec5SDimitry Andric
19070b57cec5SDimitry Andric Stream &strm = result.GetOutputStream();
19080b57cec5SDimitry Andric DescriptionLevel desc_level = eDescriptionLevelFull;
19090b57cec5SDimitry Andric if (m_options.m_verbose)
19100b57cec5SDimitry Andric desc_level = eDescriptionLevelVerbose;
19110b57cec5SDimitry Andric
19125ffd83dbSDimitry Andric process->DumpThreadPlansForTID(strm, tid, desc_level, m_options.m_internal,
19135ffd83dbSDimitry Andric true /* condense_trivial */,
19145ffd83dbSDimitry Andric m_options.m_unreported);
19150b57cec5SDimitry Andric return true;
19160b57cec5SDimitry Andric }
19170b57cec5SDimitry Andric
19180b57cec5SDimitry Andric CommandOptions m_options;
19190b57cec5SDimitry Andric };
19200b57cec5SDimitry Andric
19210b57cec5SDimitry Andric class CommandObjectThreadPlanDiscard : public CommandObjectParsed {
19220b57cec5SDimitry Andric public:
CommandObjectThreadPlanDiscard(CommandInterpreter & interpreter)19230b57cec5SDimitry Andric CommandObjectThreadPlanDiscard(CommandInterpreter &interpreter)
19240b57cec5SDimitry Andric : CommandObjectParsed(interpreter, "thread plan discard",
19250b57cec5SDimitry Andric "Discards thread plans up to and including the "
19260b57cec5SDimitry Andric "specified index (see 'thread plan list'.) "
19270b57cec5SDimitry Andric "Only user visible plans can be discarded.",
19280b57cec5SDimitry Andric nullptr,
19290b57cec5SDimitry Andric eCommandRequiresProcess | eCommandRequiresThread |
19300b57cec5SDimitry Andric eCommandTryTargetAPILock |
19310b57cec5SDimitry Andric eCommandProcessMustBeLaunched |
19320b57cec5SDimitry Andric eCommandProcessMustBePaused) {
19330b57cec5SDimitry Andric CommandArgumentEntry arg;
19340b57cec5SDimitry Andric CommandArgumentData plan_index_arg;
19350b57cec5SDimitry Andric
19360b57cec5SDimitry Andric // Define the first (and only) variant of this arg.
19370b57cec5SDimitry Andric plan_index_arg.arg_type = eArgTypeUnsignedInteger;
19380b57cec5SDimitry Andric plan_index_arg.arg_repetition = eArgRepeatPlain;
19390b57cec5SDimitry Andric
19400b57cec5SDimitry Andric // There is only one variant this argument could be; put it into the
19410b57cec5SDimitry Andric // argument entry.
19420b57cec5SDimitry Andric arg.push_back(plan_index_arg);
19430b57cec5SDimitry Andric
19440b57cec5SDimitry Andric // Push the data for the first argument into the m_arguments vector.
19450b57cec5SDimitry Andric m_arguments.push_back(arg);
19460b57cec5SDimitry Andric }
19470b57cec5SDimitry Andric
19480b57cec5SDimitry Andric ~CommandObjectThreadPlanDiscard() override = default;
19490b57cec5SDimitry Andric
1950e8d8bef9SDimitry Andric void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1951e8d8bef9SDimitry Andric HandleArgumentCompletion(CompletionRequest &request,
1952e8d8bef9SDimitry Andric OptionElementVector &opt_element_vector) override {
1953e8d8bef9SDimitry Andric if (!m_exe_ctx.HasThreadScope() || request.GetCursorIndex())
1954e8d8bef9SDimitry Andric return;
1955e8d8bef9SDimitry Andric
1956e8d8bef9SDimitry Andric m_exe_ctx.GetThreadPtr()->AutoCompleteThreadPlans(request);
1957e8d8bef9SDimitry Andric }
1958e8d8bef9SDimitry Andric
DoExecute(Args & args,CommandReturnObject & result)1959*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
19600b57cec5SDimitry Andric Thread *thread = m_exe_ctx.GetThreadPtr();
19610b57cec5SDimitry Andric if (args.GetArgumentCount() != 1) {
19620b57cec5SDimitry Andric result.AppendErrorWithFormat("Too many arguments, expected one - the "
19630b57cec5SDimitry Andric "thread plan index - but got %zu.",
19640b57cec5SDimitry Andric args.GetArgumentCount());
1965*c9157d92SDimitry Andric return;
19660b57cec5SDimitry Andric }
19670b57cec5SDimitry Andric
19685ffd83dbSDimitry Andric uint32_t thread_plan_idx;
19695ffd83dbSDimitry Andric if (!llvm::to_integer(args.GetArgumentAtIndex(0), thread_plan_idx)) {
19700b57cec5SDimitry Andric result.AppendErrorWithFormat(
19710b57cec5SDimitry Andric "Invalid thread index: \"%s\" - should be unsigned int.",
19720b57cec5SDimitry Andric args.GetArgumentAtIndex(0));
1973*c9157d92SDimitry Andric return;
19740b57cec5SDimitry Andric }
19750b57cec5SDimitry Andric
19760b57cec5SDimitry Andric if (thread_plan_idx == 0) {
19770b57cec5SDimitry Andric result.AppendErrorWithFormat(
19780b57cec5SDimitry Andric "You wouldn't really want me to discard the base thread plan.");
1979*c9157d92SDimitry Andric return;
19800b57cec5SDimitry Andric }
19810b57cec5SDimitry Andric
19820b57cec5SDimitry Andric if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) {
19830b57cec5SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
19840b57cec5SDimitry Andric } else {
19850b57cec5SDimitry Andric result.AppendErrorWithFormat(
19860b57cec5SDimitry Andric "Could not find User thread plan with index %s.",
19870b57cec5SDimitry Andric args.GetArgumentAtIndex(0));
19880b57cec5SDimitry Andric }
19890b57cec5SDimitry Andric }
19900b57cec5SDimitry Andric };
19910b57cec5SDimitry Andric
19925ffd83dbSDimitry Andric class CommandObjectThreadPlanPrune : public CommandObjectParsed {
19935ffd83dbSDimitry Andric public:
CommandObjectThreadPlanPrune(CommandInterpreter & interpreter)19945ffd83dbSDimitry Andric CommandObjectThreadPlanPrune(CommandInterpreter &interpreter)
19955ffd83dbSDimitry Andric : CommandObjectParsed(interpreter, "thread plan prune",
19965ffd83dbSDimitry Andric "Removes any thread plans associated with "
19975ffd83dbSDimitry Andric "currently unreported threads. "
19985ffd83dbSDimitry Andric "Specify one or more TID's to remove, or if no "
19995ffd83dbSDimitry Andric "TID's are provides, remove threads for all "
20005ffd83dbSDimitry Andric "unreported threads",
20015ffd83dbSDimitry Andric nullptr,
20025ffd83dbSDimitry Andric eCommandRequiresProcess |
20035ffd83dbSDimitry Andric eCommandTryTargetAPILock |
20045ffd83dbSDimitry Andric eCommandProcessMustBeLaunched |
20055ffd83dbSDimitry Andric eCommandProcessMustBePaused) {
20065ffd83dbSDimitry Andric CommandArgumentEntry arg;
20075ffd83dbSDimitry Andric CommandArgumentData tid_arg;
20085ffd83dbSDimitry Andric
20095ffd83dbSDimitry Andric // Define the first (and only) variant of this arg.
20105ffd83dbSDimitry Andric tid_arg.arg_type = eArgTypeThreadID;
20115ffd83dbSDimitry Andric tid_arg.arg_repetition = eArgRepeatStar;
20125ffd83dbSDimitry Andric
20135ffd83dbSDimitry Andric // There is only one variant this argument could be; put it into the
20145ffd83dbSDimitry Andric // argument entry.
20155ffd83dbSDimitry Andric arg.push_back(tid_arg);
20165ffd83dbSDimitry Andric
20175ffd83dbSDimitry Andric // Push the data for the first argument into the m_arguments vector.
20185ffd83dbSDimitry Andric m_arguments.push_back(arg);
20195ffd83dbSDimitry Andric }
20205ffd83dbSDimitry Andric
20215ffd83dbSDimitry Andric ~CommandObjectThreadPlanPrune() override = default;
20225ffd83dbSDimitry Andric
DoExecute(Args & args,CommandReturnObject & result)2023*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
20245ffd83dbSDimitry Andric Process *process = m_exe_ctx.GetProcessPtr();
20255ffd83dbSDimitry Andric
20265ffd83dbSDimitry Andric if (args.GetArgumentCount() == 0) {
20275ffd83dbSDimitry Andric process->PruneThreadPlans();
20285ffd83dbSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
2029*c9157d92SDimitry Andric return;
20305ffd83dbSDimitry Andric }
20315ffd83dbSDimitry Andric
20325ffd83dbSDimitry Andric const size_t num_args = args.GetArgumentCount();
20335ffd83dbSDimitry Andric
20345ffd83dbSDimitry Andric std::lock_guard<std::recursive_mutex> guard(
20355ffd83dbSDimitry Andric process->GetThreadList().GetMutex());
20365ffd83dbSDimitry Andric
20375ffd83dbSDimitry Andric for (size_t i = 0; i < num_args; i++) {
20385ffd83dbSDimitry Andric lldb::tid_t tid;
20395ffd83dbSDimitry Andric if (!llvm::to_integer(args.GetArgumentAtIndex(i), tid)) {
20405ffd83dbSDimitry Andric result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
20415ffd83dbSDimitry Andric args.GetArgumentAtIndex(i));
2042*c9157d92SDimitry Andric return;
20435ffd83dbSDimitry Andric }
20445ffd83dbSDimitry Andric if (!process->PruneThreadPlansForTID(tid)) {
20455ffd83dbSDimitry Andric result.AppendErrorWithFormat("Could not find unreported tid: \"%s\"\n",
20465ffd83dbSDimitry Andric args.GetArgumentAtIndex(i));
2047*c9157d92SDimitry Andric return;
20485ffd83dbSDimitry Andric }
20495ffd83dbSDimitry Andric }
20505ffd83dbSDimitry Andric result.SetStatus(eReturnStatusSuccessFinishNoResult);
20515ffd83dbSDimitry Andric }
20525ffd83dbSDimitry Andric };
20535ffd83dbSDimitry Andric
20540b57cec5SDimitry Andric // CommandObjectMultiwordThreadPlan
20550b57cec5SDimitry Andric
20560b57cec5SDimitry Andric class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword {
20570b57cec5SDimitry Andric public:
CommandObjectMultiwordThreadPlan(CommandInterpreter & interpreter)20580b57cec5SDimitry Andric CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter)
20590b57cec5SDimitry Andric : CommandObjectMultiword(
20600b57cec5SDimitry Andric interpreter, "plan",
20610b57cec5SDimitry Andric "Commands for managing thread plans that control execution.",
20620b57cec5SDimitry Andric "thread plan <subcommand> [<subcommand objects]") {
20630b57cec5SDimitry Andric LoadSubCommand(
20640b57cec5SDimitry Andric "list", CommandObjectSP(new CommandObjectThreadPlanList(interpreter)));
20650b57cec5SDimitry Andric LoadSubCommand(
20660b57cec5SDimitry Andric "discard",
20670b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadPlanDiscard(interpreter)));
20685ffd83dbSDimitry Andric LoadSubCommand(
20695ffd83dbSDimitry Andric "prune",
20705ffd83dbSDimitry Andric CommandObjectSP(new CommandObjectThreadPlanPrune(interpreter)));
20710b57cec5SDimitry Andric }
20720b57cec5SDimitry Andric
20730b57cec5SDimitry Andric ~CommandObjectMultiwordThreadPlan() override = default;
20740b57cec5SDimitry Andric };
20750b57cec5SDimitry Andric
2076e8d8bef9SDimitry Andric // Next are the subcommands of CommandObjectMultiwordTrace
2077e8d8bef9SDimitry Andric
2078fe6060f1SDimitry Andric // CommandObjectTraceExport
2079fe6060f1SDimitry Andric
2080fe6060f1SDimitry Andric class CommandObjectTraceExport : public CommandObjectMultiword {
2081fe6060f1SDimitry Andric public:
CommandObjectTraceExport(CommandInterpreter & interpreter)2082fe6060f1SDimitry Andric CommandObjectTraceExport(CommandInterpreter &interpreter)
2083fe6060f1SDimitry Andric : CommandObjectMultiword(
2084fe6060f1SDimitry Andric interpreter, "trace thread export",
2085fe6060f1SDimitry Andric "Commands for exporting traces of the threads in the current "
2086fe6060f1SDimitry Andric "process to different formats.",
2087fe6060f1SDimitry Andric "thread trace export <export-plugin> [<subcommand objects>]") {
2088fe6060f1SDimitry Andric
2089349cc55cSDimitry Andric unsigned i = 0;
2090349cc55cSDimitry Andric for (llvm::StringRef plugin_name =
209181ad6265SDimitry Andric PluginManager::GetTraceExporterPluginNameAtIndex(i);
2092349cc55cSDimitry Andric !plugin_name.empty();
2093349cc55cSDimitry Andric plugin_name = PluginManager::GetTraceExporterPluginNameAtIndex(i++)) {
2094fe6060f1SDimitry Andric if (ThreadTraceExportCommandCreator command_creator =
2095fe6060f1SDimitry Andric PluginManager::GetThreadTraceExportCommandCreatorAtIndex(i)) {
2096fe6060f1SDimitry Andric LoadSubCommand(plugin_name, command_creator(interpreter));
2097fe6060f1SDimitry Andric }
2098fe6060f1SDimitry Andric }
2099fe6060f1SDimitry Andric }
2100fe6060f1SDimitry Andric };
2101fe6060f1SDimitry Andric
2102e8d8bef9SDimitry Andric // CommandObjectTraceStart
2103e8d8bef9SDimitry Andric
2104fe6060f1SDimitry Andric class CommandObjectTraceStart : public CommandObjectTraceProxy {
2105e8d8bef9SDimitry Andric public:
CommandObjectTraceStart(CommandInterpreter & interpreter)2106e8d8bef9SDimitry Andric CommandObjectTraceStart(CommandInterpreter &interpreter)
2107fe6060f1SDimitry Andric : CommandObjectTraceProxy(
2108fe6060f1SDimitry Andric /*live_debug_session_only=*/true, interpreter, "thread trace start",
2109e8d8bef9SDimitry Andric "Start tracing threads with the corresponding trace "
2110e8d8bef9SDimitry Andric "plug-in for the current process.",
2111e8d8bef9SDimitry Andric "thread trace start [<trace-options>]") {}
2112e8d8bef9SDimitry Andric
2113e8d8bef9SDimitry Andric protected:
GetDelegateCommand(Trace & trace)2114fe6060f1SDimitry Andric lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override {
2115fe6060f1SDimitry Andric return trace.GetThreadTraceStartCommand(m_interpreter);
2116e8d8bef9SDimitry Andric }
2117e8d8bef9SDimitry Andric };
2118e8d8bef9SDimitry Andric
2119e8d8bef9SDimitry Andric // CommandObjectTraceStop
2120e8d8bef9SDimitry Andric
2121fe6060f1SDimitry Andric class CommandObjectTraceStop : public CommandObjectMultipleThreads {
2122e8d8bef9SDimitry Andric public:
CommandObjectTraceStop(CommandInterpreter & interpreter)2123e8d8bef9SDimitry Andric CommandObjectTraceStop(CommandInterpreter &interpreter)
2124fe6060f1SDimitry Andric : CommandObjectMultipleThreads(
2125e8d8bef9SDimitry Andric interpreter, "thread trace stop",
2126fe6060f1SDimitry Andric "Stop tracing threads, including the ones traced with the "
2127fe6060f1SDimitry Andric "\"process trace start\" command."
2128e8d8bef9SDimitry Andric "Defaults to the current thread. Thread indices can be "
2129fe6060f1SDimitry Andric "specified as arguments.\n Use the thread-index \"all\" to stop "
2130fe6060f1SDimitry Andric "tracing "
2131fe6060f1SDimitry Andric "for all existing threads.",
2132e8d8bef9SDimitry Andric "thread trace stop [<thread-index> <thread-index> ...]",
2133e8d8bef9SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock |
2134e8d8bef9SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
2135e8d8bef9SDimitry Andric eCommandProcessMustBeTraced) {}
2136e8d8bef9SDimitry Andric
2137e8d8bef9SDimitry Andric ~CommandObjectTraceStop() override = default;
2138e8d8bef9SDimitry Andric
DoExecuteOnThreads(Args & command,CommandReturnObject & result,llvm::ArrayRef<lldb::tid_t> tids)2139fe6060f1SDimitry Andric bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
2140fe6060f1SDimitry Andric llvm::ArrayRef<lldb::tid_t> tids) override {
2141fe6060f1SDimitry Andric ProcessSP process_sp = m_exe_ctx.GetProcessSP();
2142e8d8bef9SDimitry Andric
2143fe6060f1SDimitry Andric TraceSP trace_sp = process_sp->GetTarget().GetTrace();
2144e8d8bef9SDimitry Andric
2145fe6060f1SDimitry Andric if (llvm::Error err = trace_sp->Stop(tids))
2146fe6060f1SDimitry Andric result.AppendError(toString(std::move(err)));
2147fe6060f1SDimitry Andric else
2148fe6060f1SDimitry Andric result.SetStatus(eReturnStatusSuccessFinishResult);
2149fe6060f1SDimitry Andric
2150fe6060f1SDimitry Andric return result.Succeeded();
2151e8d8bef9SDimitry Andric }
2152e8d8bef9SDimitry Andric };
2153e8d8bef9SDimitry Andric
GetSingleThreadFromArgs(ExecutionContext & exe_ctx,Args & args,CommandReturnObject & result)2154bdd1243dSDimitry Andric static ThreadSP GetSingleThreadFromArgs(ExecutionContext &exe_ctx, Args &args,
2155bdd1243dSDimitry Andric CommandReturnObject &result) {
2156bdd1243dSDimitry Andric if (args.GetArgumentCount() == 0)
2157bdd1243dSDimitry Andric return exe_ctx.GetThreadSP();
2158bdd1243dSDimitry Andric
2159bdd1243dSDimitry Andric const char *arg = args.GetArgumentAtIndex(0);
2160bdd1243dSDimitry Andric uint32_t thread_idx;
2161bdd1243dSDimitry Andric
2162bdd1243dSDimitry Andric if (!llvm::to_integer(arg, thread_idx)) {
2163bdd1243dSDimitry Andric result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", arg);
2164bdd1243dSDimitry Andric return nullptr;
2165bdd1243dSDimitry Andric }
2166bdd1243dSDimitry Andric ThreadSP thread_sp =
2167bdd1243dSDimitry Andric exe_ctx.GetProcessRef().GetThreadList().FindThreadByIndexID(thread_idx);
2168bdd1243dSDimitry Andric if (!thread_sp)
2169bdd1243dSDimitry Andric result.AppendErrorWithFormat("no thread with index: \"%s\"\n", arg);
2170bdd1243dSDimitry Andric return thread_sp;
2171bdd1243dSDimitry Andric }
2172bdd1243dSDimitry Andric
2173bdd1243dSDimitry Andric // CommandObjectTraceDumpFunctionCalls
2174bdd1243dSDimitry Andric #define LLDB_OPTIONS_thread_trace_dump_function_calls
2175bdd1243dSDimitry Andric #include "CommandOptions.inc"
2176bdd1243dSDimitry Andric
2177bdd1243dSDimitry Andric class CommandObjectTraceDumpFunctionCalls : public CommandObjectParsed {
2178bdd1243dSDimitry Andric public:
2179bdd1243dSDimitry Andric class CommandOptions : public Options {
2180bdd1243dSDimitry Andric public:
CommandOptions()2181bdd1243dSDimitry Andric CommandOptions() { OptionParsingStarting(nullptr); }
2182bdd1243dSDimitry Andric
2183bdd1243dSDimitry Andric ~CommandOptions() override = default;
2184bdd1243dSDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2185bdd1243dSDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2186bdd1243dSDimitry Andric ExecutionContext *execution_context) override {
2187bdd1243dSDimitry Andric Status error;
2188bdd1243dSDimitry Andric const int short_option = m_getopt_table[option_idx].val;
2189bdd1243dSDimitry Andric
2190bdd1243dSDimitry Andric switch (short_option) {
2191bdd1243dSDimitry Andric case 'j': {
2192bdd1243dSDimitry Andric m_dumper_options.json = true;
2193bdd1243dSDimitry Andric break;
2194bdd1243dSDimitry Andric }
2195bdd1243dSDimitry Andric case 'J': {
2196bdd1243dSDimitry Andric m_dumper_options.json = true;
2197bdd1243dSDimitry Andric m_dumper_options.pretty_print_json = true;
2198bdd1243dSDimitry Andric break;
2199bdd1243dSDimitry Andric }
2200bdd1243dSDimitry Andric case 'F': {
2201bdd1243dSDimitry Andric m_output_file.emplace(option_arg);
2202bdd1243dSDimitry Andric break;
2203bdd1243dSDimitry Andric }
2204bdd1243dSDimitry Andric default:
2205bdd1243dSDimitry Andric llvm_unreachable("Unimplemented option");
2206bdd1243dSDimitry Andric }
2207bdd1243dSDimitry Andric return error;
2208bdd1243dSDimitry Andric }
2209bdd1243dSDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)2210bdd1243dSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
2211bdd1243dSDimitry Andric m_dumper_options = {};
2212bdd1243dSDimitry Andric m_output_file = std::nullopt;
2213bdd1243dSDimitry Andric }
2214bdd1243dSDimitry Andric
GetDefinitions()2215bdd1243dSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2216bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_trace_dump_function_calls_options);
2217bdd1243dSDimitry Andric }
2218bdd1243dSDimitry Andric
2219bdd1243dSDimitry Andric static const size_t kDefaultCount = 20;
2220bdd1243dSDimitry Andric
2221bdd1243dSDimitry Andric // Instance variables to hold the values for command options.
2222bdd1243dSDimitry Andric TraceDumperOptions m_dumper_options;
2223bdd1243dSDimitry Andric std::optional<FileSpec> m_output_file;
2224bdd1243dSDimitry Andric };
2225bdd1243dSDimitry Andric
CommandObjectTraceDumpFunctionCalls(CommandInterpreter & interpreter)2226bdd1243dSDimitry Andric CommandObjectTraceDumpFunctionCalls(CommandInterpreter &interpreter)
2227bdd1243dSDimitry Andric : CommandObjectParsed(
2228bdd1243dSDimitry Andric interpreter, "thread trace dump function-calls",
2229bdd1243dSDimitry Andric "Dump the traced function-calls for one thread. If no "
2230bdd1243dSDimitry Andric "thread is specified, the current thread is used.",
2231bdd1243dSDimitry Andric nullptr,
2232bdd1243dSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread |
2233bdd1243dSDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
2234bdd1243dSDimitry Andric eCommandProcessMustBePaused | eCommandProcessMustBeTraced) {
2235bdd1243dSDimitry Andric CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatOptional};
2236bdd1243dSDimitry Andric m_arguments.push_back({thread_arg});
2237bdd1243dSDimitry Andric }
2238bdd1243dSDimitry Andric
2239bdd1243dSDimitry Andric ~CommandObjectTraceDumpFunctionCalls() override = default;
2240bdd1243dSDimitry Andric
GetOptions()2241bdd1243dSDimitry Andric Options *GetOptions() override { return &m_options; }
2242bdd1243dSDimitry Andric
2243bdd1243dSDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)2244*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
2245bdd1243dSDimitry Andric ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);
2246bdd1243dSDimitry Andric if (!thread_sp) {
2247bdd1243dSDimitry Andric result.AppendError("invalid thread\n");
2248*c9157d92SDimitry Andric return;
2249bdd1243dSDimitry Andric }
2250bdd1243dSDimitry Andric
2251bdd1243dSDimitry Andric llvm::Expected<TraceCursorSP> cursor_or_error =
2252bdd1243dSDimitry Andric m_exe_ctx.GetTargetSP()->GetTrace()->CreateNewCursor(*thread_sp);
2253bdd1243dSDimitry Andric
2254bdd1243dSDimitry Andric if (!cursor_or_error) {
2255bdd1243dSDimitry Andric result.AppendError(llvm::toString(cursor_or_error.takeError()));
2256*c9157d92SDimitry Andric return;
2257bdd1243dSDimitry Andric }
2258bdd1243dSDimitry Andric TraceCursorSP &cursor_sp = *cursor_or_error;
2259bdd1243dSDimitry Andric
2260bdd1243dSDimitry Andric std::optional<StreamFile> out_file;
2261bdd1243dSDimitry Andric if (m_options.m_output_file) {
2262bdd1243dSDimitry Andric out_file.emplace(m_options.m_output_file->GetPath().c_str(),
2263bdd1243dSDimitry Andric File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |
2264bdd1243dSDimitry Andric File::eOpenOptionTruncate);
2265bdd1243dSDimitry Andric }
2266bdd1243dSDimitry Andric
2267bdd1243dSDimitry Andric m_options.m_dumper_options.forwards = true;
2268bdd1243dSDimitry Andric
2269bdd1243dSDimitry Andric TraceDumper dumper(std::move(cursor_sp),
2270bdd1243dSDimitry Andric out_file ? *out_file : result.GetOutputStream(),
2271bdd1243dSDimitry Andric m_options.m_dumper_options);
2272bdd1243dSDimitry Andric
2273bdd1243dSDimitry Andric dumper.DumpFunctionCalls();
2274bdd1243dSDimitry Andric }
2275bdd1243dSDimitry Andric
2276bdd1243dSDimitry Andric CommandOptions m_options;
2277bdd1243dSDimitry Andric };
2278bdd1243dSDimitry Andric
2279e8d8bef9SDimitry Andric // CommandObjectTraceDumpInstructions
2280e8d8bef9SDimitry Andric #define LLDB_OPTIONS_thread_trace_dump_instructions
2281e8d8bef9SDimitry Andric #include "CommandOptions.inc"
2282e8d8bef9SDimitry Andric
228381ad6265SDimitry Andric class CommandObjectTraceDumpInstructions : public CommandObjectParsed {
2284e8d8bef9SDimitry Andric public:
2285e8d8bef9SDimitry Andric class CommandOptions : public Options {
2286e8d8bef9SDimitry Andric public:
CommandOptions()228704eeddc0SDimitry Andric CommandOptions() { OptionParsingStarting(nullptr); }
2288e8d8bef9SDimitry Andric
2289e8d8bef9SDimitry Andric ~CommandOptions() override = default;
2290e8d8bef9SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2291e8d8bef9SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2292e8d8bef9SDimitry Andric ExecutionContext *execution_context) override {
2293e8d8bef9SDimitry Andric Status error;
2294e8d8bef9SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
2295e8d8bef9SDimitry Andric
2296e8d8bef9SDimitry Andric switch (short_option) {
2297e8d8bef9SDimitry Andric case 'c': {
2298e8d8bef9SDimitry Andric int32_t count;
2299e8d8bef9SDimitry Andric if (option_arg.empty() || option_arg.getAsInteger(0, count) ||
2300e8d8bef9SDimitry Andric count < 0)
2301e8d8bef9SDimitry Andric error.SetErrorStringWithFormat(
2302e8d8bef9SDimitry Andric "invalid integer value for option '%s'",
2303e8d8bef9SDimitry Andric option_arg.str().c_str());
2304e8d8bef9SDimitry Andric else
2305e8d8bef9SDimitry Andric m_count = count;
2306e8d8bef9SDimitry Andric break;
2307e8d8bef9SDimitry Andric }
230881ad6265SDimitry Andric case 'a': {
230981ad6265SDimitry Andric m_count = std::numeric_limits<decltype(m_count)>::max();
231081ad6265SDimitry Andric break;
231181ad6265SDimitry Andric }
2312fe6060f1SDimitry Andric case 's': {
2313fe6060f1SDimitry Andric int32_t skip;
2314fe6060f1SDimitry Andric if (option_arg.empty() || option_arg.getAsInteger(0, skip) || skip < 0)
2315e8d8bef9SDimitry Andric error.SetErrorStringWithFormat(
2316e8d8bef9SDimitry Andric "invalid integer value for option '%s'",
2317e8d8bef9SDimitry Andric option_arg.str().c_str());
2318e8d8bef9SDimitry Andric else
231981ad6265SDimitry Andric m_dumper_options.skip = skip;
232081ad6265SDimitry Andric break;
232181ad6265SDimitry Andric }
232281ad6265SDimitry Andric case 'i': {
232381ad6265SDimitry Andric uint64_t id;
232481ad6265SDimitry Andric if (option_arg.empty() || option_arg.getAsInteger(0, id))
232581ad6265SDimitry Andric error.SetErrorStringWithFormat(
232681ad6265SDimitry Andric "invalid integer value for option '%s'",
232781ad6265SDimitry Andric option_arg.str().c_str());
232881ad6265SDimitry Andric else
232981ad6265SDimitry Andric m_dumper_options.id = id;
233081ad6265SDimitry Andric break;
233181ad6265SDimitry Andric }
233281ad6265SDimitry Andric case 'F': {
233381ad6265SDimitry Andric m_output_file.emplace(option_arg);
2334e8d8bef9SDimitry Andric break;
2335e8d8bef9SDimitry Andric }
2336e8d8bef9SDimitry Andric case 'r': {
233781ad6265SDimitry Andric m_dumper_options.raw = true;
2338e8d8bef9SDimitry Andric break;
2339e8d8bef9SDimitry Andric }
2340fe6060f1SDimitry Andric case 'f': {
234181ad6265SDimitry Andric m_dumper_options.forwards = true;
2342fe6060f1SDimitry Andric break;
2343fe6060f1SDimitry Andric }
2344753f127fSDimitry Andric case 'k': {
2345753f127fSDimitry Andric m_dumper_options.show_control_flow_kind = true;
2346753f127fSDimitry Andric break;
2347753f127fSDimitry Andric }
2348fe6060f1SDimitry Andric case 't': {
2349972a253aSDimitry Andric m_dumper_options.show_timestamps = true;
235081ad6265SDimitry Andric break;
235181ad6265SDimitry Andric }
235281ad6265SDimitry Andric case 'e': {
235381ad6265SDimitry Andric m_dumper_options.show_events = true;
235481ad6265SDimitry Andric break;
235581ad6265SDimitry Andric }
235681ad6265SDimitry Andric case 'j': {
235781ad6265SDimitry Andric m_dumper_options.json = true;
235881ad6265SDimitry Andric break;
235981ad6265SDimitry Andric }
236081ad6265SDimitry Andric case 'J': {
236181ad6265SDimitry Andric m_dumper_options.pretty_print_json = true;
236281ad6265SDimitry Andric m_dumper_options.json = true;
236381ad6265SDimitry Andric break;
236481ad6265SDimitry Andric }
2365bdd1243dSDimitry Andric case 'E': {
2366bdd1243dSDimitry Andric m_dumper_options.only_events = true;
2367bdd1243dSDimitry Andric m_dumper_options.show_events = true;
2368bdd1243dSDimitry Andric break;
2369bdd1243dSDimitry Andric }
237081ad6265SDimitry Andric case 'C': {
237181ad6265SDimitry Andric m_continue = true;
2372fe6060f1SDimitry Andric break;
2373fe6060f1SDimitry Andric }
2374e8d8bef9SDimitry Andric default:
2375e8d8bef9SDimitry Andric llvm_unreachable("Unimplemented option");
2376e8d8bef9SDimitry Andric }
2377e8d8bef9SDimitry Andric return error;
2378e8d8bef9SDimitry Andric }
2379e8d8bef9SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)2380e8d8bef9SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
2381e8d8bef9SDimitry Andric m_count = kDefaultCount;
238281ad6265SDimitry Andric m_continue = false;
2383bdd1243dSDimitry Andric m_output_file = std::nullopt;
238481ad6265SDimitry Andric m_dumper_options = {};
2385e8d8bef9SDimitry Andric }
2386e8d8bef9SDimitry Andric
GetDefinitions()2387e8d8bef9SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2388bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_trace_dump_instructions_options);
2389e8d8bef9SDimitry Andric }
2390e8d8bef9SDimitry Andric
2391e8d8bef9SDimitry Andric static const size_t kDefaultCount = 20;
2392e8d8bef9SDimitry Andric
2393e8d8bef9SDimitry Andric // Instance variables to hold the values for command options.
2394e8d8bef9SDimitry Andric size_t m_count;
239581ad6265SDimitry Andric size_t m_continue;
2396bdd1243dSDimitry Andric std::optional<FileSpec> m_output_file;
239781ad6265SDimitry Andric TraceDumperOptions m_dumper_options;
2398e8d8bef9SDimitry Andric };
2399e8d8bef9SDimitry Andric
CommandObjectTraceDumpInstructions(CommandInterpreter & interpreter)2400e8d8bef9SDimitry Andric CommandObjectTraceDumpInstructions(CommandInterpreter &interpreter)
240181ad6265SDimitry Andric : CommandObjectParsed(
2402e8d8bef9SDimitry Andric interpreter, "thread trace dump instructions",
240381ad6265SDimitry Andric "Dump the traced instructions for one thread. If no "
240481ad6265SDimitry Andric "thread is specified, show the current thread.",
2405e8d8bef9SDimitry Andric nullptr,
240681ad6265SDimitry Andric eCommandRequiresProcess | eCommandRequiresThread |
240781ad6265SDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
240881ad6265SDimitry Andric eCommandProcessMustBePaused | eCommandProcessMustBeTraced) {
240981ad6265SDimitry Andric CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatOptional};
241081ad6265SDimitry Andric m_arguments.push_back({thread_arg});
241181ad6265SDimitry Andric }
2412e8d8bef9SDimitry Andric
2413e8d8bef9SDimitry Andric ~CommandObjectTraceDumpInstructions() override = default;
2414e8d8bef9SDimitry Andric
GetOptions()2415e8d8bef9SDimitry Andric Options *GetOptions() override { return &m_options; }
2416e8d8bef9SDimitry Andric
GetRepeatCommand(Args & current_command_args,uint32_t index)2417bdd1243dSDimitry Andric std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,
2418e8d8bef9SDimitry Andric uint32_t index) override {
241981ad6265SDimitry Andric std::string cmd;
242081ad6265SDimitry Andric current_command_args.GetCommandString(cmd);
242181ad6265SDimitry Andric if (cmd.find(" --continue") == std::string::npos)
242281ad6265SDimitry Andric cmd += " --continue";
242381ad6265SDimitry Andric return cmd;
2424e8d8bef9SDimitry Andric }
2425e8d8bef9SDimitry Andric
2426e8d8bef9SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)2427*c9157d92SDimitry Andric void DoExecute(Args &args, CommandReturnObject &result) override {
2428bdd1243dSDimitry Andric ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);
242981ad6265SDimitry Andric if (!thread_sp) {
243081ad6265SDimitry Andric result.AppendError("invalid thread\n");
2431*c9157d92SDimitry Andric return;
243281ad6265SDimitry Andric }
243381ad6265SDimitry Andric
243481ad6265SDimitry Andric if (m_options.m_continue && m_last_id) {
243581ad6265SDimitry Andric // We set up the options to continue one instruction past where
243681ad6265SDimitry Andric // the previous iteration stopped.
243781ad6265SDimitry Andric m_options.m_dumper_options.skip = 1;
243881ad6265SDimitry Andric m_options.m_dumper_options.id = m_last_id;
243981ad6265SDimitry Andric }
244081ad6265SDimitry Andric
2441bdd1243dSDimitry Andric llvm::Expected<TraceCursorSP> cursor_or_error =
244281ad6265SDimitry Andric m_exe_ctx.GetTargetSP()->GetTrace()->CreateNewCursor(*thread_sp);
244381ad6265SDimitry Andric
244481ad6265SDimitry Andric if (!cursor_or_error) {
244581ad6265SDimitry Andric result.AppendError(llvm::toString(cursor_or_error.takeError()));
2446*c9157d92SDimitry Andric return;
244781ad6265SDimitry Andric }
2448bdd1243dSDimitry Andric TraceCursorSP &cursor_sp = *cursor_or_error;
244981ad6265SDimitry Andric
245081ad6265SDimitry Andric if (m_options.m_dumper_options.id &&
2451bdd1243dSDimitry Andric !cursor_sp->HasId(*m_options.m_dumper_options.id)) {
245281ad6265SDimitry Andric result.AppendError("invalid instruction id\n");
2453*c9157d92SDimitry Andric return;
245481ad6265SDimitry Andric }
245581ad6265SDimitry Andric
2456bdd1243dSDimitry Andric std::optional<StreamFile> out_file;
245781ad6265SDimitry Andric if (m_options.m_output_file) {
245881ad6265SDimitry Andric out_file.emplace(m_options.m_output_file->GetPath().c_str(),
2459bdd1243dSDimitry Andric File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |
2460bdd1243dSDimitry Andric File::eOpenOptionTruncate);
246181ad6265SDimitry Andric }
246281ad6265SDimitry Andric
246381ad6265SDimitry Andric if (m_options.m_continue && !m_last_id) {
246481ad6265SDimitry Andric // We need to stop processing data when we already ran out of instructions
246581ad6265SDimitry Andric // in a previous command. We can fake this by setting the cursor past the
246681ad6265SDimitry Andric // end of the trace.
2467bdd1243dSDimitry Andric cursor_sp->Seek(1, lldb::eTraceCursorSeekTypeEnd);
246881ad6265SDimitry Andric }
246981ad6265SDimitry Andric
2470bdd1243dSDimitry Andric TraceDumper dumper(std::move(cursor_sp),
247181ad6265SDimitry Andric out_file ? *out_file : result.GetOutputStream(),
247281ad6265SDimitry Andric m_options.m_dumper_options);
247381ad6265SDimitry Andric
247481ad6265SDimitry Andric m_last_id = dumper.DumpInstructions(m_options.m_count);
2475e8d8bef9SDimitry Andric }
2476e8d8bef9SDimitry Andric
2477e8d8bef9SDimitry Andric CommandOptions m_options;
2478fe013be4SDimitry Andric // Last traversed id used to continue a repeat command. std::nullopt means
247981ad6265SDimitry Andric // that all the trace has been consumed.
2480bdd1243dSDimitry Andric std::optional<lldb::user_id_t> m_last_id;
2481fe6060f1SDimitry Andric };
2482fe6060f1SDimitry Andric
2483fe6060f1SDimitry Andric // CommandObjectTraceDumpInfo
2484fe6060f1SDimitry Andric #define LLDB_OPTIONS_thread_trace_dump_info
2485fe6060f1SDimitry Andric #include "CommandOptions.inc"
2486fe6060f1SDimitry Andric
2487fe6060f1SDimitry Andric class CommandObjectTraceDumpInfo : public CommandObjectIterateOverThreads {
2488fe6060f1SDimitry Andric public:
2489fe6060f1SDimitry Andric class CommandOptions : public Options {
2490fe6060f1SDimitry Andric public:
CommandOptions()249104eeddc0SDimitry Andric CommandOptions() { OptionParsingStarting(nullptr); }
2492fe6060f1SDimitry Andric
2493fe6060f1SDimitry Andric ~CommandOptions() override = default;
2494fe6060f1SDimitry Andric
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2495fe6060f1SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2496fe6060f1SDimitry Andric ExecutionContext *execution_context) override {
2497fe6060f1SDimitry Andric Status error;
2498fe6060f1SDimitry Andric const int short_option = m_getopt_table[option_idx].val;
2499fe6060f1SDimitry Andric
2500fe6060f1SDimitry Andric switch (short_option) {
2501fe6060f1SDimitry Andric case 'v': {
2502fe6060f1SDimitry Andric m_verbose = true;
2503fe6060f1SDimitry Andric break;
2504fe6060f1SDimitry Andric }
2505753f127fSDimitry Andric case 'j': {
2506753f127fSDimitry Andric m_json = true;
2507753f127fSDimitry Andric break;
2508753f127fSDimitry Andric }
2509fe6060f1SDimitry Andric default:
2510fe6060f1SDimitry Andric llvm_unreachable("Unimplemented option");
2511fe6060f1SDimitry Andric }
2512fe6060f1SDimitry Andric return error;
2513fe6060f1SDimitry Andric }
2514fe6060f1SDimitry Andric
OptionParsingStarting(ExecutionContext * execution_context)2515fe6060f1SDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
2516fe6060f1SDimitry Andric m_verbose = false;
2517753f127fSDimitry Andric m_json = false;
2518fe6060f1SDimitry Andric }
2519fe6060f1SDimitry Andric
GetDefinitions()2520fe6060f1SDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2521bdd1243dSDimitry Andric return llvm::ArrayRef(g_thread_trace_dump_info_options);
2522fe6060f1SDimitry Andric }
2523fe6060f1SDimitry Andric
2524fe6060f1SDimitry Andric // Instance variables to hold the values for command options.
2525fe6060f1SDimitry Andric bool m_verbose;
2526753f127fSDimitry Andric bool m_json;
2527fe6060f1SDimitry Andric };
2528fe6060f1SDimitry Andric
CommandObjectTraceDumpInfo(CommandInterpreter & interpreter)2529fe6060f1SDimitry Andric CommandObjectTraceDumpInfo(CommandInterpreter &interpreter)
2530fe6060f1SDimitry Andric : CommandObjectIterateOverThreads(
2531fe6060f1SDimitry Andric interpreter, "thread trace dump info",
2532fe6060f1SDimitry Andric "Dump the traced information for one or more threads. If no "
2533fe6060f1SDimitry Andric "threads are specified, show the current thread. Use the "
2534fe6060f1SDimitry Andric "thread-index \"all\" to see all threads.",
2535fe6060f1SDimitry Andric nullptr,
2536fe6060f1SDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock |
2537fe6060f1SDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
253804eeddc0SDimitry Andric eCommandProcessMustBeTraced) {}
2539fe6060f1SDimitry Andric
2540fe6060f1SDimitry Andric ~CommandObjectTraceDumpInfo() override = default;
2541fe6060f1SDimitry Andric
GetOptions()2542fe6060f1SDimitry Andric Options *GetOptions() override { return &m_options; }
2543fe6060f1SDimitry Andric
2544fe6060f1SDimitry Andric protected:
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)2545fe6060f1SDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
2546fe6060f1SDimitry Andric const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace();
2547fe6060f1SDimitry Andric ThreadSP thread_sp =
2548fe6060f1SDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
2549fe6060f1SDimitry Andric trace_sp->DumpTraceInfo(*thread_sp, result.GetOutputStream(),
2550753f127fSDimitry Andric m_options.m_verbose, m_options.m_json);
2551fe6060f1SDimitry Andric return true;
2552fe6060f1SDimitry Andric }
2553fe6060f1SDimitry Andric
2554fe6060f1SDimitry Andric CommandOptions m_options;
2555e8d8bef9SDimitry Andric };
2556e8d8bef9SDimitry Andric
2557e8d8bef9SDimitry Andric // CommandObjectMultiwordTraceDump
2558e8d8bef9SDimitry Andric class CommandObjectMultiwordTraceDump : public CommandObjectMultiword {
2559e8d8bef9SDimitry Andric public:
CommandObjectMultiwordTraceDump(CommandInterpreter & interpreter)2560e8d8bef9SDimitry Andric CommandObjectMultiwordTraceDump(CommandInterpreter &interpreter)
2561e8d8bef9SDimitry Andric : CommandObjectMultiword(
2562e8d8bef9SDimitry Andric interpreter, "dump",
2563e8d8bef9SDimitry Andric "Commands for displaying trace information of the threads "
2564e8d8bef9SDimitry Andric "in the current process.",
2565e8d8bef9SDimitry Andric "thread trace dump <subcommand> [<subcommand objects>]") {
2566e8d8bef9SDimitry Andric LoadSubCommand(
2567e8d8bef9SDimitry Andric "instructions",
2568e8d8bef9SDimitry Andric CommandObjectSP(new CommandObjectTraceDumpInstructions(interpreter)));
2569fe6060f1SDimitry Andric LoadSubCommand(
2570bdd1243dSDimitry Andric "function-calls",
2571bdd1243dSDimitry Andric CommandObjectSP(new CommandObjectTraceDumpFunctionCalls(interpreter)));
2572bdd1243dSDimitry Andric LoadSubCommand(
2573fe6060f1SDimitry Andric "info", CommandObjectSP(new CommandObjectTraceDumpInfo(interpreter)));
2574e8d8bef9SDimitry Andric }
2575e8d8bef9SDimitry Andric ~CommandObjectMultiwordTraceDump() override = default;
2576e8d8bef9SDimitry Andric };
2577e8d8bef9SDimitry Andric
2578e8d8bef9SDimitry Andric // CommandObjectMultiwordTrace
2579e8d8bef9SDimitry Andric class CommandObjectMultiwordTrace : public CommandObjectMultiword {
2580e8d8bef9SDimitry Andric public:
CommandObjectMultiwordTrace(CommandInterpreter & interpreter)2581e8d8bef9SDimitry Andric CommandObjectMultiwordTrace(CommandInterpreter &interpreter)
2582e8d8bef9SDimitry Andric : CommandObjectMultiword(
2583e8d8bef9SDimitry Andric interpreter, "trace",
2584e8d8bef9SDimitry Andric "Commands for operating on traces of the threads in the current "
2585e8d8bef9SDimitry Andric "process.",
2586e8d8bef9SDimitry Andric "thread trace <subcommand> [<subcommand objects>]") {
2587e8d8bef9SDimitry Andric LoadSubCommand("dump", CommandObjectSP(new CommandObjectMultiwordTraceDump(
2588e8d8bef9SDimitry Andric interpreter)));
2589e8d8bef9SDimitry Andric LoadSubCommand("start",
2590e8d8bef9SDimitry Andric CommandObjectSP(new CommandObjectTraceStart(interpreter)));
2591e8d8bef9SDimitry Andric LoadSubCommand("stop",
2592e8d8bef9SDimitry Andric CommandObjectSP(new CommandObjectTraceStop(interpreter)));
2593fe6060f1SDimitry Andric LoadSubCommand("export",
2594fe6060f1SDimitry Andric CommandObjectSP(new CommandObjectTraceExport(interpreter)));
2595e8d8bef9SDimitry Andric }
2596e8d8bef9SDimitry Andric
2597e8d8bef9SDimitry Andric ~CommandObjectMultiwordTrace() override = default;
2598e8d8bef9SDimitry Andric };
2599e8d8bef9SDimitry Andric
26000b57cec5SDimitry Andric // CommandObjectMultiwordThread
26010b57cec5SDimitry Andric
CommandObjectMultiwordThread(CommandInterpreter & interpreter)26020b57cec5SDimitry Andric CommandObjectMultiwordThread::CommandObjectMultiwordThread(
26030b57cec5SDimitry Andric CommandInterpreter &interpreter)
2604480093f4SDimitry Andric : CommandObjectMultiword(interpreter, "thread",
2605480093f4SDimitry Andric "Commands for operating on "
26060b57cec5SDimitry Andric "one or more threads in "
26070b57cec5SDimitry Andric "the current process.",
26080b57cec5SDimitry Andric "thread <subcommand> [<subcommand-options>]") {
26090b57cec5SDimitry Andric LoadSubCommand("backtrace", CommandObjectSP(new CommandObjectThreadBacktrace(
26100b57cec5SDimitry Andric interpreter)));
26110b57cec5SDimitry Andric LoadSubCommand("continue",
26120b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadContinue(interpreter)));
26130b57cec5SDimitry Andric LoadSubCommand("list",
26140b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadList(interpreter)));
26150b57cec5SDimitry Andric LoadSubCommand("return",
26160b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadReturn(interpreter)));
26170b57cec5SDimitry Andric LoadSubCommand("jump",
26180b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadJump(interpreter)));
26190b57cec5SDimitry Andric LoadSubCommand("select",
26200b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadSelect(interpreter)));
26210b57cec5SDimitry Andric LoadSubCommand("until",
26220b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadUntil(interpreter)));
26230b57cec5SDimitry Andric LoadSubCommand("info",
26240b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadInfo(interpreter)));
2625480093f4SDimitry Andric LoadSubCommand("exception", CommandObjectSP(new CommandObjectThreadException(
2626480093f4SDimitry Andric interpreter)));
2627d56accc7SDimitry Andric LoadSubCommand("siginfo",
2628d56accc7SDimitry Andric CommandObjectSP(new CommandObjectThreadSiginfo(interpreter)));
26290b57cec5SDimitry Andric LoadSubCommand("step-in",
26300b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
26310b57cec5SDimitry Andric interpreter, "thread step-in",
26320b57cec5SDimitry Andric "Source level single step, stepping into calls. Defaults "
26330b57cec5SDimitry Andric "to current thread unless specified.",
26340b57cec5SDimitry Andric nullptr, eStepTypeInto, eStepScopeSource)));
26350b57cec5SDimitry Andric
26360b57cec5SDimitry Andric LoadSubCommand("step-out",
26370b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
26380b57cec5SDimitry Andric interpreter, "thread step-out",
26390b57cec5SDimitry Andric "Finish executing the current stack frame and stop after "
26400b57cec5SDimitry Andric "returning. Defaults to current thread unless specified.",
26410b57cec5SDimitry Andric nullptr, eStepTypeOut, eStepScopeSource)));
26420b57cec5SDimitry Andric
26430b57cec5SDimitry Andric LoadSubCommand("step-over",
26440b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
26450b57cec5SDimitry Andric interpreter, "thread step-over",
26460b57cec5SDimitry Andric "Source level single step, stepping over calls. Defaults "
26470b57cec5SDimitry Andric "to current thread unless specified.",
26480b57cec5SDimitry Andric nullptr, eStepTypeOver, eStepScopeSource)));
26490b57cec5SDimitry Andric
26500b57cec5SDimitry Andric LoadSubCommand("step-inst",
26510b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
26520b57cec5SDimitry Andric interpreter, "thread step-inst",
26530b57cec5SDimitry Andric "Instruction level single step, stepping into calls. "
26540b57cec5SDimitry Andric "Defaults to current thread unless specified.",
26550b57cec5SDimitry Andric nullptr, eStepTypeTrace, eStepScopeInstruction)));
26560b57cec5SDimitry Andric
26570b57cec5SDimitry Andric LoadSubCommand("step-inst-over",
26580b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
26590b57cec5SDimitry Andric interpreter, "thread step-inst-over",
26600b57cec5SDimitry Andric "Instruction level single step, stepping over calls. "
26610b57cec5SDimitry Andric "Defaults to current thread unless specified.",
26620b57cec5SDimitry Andric nullptr, eStepTypeTraceOver, eStepScopeInstruction)));
26630b57cec5SDimitry Andric
26640b57cec5SDimitry Andric LoadSubCommand(
26650b57cec5SDimitry Andric "step-scripted",
26660b57cec5SDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
26670b57cec5SDimitry Andric interpreter, "thread step-scripted",
26689dba64beSDimitry Andric "Step as instructed by the script class passed in the -C option. "
26699dba64beSDimitry Andric "You can also specify a dictionary of key (-k) and value (-v) pairs "
26709dba64beSDimitry Andric "that will be used to populate an SBStructuredData Dictionary, which "
26719dba64beSDimitry Andric "will be passed to the constructor of the class implementing the "
26729dba64beSDimitry Andric "scripted step. See the Python Reference for more details.",
26730b57cec5SDimitry Andric nullptr, eStepTypeScripted, eStepScopeSource)));
26740b57cec5SDimitry Andric
26750b57cec5SDimitry Andric LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan(
26760b57cec5SDimitry Andric interpreter)));
2677e8d8bef9SDimitry Andric LoadSubCommand("trace",
2678e8d8bef9SDimitry Andric CommandObjectSP(new CommandObjectMultiwordTrace(interpreter)));
26790b57cec5SDimitry Andric }
26800b57cec5SDimitry Andric
26810b57cec5SDimitry Andric CommandObjectMultiwordThread::~CommandObjectMultiwordThread() = default;
2682