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 &current_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 &current_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