xref: /freebsd-src/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===-- CommandObjectThread.cpp -------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "CommandObjectThread.h"
100b57cec5SDimitry Andric 
11fe6060f1SDimitry Andric #include <memory>
12bdd1243dSDimitry Andric #include <optional>
13e8d8bef9SDimitry Andric #include <sstream>
14e8d8bef9SDimitry Andric 
15e8d8bef9SDimitry Andric #include "CommandObjectThreadUtil.h"
16fe6060f1SDimitry Andric #include "CommandObjectTrace.h"
17e8d8bef9SDimitry Andric #include "lldb/Core/PluginManager.h"
180b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h"
190b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h"
200b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
21fcaf7f86SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
220b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
230b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
249dba64beSDimitry Andric #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
250b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h"
260b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
270b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
280b57cec5SDimitry Andric #include "lldb/Symbol/LineEntry.h"
290b57cec5SDimitry Andric #include "lldb/Symbol/LineTable.h"
300b57cec5SDimitry Andric #include "lldb/Target/Process.h"
310b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
320b57cec5SDimitry Andric #include "lldb/Target/SystemRuntime.h"
330b57cec5SDimitry Andric #include "lldb/Target/Target.h"
340b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
350b57cec5SDimitry Andric #include "lldb/Target/ThreadPlan.h"
360b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepInRange.h"
37e8d8bef9SDimitry Andric #include "lldb/Target/Trace.h"
3881ad6265SDimitry Andric #include "lldb/Target/TraceDumper.h"
390b57cec5SDimitry Andric #include "lldb/Utility/State.h"
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric using namespace lldb;
420b57cec5SDimitry Andric using namespace lldb_private;
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric // CommandObjectThreadBacktrace
450b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_backtrace
460b57cec5SDimitry Andric #include "CommandOptions.inc"
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads {
490b57cec5SDimitry Andric public:
500b57cec5SDimitry Andric   class CommandOptions : public Options {
510b57cec5SDimitry Andric   public:
5204eeddc0SDimitry Andric     CommandOptions() {
530b57cec5SDimitry Andric       // Keep default values of all options in one place: OptionParsingStarting
540b57cec5SDimitry Andric       // ()
550b57cec5SDimitry Andric       OptionParsingStarting(nullptr);
560b57cec5SDimitry Andric     }
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric     ~CommandOptions() override = default;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
610b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
620b57cec5SDimitry Andric       Status error;
630b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric       switch (short_option) {
66bdd1243dSDimitry Andric       case 'c':
670b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_count)) {
680b57cec5SDimitry Andric           m_count = UINT32_MAX;
690b57cec5SDimitry Andric           error.SetErrorStringWithFormat(
70*0fca6ea1SDimitry Andric               "invalid integer value for option '%c': %s", short_option,
71*0fca6ea1SDimitry Andric               option_arg.data());
72bdd1243dSDimitry Andric         }
73*0fca6ea1SDimitry Andric         // A count of 0 means all frames.
74*0fca6ea1SDimitry Andric         if (m_count == 0)
75*0fca6ea1SDimitry Andric           m_count = UINT32_MAX;
76bdd1243dSDimitry Andric         break;
770b57cec5SDimitry Andric       case 's':
780b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_start))
790b57cec5SDimitry Andric           error.SetErrorStringWithFormat(
80*0fca6ea1SDimitry Andric               "invalid integer value for option '%c': %s", short_option,
81*0fca6ea1SDimitry Andric               option_arg.data());
820b57cec5SDimitry Andric         break;
830b57cec5SDimitry Andric       case 'e': {
840b57cec5SDimitry Andric         bool success;
850b57cec5SDimitry Andric         m_extended_backtrace =
860b57cec5SDimitry Andric             OptionArgParser::ToBoolean(option_arg, false, &success);
870b57cec5SDimitry Andric         if (!success)
880b57cec5SDimitry Andric           error.SetErrorStringWithFormat(
89*0fca6ea1SDimitry Andric               "invalid boolean value for option '%c': %s", short_option,
90*0fca6ea1SDimitry Andric               option_arg.data());
910b57cec5SDimitry Andric       } break;
920b57cec5SDimitry Andric       default:
939dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
940b57cec5SDimitry Andric       }
950b57cec5SDimitry Andric       return error;
960b57cec5SDimitry Andric     }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
990b57cec5SDimitry Andric       m_count = UINT32_MAX;
1000b57cec5SDimitry Andric       m_start = 0;
1010b57cec5SDimitry Andric       m_extended_backtrace = false;
1020b57cec5SDimitry Andric     }
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
105bdd1243dSDimitry Andric       return llvm::ArrayRef(g_thread_backtrace_options);
1060b57cec5SDimitry Andric     }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
1090b57cec5SDimitry Andric     uint32_t m_count;
1100b57cec5SDimitry Andric     uint32_t m_start;
1110b57cec5SDimitry Andric     bool m_extended_backtrace;
1120b57cec5SDimitry Andric   };
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   CommandObjectThreadBacktrace(CommandInterpreter &interpreter)
1150b57cec5SDimitry Andric       : CommandObjectIterateOverThreads(
1160b57cec5SDimitry Andric             interpreter, "thread backtrace",
117*0fca6ea1SDimitry Andric             "Show backtraces of thread call stacks.  Defaults to the current "
118*0fca6ea1SDimitry Andric             "thread, thread indexes can be specified as arguments.\n"
1190b57cec5SDimitry Andric             "Use the thread-index \"all\" to see all threads.\n"
1200b57cec5SDimitry Andric             "Use the thread-index \"unique\" to see threads grouped by unique "
1210b57cec5SDimitry Andric             "call stacks.\n"
1220b57cec5SDimitry Andric             "Use 'settings set frame-format' to customize the printing of "
1230b57cec5SDimitry Andric             "frames in the backtrace and 'settings set thread-format' to "
1240b57cec5SDimitry Andric             "customize the thread header.",
1250b57cec5SDimitry Andric             nullptr,
1260b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandRequiresThread |
1270b57cec5SDimitry Andric                 eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
12804eeddc0SDimitry Andric                 eCommandProcessMustBePaused) {}
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric   ~CommandObjectThreadBacktrace() override = default;
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
1330b57cec5SDimitry Andric 
134bdd1243dSDimitry Andric   std::optional<std::string> GetRepeatCommand(Args &current_args,
135*0fca6ea1SDimitry Andric                                               uint32_t index) override {
13681ad6265SDimitry Andric     llvm::StringRef count_opt("--count");
13781ad6265SDimitry Andric     llvm::StringRef start_opt("--start");
13881ad6265SDimitry Andric 
13981ad6265SDimitry Andric     // If no "count" was provided, we are dumping the entire backtrace, so
14081ad6265SDimitry Andric     // there isn't a repeat command.  So we search for the count option in
14181ad6265SDimitry Andric     // the args, and if we find it, we make a copy and insert or modify the
14281ad6265SDimitry Andric     // start option's value to start count indices greater.
14381ad6265SDimitry Andric 
14481ad6265SDimitry Andric     Args copy_args(current_args);
14581ad6265SDimitry Andric     size_t num_entries = copy_args.GetArgumentCount();
14681ad6265SDimitry Andric     // These two point at the index of the option value if found.
14781ad6265SDimitry Andric     size_t count_idx = 0;
14881ad6265SDimitry Andric     size_t start_idx = 0;
14981ad6265SDimitry Andric     size_t count_val = 0;
15081ad6265SDimitry Andric     size_t start_val = 0;
15181ad6265SDimitry Andric 
15281ad6265SDimitry Andric     for (size_t idx = 0; idx < num_entries; idx++) {
15381ad6265SDimitry Andric       llvm::StringRef arg_string = copy_args[idx].ref();
154*0fca6ea1SDimitry Andric       if (arg_string == "-c" || count_opt.starts_with(arg_string)) {
15581ad6265SDimitry Andric         idx++;
15681ad6265SDimitry Andric         if (idx == num_entries)
157bdd1243dSDimitry Andric           return std::nullopt;
15881ad6265SDimitry Andric         count_idx = idx;
15981ad6265SDimitry Andric         if (copy_args[idx].ref().getAsInteger(0, count_val))
160bdd1243dSDimitry Andric           return std::nullopt;
161*0fca6ea1SDimitry Andric       } else if (arg_string == "-s" || start_opt.starts_with(arg_string)) {
16281ad6265SDimitry Andric         idx++;
16381ad6265SDimitry Andric         if (idx == num_entries)
164bdd1243dSDimitry Andric           return std::nullopt;
16581ad6265SDimitry Andric         start_idx = idx;
16681ad6265SDimitry Andric         if (copy_args[idx].ref().getAsInteger(0, start_val))
167bdd1243dSDimitry Andric           return std::nullopt;
16881ad6265SDimitry Andric       }
16981ad6265SDimitry Andric     }
17081ad6265SDimitry Andric     if (count_idx == 0)
171bdd1243dSDimitry Andric       return std::nullopt;
17281ad6265SDimitry Andric 
17381ad6265SDimitry Andric     std::string new_start_val = llvm::formatv("{0}", start_val + count_val);
17481ad6265SDimitry Andric     if (start_idx == 0) {
17581ad6265SDimitry Andric       copy_args.AppendArgument(start_opt);
17681ad6265SDimitry Andric       copy_args.AppendArgument(new_start_val);
17781ad6265SDimitry Andric     } else {
17881ad6265SDimitry Andric       copy_args.ReplaceArgumentAtIndex(start_idx, new_start_val);
17981ad6265SDimitry Andric     }
18081ad6265SDimitry Andric     std::string repeat_command;
18181ad6265SDimitry Andric     if (!copy_args.GetQuotedCommandString(repeat_command))
182bdd1243dSDimitry Andric       return std::nullopt;
18381ad6265SDimitry Andric     return repeat_command;
18481ad6265SDimitry Andric   }
18581ad6265SDimitry Andric 
1860b57cec5SDimitry Andric protected:
1870b57cec5SDimitry Andric   void DoExtendedBacktrace(Thread *thread, CommandReturnObject &result) {
1880b57cec5SDimitry Andric     SystemRuntime *runtime = thread->GetProcess()->GetSystemRuntime();
1890b57cec5SDimitry Andric     if (runtime) {
1900b57cec5SDimitry Andric       Stream &strm = result.GetOutputStream();
1910b57cec5SDimitry Andric       const std::vector<ConstString> &types =
1920b57cec5SDimitry Andric           runtime->GetExtendedBacktraceTypes();
1930b57cec5SDimitry Andric       for (auto type : types) {
1940b57cec5SDimitry Andric         ThreadSP ext_thread_sp = runtime->GetExtendedBacktraceThread(
1950b57cec5SDimitry Andric             thread->shared_from_this(), type);
1960b57cec5SDimitry Andric         if (ext_thread_sp && ext_thread_sp->IsValid()) {
1970b57cec5SDimitry Andric           const uint32_t num_frames_with_source = 0;
1980b57cec5SDimitry Andric           const bool stop_format = false;
199bdd1243dSDimitry Andric           strm.PutChar('\n');
2000b57cec5SDimitry Andric           if (ext_thread_sp->GetStatus(strm, m_options.m_start,
2010b57cec5SDimitry Andric                                        m_options.m_count,
202480093f4SDimitry Andric                                        num_frames_with_source, stop_format)) {
2030b57cec5SDimitry Andric             DoExtendedBacktrace(ext_thread_sp.get(), result);
2040b57cec5SDimitry Andric           }
2050b57cec5SDimitry Andric         }
2060b57cec5SDimitry Andric       }
2070b57cec5SDimitry Andric     }
2080b57cec5SDimitry Andric   }
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
2110b57cec5SDimitry Andric     ThreadSP thread_sp =
2120b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
2130b57cec5SDimitry Andric     if (!thread_sp) {
2140b57cec5SDimitry Andric       result.AppendErrorWithFormat(
2150b57cec5SDimitry Andric           "thread disappeared while computing backtraces: 0x%" PRIx64 "\n",
2160b57cec5SDimitry Andric           tid);
2170b57cec5SDimitry Andric       return false;
2180b57cec5SDimitry Andric     }
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric     Thread *thread = thread_sp.get();
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric     Stream &strm = result.GetOutputStream();
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric     // Only dump stack info if we processing unique stacks.
2250b57cec5SDimitry Andric     const bool only_stacks = m_unique_stacks;
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric     // Don't show source context when doing backtraces.
2280b57cec5SDimitry Andric     const uint32_t num_frames_with_source = 0;
2290b57cec5SDimitry Andric     const bool stop_format = true;
2300b57cec5SDimitry Andric     if (!thread->GetStatus(strm, m_options.m_start, m_options.m_count,
2310b57cec5SDimitry Andric                            num_frames_with_source, stop_format, only_stacks)) {
2320b57cec5SDimitry Andric       result.AppendErrorWithFormat(
2330b57cec5SDimitry Andric           "error displaying backtrace for thread: \"0x%4.4x\"\n",
2340b57cec5SDimitry Andric           thread->GetIndexID());
2350b57cec5SDimitry Andric       return false;
2360b57cec5SDimitry Andric     }
2370b57cec5SDimitry Andric     if (m_options.m_extended_backtrace) {
23806c3fb27SDimitry Andric       if (!INTERRUPT_REQUESTED(GetDebugger(),
23906c3fb27SDimitry Andric                                "Interrupt skipped extended backtrace")) {
2400b57cec5SDimitry Andric         DoExtendedBacktrace(thread, result);
2410b57cec5SDimitry Andric       }
24206c3fb27SDimitry Andric     }
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric     return true;
2450b57cec5SDimitry Andric   }
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric   CommandOptions m_options;
2480b57cec5SDimitry Andric };
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric enum StepScope { eStepScopeSource, eStepScopeInstruction };
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_step_scope
2530b57cec5SDimitry Andric #include "CommandOptions.inc"
2540b57cec5SDimitry Andric 
2559dba64beSDimitry Andric class ThreadStepScopeOptionGroup : public OptionGroup {
2560b57cec5SDimitry Andric public:
25704eeddc0SDimitry Andric   ThreadStepScopeOptionGroup() {
2580b57cec5SDimitry Andric     // Keep default values of all options in one place: OptionParsingStarting
2590b57cec5SDimitry Andric     // ()
2600b57cec5SDimitry Andric     OptionParsingStarting(nullptr);
2610b57cec5SDimitry Andric   }
2620b57cec5SDimitry Andric 
2639dba64beSDimitry Andric   ~ThreadStepScopeOptionGroup() override = default;
2649dba64beSDimitry Andric 
2659dba64beSDimitry Andric   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
266bdd1243dSDimitry Andric     return llvm::ArrayRef(g_thread_step_scope_options);
2679dba64beSDimitry Andric   }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2700b57cec5SDimitry Andric                         ExecutionContext *execution_context) override {
2710b57cec5SDimitry Andric     Status error;
272480093f4SDimitry Andric     const int short_option =
273480093f4SDimitry Andric         g_thread_step_scope_options[option_idx].short_option;
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric     switch (short_option) {
2760b57cec5SDimitry Andric     case 'a': {
2770b57cec5SDimitry Andric       bool success;
2780b57cec5SDimitry Andric       bool avoid_no_debug =
2790b57cec5SDimitry Andric           OptionArgParser::ToBoolean(option_arg, true, &success);
2800b57cec5SDimitry Andric       if (!success)
281*0fca6ea1SDimitry Andric         error.SetErrorStringWithFormat(
282*0fca6ea1SDimitry Andric             "invalid boolean value for option '%c': %s", short_option,
283*0fca6ea1SDimitry Andric             option_arg.data());
2840b57cec5SDimitry Andric       else {
285480093f4SDimitry Andric         m_step_in_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
2860b57cec5SDimitry Andric       }
2870b57cec5SDimitry Andric     } break;
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric     case 'A': {
2900b57cec5SDimitry Andric       bool success;
2910b57cec5SDimitry Andric       bool avoid_no_debug =
2920b57cec5SDimitry Andric           OptionArgParser::ToBoolean(option_arg, true, &success);
2930b57cec5SDimitry Andric       if (!success)
294*0fca6ea1SDimitry Andric         error.SetErrorStringWithFormat(
295*0fca6ea1SDimitry Andric             "invalid boolean value for option '%c': %s", short_option,
296*0fca6ea1SDimitry Andric             option_arg.data());
2970b57cec5SDimitry Andric       else {
298480093f4SDimitry Andric         m_step_out_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
2990b57cec5SDimitry Andric       }
3000b57cec5SDimitry Andric     } break;
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric     case 'c':
3030b57cec5SDimitry Andric       if (option_arg.getAsInteger(0, m_step_count))
304*0fca6ea1SDimitry Andric         error.SetErrorStringWithFormat(
305*0fca6ea1SDimitry Andric             "invalid integer value for option '%c': %s", short_option,
306*0fca6ea1SDimitry Andric             option_arg.data());
3070b57cec5SDimitry Andric       break;
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric     case 'm': {
3100b57cec5SDimitry Andric       auto enum_values = GetDefinitions()[option_idx].enum_values;
3110b57cec5SDimitry Andric       m_run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(
3120b57cec5SDimitry Andric           option_arg, enum_values, eOnlyDuringStepping, error);
3130b57cec5SDimitry Andric     } break;
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric     case 'e':
3160b57cec5SDimitry Andric       if (option_arg == "block") {
3170b57cec5SDimitry Andric         m_end_line_is_block_end = true;
3180b57cec5SDimitry Andric         break;
3190b57cec5SDimitry Andric       }
3200b57cec5SDimitry Andric       if (option_arg.getAsInteger(0, m_end_line))
3210b57cec5SDimitry Andric         error.SetErrorStringWithFormat("invalid end line number '%s'",
3220b57cec5SDimitry Andric                                        option_arg.str().c_str());
3230b57cec5SDimitry Andric       break;
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric     case 'r':
3260b57cec5SDimitry Andric       m_avoid_regexp.clear();
3275ffd83dbSDimitry Andric       m_avoid_regexp.assign(std::string(option_arg));
3280b57cec5SDimitry Andric       break;
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric     case 't':
3310b57cec5SDimitry Andric       m_step_in_target.clear();
3325ffd83dbSDimitry Andric       m_step_in_target.assign(std::string(option_arg));
3330b57cec5SDimitry Andric       break;
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric     default:
3369dba64beSDimitry Andric       llvm_unreachable("Unimplemented option");
3370b57cec5SDimitry Andric     }
3380b57cec5SDimitry Andric     return error;
3390b57cec5SDimitry Andric   }
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric   void OptionParsingStarting(ExecutionContext *execution_context) override {
3420b57cec5SDimitry Andric     m_step_in_avoid_no_debug = eLazyBoolCalculate;
3430b57cec5SDimitry Andric     m_step_out_avoid_no_debug = eLazyBoolCalculate;
3440b57cec5SDimitry Andric     m_run_mode = eOnlyDuringStepping;
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric     // Check if we are in Non-Stop mode
3470b57cec5SDimitry Andric     TargetSP target_sp =
3480b57cec5SDimitry Andric         execution_context ? execution_context->GetTargetSP() : TargetSP();
349e8d8bef9SDimitry Andric     ProcessSP process_sp =
350e8d8bef9SDimitry Andric         execution_context ? execution_context->GetProcessSP() : ProcessSP();
351e8d8bef9SDimitry Andric     if (process_sp && process_sp->GetSteppingRunsAllThreads())
352e8d8bef9SDimitry Andric       m_run_mode = eAllThreads;
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric     m_avoid_regexp.clear();
3550b57cec5SDimitry Andric     m_step_in_target.clear();
3560b57cec5SDimitry Andric     m_step_count = 1;
3570b57cec5SDimitry Andric     m_end_line = LLDB_INVALID_LINE_NUMBER;
3580b57cec5SDimitry Andric     m_end_line_is_block_end = false;
3590b57cec5SDimitry Andric   }
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric   // Instance variables to hold the values for command options.
3620b57cec5SDimitry Andric   LazyBool m_step_in_avoid_no_debug;
3630b57cec5SDimitry Andric   LazyBool m_step_out_avoid_no_debug;
3640b57cec5SDimitry Andric   RunMode m_run_mode;
3650b57cec5SDimitry Andric   std::string m_avoid_regexp;
3660b57cec5SDimitry Andric   std::string m_step_in_target;
3670b57cec5SDimitry Andric   uint32_t m_step_count;
3680b57cec5SDimitry Andric   uint32_t m_end_line;
3690b57cec5SDimitry Andric   bool m_end_line_is_block_end;
3700b57cec5SDimitry Andric };
3710b57cec5SDimitry Andric 
3729dba64beSDimitry Andric class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed {
3739dba64beSDimitry Andric public:
3740b57cec5SDimitry Andric   CommandObjectThreadStepWithTypeAndScope(CommandInterpreter &interpreter,
3750b57cec5SDimitry Andric                                           const char *name, const char *help,
3760b57cec5SDimitry Andric                                           const char *syntax,
3770b57cec5SDimitry Andric                                           StepType step_type,
3780b57cec5SDimitry Andric                                           StepScope step_scope)
3790b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, name, help, syntax,
3800b57cec5SDimitry Andric                             eCommandRequiresProcess | eCommandRequiresThread |
3810b57cec5SDimitry Andric                                 eCommandTryTargetAPILock |
3820b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched |
3830b57cec5SDimitry Andric                                 eCommandProcessMustBePaused),
38404eeddc0SDimitry Andric         m_step_type(step_type), m_step_scope(step_scope),
385480093f4SDimitry Andric         m_class_options("scripted step") {
386*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatOptional);
3879dba64beSDimitry Andric 
3889dba64beSDimitry Andric     if (step_type == eStepTypeScripted) {
389480093f4SDimitry Andric       m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
390480093f4SDimitry Andric                            LLDB_OPT_SET_1);
3919dba64beSDimitry Andric     }
3929dba64beSDimitry Andric     m_all_options.Append(&m_options);
3939dba64beSDimitry Andric     m_all_options.Finalize();
3940b57cec5SDimitry Andric   }
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric   ~CommandObjectThreadStepWithTypeAndScope() override = default;
3970b57cec5SDimitry Andric 
398e8d8bef9SDimitry Andric   void
399e8d8bef9SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
400e8d8bef9SDimitry Andric                            OptionElementVector &opt_element_vector) override {
401e8d8bef9SDimitry Andric     if (request.GetCursorIndex())
402e8d8bef9SDimitry Andric       return;
403*0fca6ea1SDimitry Andric     CommandObject::HandleArgumentCompletion(request, opt_element_vector);
404e8d8bef9SDimitry Andric   }
405e8d8bef9SDimitry Andric 
406480093f4SDimitry Andric   Options *GetOptions() override { return &m_all_options; }
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric protected:
4095f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
4100b57cec5SDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
4110b57cec5SDimitry Andric     bool synchronous_execution = m_interpreter.GetSynchronous();
4120b57cec5SDimitry Andric 
4130b57cec5SDimitry Andric     const uint32_t num_threads = process->GetThreadList().GetSize();
4140b57cec5SDimitry Andric     Thread *thread = nullptr;
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric     if (command.GetArgumentCount() == 0) {
4170b57cec5SDimitry Andric       thread = GetDefaultThread();
4180b57cec5SDimitry Andric 
4190b57cec5SDimitry Andric       if (thread == nullptr) {
4200b57cec5SDimitry Andric         result.AppendError("no selected thread in process");
4215f757f3fSDimitry Andric         return;
4220b57cec5SDimitry Andric       }
4230b57cec5SDimitry Andric     } else {
4240b57cec5SDimitry Andric       const char *thread_idx_cstr = command.GetArgumentAtIndex(0);
4255ffd83dbSDimitry Andric       uint32_t step_thread_idx;
4265ffd83dbSDimitry Andric 
4275ffd83dbSDimitry Andric       if (!llvm::to_integer(thread_idx_cstr, step_thread_idx)) {
4280b57cec5SDimitry Andric         result.AppendErrorWithFormat("invalid thread index '%s'.\n",
4290b57cec5SDimitry Andric                                      thread_idx_cstr);
4305f757f3fSDimitry Andric         return;
4310b57cec5SDimitry Andric       }
4320b57cec5SDimitry Andric       thread =
4330b57cec5SDimitry Andric           process->GetThreadList().FindThreadByIndexID(step_thread_idx).get();
4340b57cec5SDimitry Andric       if (thread == nullptr) {
4350b57cec5SDimitry Andric         result.AppendErrorWithFormat(
4360b57cec5SDimitry Andric             "Thread index %u is out of range (valid values are 0 - %u).\n",
4370b57cec5SDimitry Andric             step_thread_idx, num_threads);
4385f757f3fSDimitry Andric         return;
4390b57cec5SDimitry Andric       }
4400b57cec5SDimitry Andric     }
4410b57cec5SDimitry Andric 
4420b57cec5SDimitry Andric     if (m_step_type == eStepTypeScripted) {
443480093f4SDimitry Andric       if (m_class_options.GetName().empty()) {
4440b57cec5SDimitry Andric         result.AppendErrorWithFormat("empty class name for scripted step.");
4455f757f3fSDimitry Andric         return;
4460b57cec5SDimitry Andric       } else if (!GetDebugger().GetScriptInterpreter()->CheckObjectExists(
447480093f4SDimitry Andric                      m_class_options.GetName().c_str())) {
4480b57cec5SDimitry Andric         result.AppendErrorWithFormat(
4490b57cec5SDimitry Andric             "class for scripted step: \"%s\" does not exist.",
450480093f4SDimitry Andric             m_class_options.GetName().c_str());
4515f757f3fSDimitry Andric         return;
4520b57cec5SDimitry Andric       }
4530b57cec5SDimitry Andric     }
4540b57cec5SDimitry Andric 
4550b57cec5SDimitry Andric     if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER &&
4560b57cec5SDimitry Andric         m_step_type != eStepTypeInto) {
4570b57cec5SDimitry Andric       result.AppendErrorWithFormat(
4580b57cec5SDimitry Andric           "end line option is only valid for step into");
4595f757f3fSDimitry Andric       return;
4600b57cec5SDimitry Andric     }
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric     const bool abort_other_plans = false;
4630b57cec5SDimitry Andric     const lldb::RunMode stop_other_threads = m_options.m_run_mode;
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric     // This is a bit unfortunate, but not all the commands in this command
4660b57cec5SDimitry Andric     // object support only while stepping, so I use the bool for them.
4670b57cec5SDimitry Andric     bool bool_stop_other_threads;
4680b57cec5SDimitry Andric     if (m_options.m_run_mode == eAllThreads)
4690b57cec5SDimitry Andric       bool_stop_other_threads = false;
4700b57cec5SDimitry Andric     else if (m_options.m_run_mode == eOnlyDuringStepping)
471e8d8bef9SDimitry Andric       bool_stop_other_threads = (m_step_type != eStepTypeOut);
4720b57cec5SDimitry Andric     else
4730b57cec5SDimitry Andric       bool_stop_other_threads = true;
4740b57cec5SDimitry Andric 
4750b57cec5SDimitry Andric     ThreadPlanSP new_plan_sp;
4760b57cec5SDimitry Andric     Status new_plan_status;
4770b57cec5SDimitry Andric 
4780b57cec5SDimitry Andric     if (m_step_type == eStepTypeInto) {
4790b57cec5SDimitry Andric       StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
4800b57cec5SDimitry Andric       assert(frame != nullptr);
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric       if (frame->HasDebugInformation()) {
4830b57cec5SDimitry Andric         AddressRange range;
4840b57cec5SDimitry Andric         SymbolContext sc = frame->GetSymbolContext(eSymbolContextEverything);
4850b57cec5SDimitry Andric         if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER) {
4860b57cec5SDimitry Andric           Status error;
4870b57cec5SDimitry Andric           if (!sc.GetAddressRangeFromHereToEndLine(m_options.m_end_line, range,
4880b57cec5SDimitry Andric                                                    error)) {
4890b57cec5SDimitry Andric             result.AppendErrorWithFormat("invalid end-line option: %s.",
4900b57cec5SDimitry Andric                                          error.AsCString());
4915f757f3fSDimitry Andric             return;
4920b57cec5SDimitry Andric           }
4930b57cec5SDimitry Andric         } else if (m_options.m_end_line_is_block_end) {
4940b57cec5SDimitry Andric           Status error;
4950b57cec5SDimitry Andric           Block *block = frame->GetSymbolContext(eSymbolContextBlock).block;
4960b57cec5SDimitry Andric           if (!block) {
4970b57cec5SDimitry Andric             result.AppendErrorWithFormat("Could not find the current block.");
4985f757f3fSDimitry Andric             return;
4990b57cec5SDimitry Andric           }
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric           AddressRange block_range;
5020b57cec5SDimitry Andric           Address pc_address = frame->GetFrameCodeAddress();
5030b57cec5SDimitry Andric           block->GetRangeContainingAddress(pc_address, block_range);
5040b57cec5SDimitry Andric           if (!block_range.GetBaseAddress().IsValid()) {
5050b57cec5SDimitry Andric             result.AppendErrorWithFormat(
5060b57cec5SDimitry Andric                 "Could not find the current block address.");
5075f757f3fSDimitry Andric             return;
5080b57cec5SDimitry Andric           }
5090b57cec5SDimitry Andric           lldb::addr_t pc_offset_in_block =
5100b57cec5SDimitry Andric               pc_address.GetFileAddress() -
5110b57cec5SDimitry Andric               block_range.GetBaseAddress().GetFileAddress();
5120b57cec5SDimitry Andric           lldb::addr_t range_length =
5130b57cec5SDimitry Andric               block_range.GetByteSize() - pc_offset_in_block;
5140b57cec5SDimitry Andric           range = AddressRange(pc_address, range_length);
5150b57cec5SDimitry Andric         } else {
5160b57cec5SDimitry Andric           range = sc.line_entry.range;
5170b57cec5SDimitry Andric         }
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric         new_plan_sp = thread->QueueThreadPlanForStepInRange(
5200b57cec5SDimitry Andric             abort_other_plans, range,
5210b57cec5SDimitry Andric             frame->GetSymbolContext(eSymbolContextEverything),
5220b57cec5SDimitry Andric             m_options.m_step_in_target.c_str(), stop_other_threads,
5230b57cec5SDimitry Andric             new_plan_status, m_options.m_step_in_avoid_no_debug,
5240b57cec5SDimitry Andric             m_options.m_step_out_avoid_no_debug);
5250b57cec5SDimitry Andric 
5260b57cec5SDimitry Andric         if (new_plan_sp && !m_options.m_avoid_regexp.empty()) {
5270b57cec5SDimitry Andric           ThreadPlanStepInRange *step_in_range_plan =
5280b57cec5SDimitry Andric               static_cast<ThreadPlanStepInRange *>(new_plan_sp.get());
5290b57cec5SDimitry Andric           step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str());
5300b57cec5SDimitry Andric         }
5310b57cec5SDimitry Andric       } else
5320b57cec5SDimitry Andric         new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
5330b57cec5SDimitry Andric             false, abort_other_plans, bool_stop_other_threads, new_plan_status);
5340b57cec5SDimitry Andric     } else if (m_step_type == eStepTypeOver) {
5350b57cec5SDimitry Andric       StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric       if (frame->HasDebugInformation())
5380b57cec5SDimitry Andric         new_plan_sp = thread->QueueThreadPlanForStepOverRange(
5390b57cec5SDimitry Andric             abort_other_plans,
5400b57cec5SDimitry Andric             frame->GetSymbolContext(eSymbolContextEverything).line_entry,
5410b57cec5SDimitry Andric             frame->GetSymbolContext(eSymbolContextEverything),
5420b57cec5SDimitry Andric             stop_other_threads, new_plan_status,
5430b57cec5SDimitry Andric             m_options.m_step_out_avoid_no_debug);
5440b57cec5SDimitry Andric       else
5450b57cec5SDimitry Andric         new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
5460b57cec5SDimitry Andric             true, abort_other_plans, bool_stop_other_threads, new_plan_status);
5470b57cec5SDimitry Andric     } else if (m_step_type == eStepTypeTrace) {
5480b57cec5SDimitry Andric       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
5490b57cec5SDimitry Andric           false, abort_other_plans, bool_stop_other_threads, new_plan_status);
5500b57cec5SDimitry Andric     } else if (m_step_type == eStepTypeTraceOver) {
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 == eStepTypeOut) {
5540b57cec5SDimitry Andric       new_plan_sp = thread->QueueThreadPlanForStepOut(
5550b57cec5SDimitry Andric           abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes,
55606c3fb27SDimitry Andric           eVoteNoOpinion,
55706c3fb27SDimitry Andric           thread->GetSelectedFrameIndex(DoNoSelectMostRelevantFrame),
55806c3fb27SDimitry Andric           new_plan_status, m_options.m_step_out_avoid_no_debug);
5590b57cec5SDimitry Andric     } else if (m_step_type == eStepTypeScripted) {
5600b57cec5SDimitry Andric       new_plan_sp = thread->QueueThreadPlanForStepScripted(
561480093f4SDimitry Andric           abort_other_plans, m_class_options.GetName().c_str(),
562480093f4SDimitry Andric           m_class_options.GetStructuredData(), bool_stop_other_threads,
563480093f4SDimitry Andric           new_plan_status);
5640b57cec5SDimitry Andric     } else {
5650b57cec5SDimitry Andric       result.AppendError("step type is not supported");
5665f757f3fSDimitry Andric       return;
5670b57cec5SDimitry Andric     }
5680b57cec5SDimitry Andric 
569349cc55cSDimitry Andric     // If we got a new plan, then set it to be a controlling plan (User level
570349cc55cSDimitry Andric     // Plans should be controlling plans so that they can be interruptible).
571349cc55cSDimitry Andric     // Then resume the process.
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric     if (new_plan_sp) {
574349cc55cSDimitry Andric       new_plan_sp->SetIsControllingPlan(true);
5750b57cec5SDimitry Andric       new_plan_sp->SetOkayToDiscard(false);
5760b57cec5SDimitry Andric 
5770b57cec5SDimitry Andric       if (m_options.m_step_count > 1) {
5780b57cec5SDimitry Andric         if (!new_plan_sp->SetIterationCount(m_options.m_step_count)) {
5790b57cec5SDimitry Andric           result.AppendWarning(
5800b57cec5SDimitry Andric               "step operation does not support iteration count.");
5810b57cec5SDimitry Andric         }
5820b57cec5SDimitry Andric       }
5830b57cec5SDimitry Andric 
5840b57cec5SDimitry Andric       process->GetThreadList().SetSelectedThreadByID(thread->GetID());
5850b57cec5SDimitry Andric 
5860b57cec5SDimitry Andric       const uint32_t iohandler_id = process->GetIOHandlerID();
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric       StreamString stream;
5890b57cec5SDimitry Andric       Status error;
5900b57cec5SDimitry Andric       if (synchronous_execution)
5910b57cec5SDimitry Andric         error = process->ResumeSynchronous(&stream);
5920b57cec5SDimitry Andric       else
5930b57cec5SDimitry Andric         error = process->Resume();
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric       if (!error.Success()) {
5960b57cec5SDimitry Andric         result.AppendMessage(error.AsCString());
5975f757f3fSDimitry Andric         return;
5980b57cec5SDimitry Andric       }
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric       // There is a race condition where this thread will return up the call
6010b57cec5SDimitry Andric       // stack to the main command handler and show an (lldb) prompt before
6020b57cec5SDimitry Andric       // HandlePrivateEvent (from PrivateStateThread) has a chance to call
6030b57cec5SDimitry Andric       // PushProcessIOHandler().
6040b57cec5SDimitry Andric       process->SyncIOHandler(iohandler_id, std::chrono::seconds(2));
6050b57cec5SDimitry Andric 
6060b57cec5SDimitry Andric       if (synchronous_execution) {
6070b57cec5SDimitry Andric         // If any state changed events had anything to say, add that to the
6080b57cec5SDimitry Andric         // result
6090b57cec5SDimitry Andric         if (stream.GetSize() > 0)
6100b57cec5SDimitry Andric           result.AppendMessage(stream.GetString());
6110b57cec5SDimitry Andric 
6120b57cec5SDimitry Andric         process->GetThreadList().SetSelectedThreadByID(thread->GetID());
6130b57cec5SDimitry Andric         result.SetDidChangeProcessState(true);
6140b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishNoResult);
6150b57cec5SDimitry Andric       } else {
6160b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessContinuingNoResult);
6170b57cec5SDimitry Andric       }
6180b57cec5SDimitry Andric     } else {
6190b57cec5SDimitry Andric       result.SetError(new_plan_status);
6200b57cec5SDimitry Andric     }
6210b57cec5SDimitry Andric   }
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric   StepType m_step_type;
6240b57cec5SDimitry Andric   StepScope m_step_scope;
6259dba64beSDimitry Andric   ThreadStepScopeOptionGroup m_options;
6269dba64beSDimitry Andric   OptionGroupPythonClassWithDict m_class_options;
6279dba64beSDimitry Andric   OptionGroupOptions m_all_options;
6280b57cec5SDimitry Andric };
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric // CommandObjectThreadContinue
6310b57cec5SDimitry Andric 
6320b57cec5SDimitry Andric class CommandObjectThreadContinue : public CommandObjectParsed {
6330b57cec5SDimitry Andric public:
6340b57cec5SDimitry Andric   CommandObjectThreadContinue(CommandInterpreter &interpreter)
6350b57cec5SDimitry Andric       : CommandObjectParsed(
6360b57cec5SDimitry Andric             interpreter, "thread continue",
6370b57cec5SDimitry Andric             "Continue execution of the current target process.  One "
6380b57cec5SDimitry Andric             "or more threads may be specified, by default all "
6390b57cec5SDimitry Andric             "threads continue.",
6400b57cec5SDimitry Andric             nullptr,
6410b57cec5SDimitry Andric             eCommandRequiresThread | eCommandTryTargetAPILock |
6420b57cec5SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
643*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatPlus);
6440b57cec5SDimitry Andric   }
6450b57cec5SDimitry Andric 
6460b57cec5SDimitry Andric   ~CommandObjectThreadContinue() override = default;
6470b57cec5SDimitry Andric 
6485f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
6490b57cec5SDimitry Andric     bool synchronous_execution = m_interpreter.GetSynchronous();
6500b57cec5SDimitry Andric 
6510b57cec5SDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
6520b57cec5SDimitry Andric     if (process == nullptr) {
6530b57cec5SDimitry Andric       result.AppendError("no process exists. Cannot continue");
6545f757f3fSDimitry Andric       return;
6550b57cec5SDimitry Andric     }
6560b57cec5SDimitry Andric 
6570b57cec5SDimitry Andric     StateType state = process->GetState();
6580b57cec5SDimitry Andric     if ((state == eStateCrashed) || (state == eStateStopped) ||
6590b57cec5SDimitry Andric         (state == eStateSuspended)) {
6600b57cec5SDimitry Andric       const size_t argc = command.GetArgumentCount();
6610b57cec5SDimitry Andric       if (argc > 0) {
6620b57cec5SDimitry Andric         // These two lines appear at the beginning of both blocks in this
6630b57cec5SDimitry Andric         // if..else, but that is because we need to release the lock before
6640b57cec5SDimitry Andric         // calling process->Resume below.
6650b57cec5SDimitry Andric         std::lock_guard<std::recursive_mutex> guard(
6660b57cec5SDimitry Andric             process->GetThreadList().GetMutex());
6670b57cec5SDimitry Andric         const uint32_t num_threads = process->GetThreadList().GetSize();
6680b57cec5SDimitry Andric         std::vector<Thread *> resume_threads;
6690b57cec5SDimitry Andric         for (auto &entry : command.entries()) {
6700b57cec5SDimitry Andric           uint32_t thread_idx;
6719dba64beSDimitry Andric           if (entry.ref().getAsInteger(0, thread_idx)) {
6720b57cec5SDimitry Andric             result.AppendErrorWithFormat(
6730b57cec5SDimitry Andric                 "invalid thread index argument: \"%s\".\n", entry.c_str());
6745f757f3fSDimitry Andric             return;
6750b57cec5SDimitry Andric           }
6760b57cec5SDimitry Andric           Thread *thread =
6770b57cec5SDimitry Andric               process->GetThreadList().FindThreadByIndexID(thread_idx).get();
6780b57cec5SDimitry Andric 
6790b57cec5SDimitry Andric           if (thread) {
6800b57cec5SDimitry Andric             resume_threads.push_back(thread);
6810b57cec5SDimitry Andric           } else {
6820b57cec5SDimitry Andric             result.AppendErrorWithFormat("invalid thread index %u.\n",
6830b57cec5SDimitry Andric                                          thread_idx);
6845f757f3fSDimitry Andric             return;
6850b57cec5SDimitry Andric           }
6860b57cec5SDimitry Andric         }
6870b57cec5SDimitry Andric 
6880b57cec5SDimitry Andric         if (resume_threads.empty()) {
6890b57cec5SDimitry Andric           result.AppendError("no valid thread indexes were specified");
6905f757f3fSDimitry Andric           return;
6910b57cec5SDimitry Andric         } else {
6920b57cec5SDimitry Andric           if (resume_threads.size() == 1)
6930b57cec5SDimitry Andric             result.AppendMessageWithFormat("Resuming thread: ");
6940b57cec5SDimitry Andric           else
6950b57cec5SDimitry Andric             result.AppendMessageWithFormat("Resuming threads: ");
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric           for (uint32_t idx = 0; idx < num_threads; ++idx) {
6980b57cec5SDimitry Andric             Thread *thread =
6990b57cec5SDimitry Andric                 process->GetThreadList().GetThreadAtIndex(idx).get();
7000b57cec5SDimitry Andric             std::vector<Thread *>::iterator this_thread_pos =
7010b57cec5SDimitry Andric                 find(resume_threads.begin(), resume_threads.end(), thread);
7020b57cec5SDimitry Andric 
7030b57cec5SDimitry Andric             if (this_thread_pos != resume_threads.end()) {
7040b57cec5SDimitry Andric               resume_threads.erase(this_thread_pos);
7050b57cec5SDimitry Andric               if (!resume_threads.empty())
7060b57cec5SDimitry Andric                 result.AppendMessageWithFormat("%u, ", thread->GetIndexID());
7070b57cec5SDimitry Andric               else
7080b57cec5SDimitry Andric                 result.AppendMessageWithFormat("%u ", thread->GetIndexID());
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric               const bool override_suspend = true;
7110b57cec5SDimitry Andric               thread->SetResumeState(eStateRunning, override_suspend);
7120b57cec5SDimitry Andric             } else {
7130b57cec5SDimitry Andric               thread->SetResumeState(eStateSuspended);
7140b57cec5SDimitry Andric             }
7150b57cec5SDimitry Andric           }
7160b57cec5SDimitry Andric           result.AppendMessageWithFormat("in process %" PRIu64 "\n",
7170b57cec5SDimitry Andric                                          process->GetID());
7180b57cec5SDimitry Andric         }
7190b57cec5SDimitry Andric       } else {
7200b57cec5SDimitry Andric         // These two lines appear at the beginning of both blocks in this
7210b57cec5SDimitry Andric         // if..else, but that is because we need to release the lock before
7220b57cec5SDimitry Andric         // calling process->Resume below.
7230b57cec5SDimitry Andric         std::lock_guard<std::recursive_mutex> guard(
7240b57cec5SDimitry Andric             process->GetThreadList().GetMutex());
7250b57cec5SDimitry Andric         const uint32_t num_threads = process->GetThreadList().GetSize();
7260b57cec5SDimitry Andric         Thread *current_thread = GetDefaultThread();
7270b57cec5SDimitry Andric         if (current_thread == nullptr) {
7280b57cec5SDimitry Andric           result.AppendError("the process doesn't have a current thread");
7295f757f3fSDimitry Andric           return;
7300b57cec5SDimitry Andric         }
7310b57cec5SDimitry Andric         // Set the actions that the threads should each take when resuming
7320b57cec5SDimitry Andric         for (uint32_t idx = 0; idx < num_threads; ++idx) {
7330b57cec5SDimitry Andric           Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
7340b57cec5SDimitry Andric           if (thread == current_thread) {
7350b57cec5SDimitry Andric             result.AppendMessageWithFormat("Resuming thread 0x%4.4" PRIx64
7360b57cec5SDimitry Andric                                            " in process %" PRIu64 "\n",
7370b57cec5SDimitry Andric                                            thread->GetID(), process->GetID());
7380b57cec5SDimitry Andric             const bool override_suspend = true;
7390b57cec5SDimitry Andric             thread->SetResumeState(eStateRunning, override_suspend);
7400b57cec5SDimitry Andric           } else {
7410b57cec5SDimitry Andric             thread->SetResumeState(eStateSuspended);
7420b57cec5SDimitry Andric           }
7430b57cec5SDimitry Andric         }
7440b57cec5SDimitry Andric       }
7450b57cec5SDimitry Andric 
7460b57cec5SDimitry Andric       StreamString stream;
7470b57cec5SDimitry Andric       Status error;
7480b57cec5SDimitry Andric       if (synchronous_execution)
7490b57cec5SDimitry Andric         error = process->ResumeSynchronous(&stream);
7500b57cec5SDimitry Andric       else
7510b57cec5SDimitry Andric         error = process->Resume();
7520b57cec5SDimitry Andric 
7530b57cec5SDimitry Andric       // We should not be holding the thread list lock when we do this.
7540b57cec5SDimitry Andric       if (error.Success()) {
7550b57cec5SDimitry Andric         result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",
7560b57cec5SDimitry Andric                                        process->GetID());
7570b57cec5SDimitry Andric         if (synchronous_execution) {
7580b57cec5SDimitry Andric           // If any state changed events had anything to say, add that to the
7590b57cec5SDimitry Andric           // result
7600b57cec5SDimitry Andric           if (stream.GetSize() > 0)
7610b57cec5SDimitry Andric             result.AppendMessage(stream.GetString());
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric           result.SetDidChangeProcessState(true);
7640b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishNoResult);
7650b57cec5SDimitry Andric         } else {
7660b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessContinuingNoResult);
7670b57cec5SDimitry Andric         }
7680b57cec5SDimitry Andric       } else {
7690b57cec5SDimitry Andric         result.AppendErrorWithFormat("Failed to resume process: %s\n",
7700b57cec5SDimitry Andric                                      error.AsCString());
7710b57cec5SDimitry Andric       }
7720b57cec5SDimitry Andric     } else {
7730b57cec5SDimitry Andric       result.AppendErrorWithFormat(
7740b57cec5SDimitry Andric           "Process cannot be continued from its current state (%s).\n",
7750b57cec5SDimitry Andric           StateAsCString(state));
7760b57cec5SDimitry Andric     }
7770b57cec5SDimitry Andric   }
7780b57cec5SDimitry Andric };
7790b57cec5SDimitry Andric 
7800b57cec5SDimitry Andric // CommandObjectThreadUntil
7810b57cec5SDimitry Andric 
7820b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_until
7830b57cec5SDimitry Andric #include "CommandOptions.inc"
7840b57cec5SDimitry Andric 
7850b57cec5SDimitry Andric class CommandObjectThreadUntil : public CommandObjectParsed {
7860b57cec5SDimitry Andric public:
7870b57cec5SDimitry Andric   class CommandOptions : public Options {
7880b57cec5SDimitry Andric   public:
789fe6060f1SDimitry Andric     uint32_t m_thread_idx = LLDB_INVALID_THREAD_ID;
790fe6060f1SDimitry Andric     uint32_t m_frame_idx = LLDB_INVALID_FRAME_ID;
7910b57cec5SDimitry Andric 
79204eeddc0SDimitry Andric     CommandOptions() {
7930b57cec5SDimitry Andric       // Keep default values of all options in one place: OptionParsingStarting
7940b57cec5SDimitry Andric       // ()
7950b57cec5SDimitry Andric       OptionParsingStarting(nullptr);
7960b57cec5SDimitry Andric     }
7970b57cec5SDimitry Andric 
7980b57cec5SDimitry Andric     ~CommandOptions() override = default;
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
8010b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
8020b57cec5SDimitry Andric       Status error;
8030b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
8040b57cec5SDimitry Andric 
8050b57cec5SDimitry Andric       switch (short_option) {
8060b57cec5SDimitry Andric       case 'a': {
8070b57cec5SDimitry Andric         lldb::addr_t tmp_addr = OptionArgParser::ToAddress(
8080b57cec5SDimitry Andric             execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
8090b57cec5SDimitry Andric         if (error.Success())
8100b57cec5SDimitry Andric           m_until_addrs.push_back(tmp_addr);
8110b57cec5SDimitry Andric       } break;
8120b57cec5SDimitry Andric       case 't':
8130b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_thread_idx)) {
8140b57cec5SDimitry Andric           m_thread_idx = LLDB_INVALID_INDEX32;
8150b57cec5SDimitry Andric           error.SetErrorStringWithFormat("invalid thread index '%s'",
8160b57cec5SDimitry Andric                                          option_arg.str().c_str());
8170b57cec5SDimitry Andric         }
8180b57cec5SDimitry Andric         break;
8190b57cec5SDimitry Andric       case 'f':
8200b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_frame_idx)) {
8210b57cec5SDimitry Andric           m_frame_idx = LLDB_INVALID_FRAME_ID;
8220b57cec5SDimitry Andric           error.SetErrorStringWithFormat("invalid frame index '%s'",
8230b57cec5SDimitry Andric                                          option_arg.str().c_str());
8240b57cec5SDimitry Andric         }
8250b57cec5SDimitry Andric         break;
8260b57cec5SDimitry Andric       case 'm': {
8270b57cec5SDimitry Andric         auto enum_values = GetDefinitions()[option_idx].enum_values;
8280b57cec5SDimitry Andric         lldb::RunMode run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(
8290b57cec5SDimitry Andric             option_arg, enum_values, eOnlyDuringStepping, error);
8300b57cec5SDimitry Andric 
8310b57cec5SDimitry Andric         if (error.Success()) {
8320b57cec5SDimitry Andric           if (run_mode == eAllThreads)
8330b57cec5SDimitry Andric             m_stop_others = false;
8340b57cec5SDimitry Andric           else
8350b57cec5SDimitry Andric             m_stop_others = true;
8360b57cec5SDimitry Andric         }
8370b57cec5SDimitry Andric       } break;
8380b57cec5SDimitry Andric       default:
8399dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
8400b57cec5SDimitry Andric       }
8410b57cec5SDimitry Andric       return error;
8420b57cec5SDimitry Andric     }
8430b57cec5SDimitry Andric 
8440b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
8450b57cec5SDimitry Andric       m_thread_idx = LLDB_INVALID_THREAD_ID;
8460b57cec5SDimitry Andric       m_frame_idx = 0;
8470b57cec5SDimitry Andric       m_stop_others = false;
8480b57cec5SDimitry Andric       m_until_addrs.clear();
8490b57cec5SDimitry Andric     }
8500b57cec5SDimitry Andric 
8510b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
852bdd1243dSDimitry Andric       return llvm::ArrayRef(g_thread_until_options);
8530b57cec5SDimitry Andric     }
8540b57cec5SDimitry Andric 
855fcaf7f86SDimitry Andric     uint32_t m_step_thread_idx = LLDB_INVALID_THREAD_ID;
856fcaf7f86SDimitry Andric     bool m_stop_others = false;
8570b57cec5SDimitry Andric     std::vector<lldb::addr_t> m_until_addrs;
8580b57cec5SDimitry Andric 
8590b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
8600b57cec5SDimitry Andric   };
8610b57cec5SDimitry Andric 
8620b57cec5SDimitry Andric   CommandObjectThreadUntil(CommandInterpreter &interpreter)
8630b57cec5SDimitry Andric       : CommandObjectParsed(
8640b57cec5SDimitry Andric             interpreter, "thread until",
8650b57cec5SDimitry Andric             "Continue until a line number or address is reached by the "
8660b57cec5SDimitry Andric             "current or specified thread.  Stops when returning from "
8670b57cec5SDimitry Andric             "the current function as a safety measure.  "
868480093f4SDimitry Andric             "The target line number(s) are given as arguments, and if more "
869480093f4SDimitry Andric             "than one"
8700b57cec5SDimitry Andric             " is provided, stepping will stop when the first one is hit.",
8710b57cec5SDimitry Andric             nullptr,
8720b57cec5SDimitry Andric             eCommandRequiresThread | eCommandTryTargetAPILock |
87304eeddc0SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
874*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeLineNum);
8750b57cec5SDimitry Andric   }
8760b57cec5SDimitry Andric 
8770b57cec5SDimitry Andric   ~CommandObjectThreadUntil() override = default;
8780b57cec5SDimitry Andric 
8790b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
8800b57cec5SDimitry Andric 
8810b57cec5SDimitry Andric protected:
8825f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
8830b57cec5SDimitry Andric     bool synchronous_execution = m_interpreter.GetSynchronous();
8840b57cec5SDimitry Andric 
8859dba64beSDimitry Andric     Target *target = &GetSelectedTarget();
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
8880b57cec5SDimitry Andric     if (process == nullptr) {
8890b57cec5SDimitry Andric       result.AppendError("need a valid process to step");
8900b57cec5SDimitry Andric     } else {
8910b57cec5SDimitry Andric       Thread *thread = nullptr;
8920b57cec5SDimitry Andric       std::vector<uint32_t> line_numbers;
8930b57cec5SDimitry Andric 
8940b57cec5SDimitry Andric       if (command.GetArgumentCount() >= 1) {
8950b57cec5SDimitry Andric         size_t num_args = command.GetArgumentCount();
8960b57cec5SDimitry Andric         for (size_t i = 0; i < num_args; i++) {
8970b57cec5SDimitry Andric           uint32_t line_number;
8985ffd83dbSDimitry Andric           if (!llvm::to_integer(command.GetArgumentAtIndex(i), line_number)) {
8990b57cec5SDimitry Andric             result.AppendErrorWithFormat("invalid line number: '%s'.\n",
9000b57cec5SDimitry Andric                                          command.GetArgumentAtIndex(i));
9015f757f3fSDimitry Andric             return;
9020b57cec5SDimitry Andric           } else
9030b57cec5SDimitry Andric             line_numbers.push_back(line_number);
9040b57cec5SDimitry Andric         }
9050b57cec5SDimitry Andric       } else if (m_options.m_until_addrs.empty()) {
9060b57cec5SDimitry Andric         result.AppendErrorWithFormat("No line number or address provided:\n%s",
9070b57cec5SDimitry Andric                                      GetSyntax().str().c_str());
9085f757f3fSDimitry Andric         return;
9090b57cec5SDimitry Andric       }
9100b57cec5SDimitry Andric 
9110b57cec5SDimitry Andric       if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) {
9120b57cec5SDimitry Andric         thread = GetDefaultThread();
9130b57cec5SDimitry Andric       } else {
9140b57cec5SDimitry Andric         thread = process->GetThreadList()
9150b57cec5SDimitry Andric                      .FindThreadByIndexID(m_options.m_thread_idx)
9160b57cec5SDimitry Andric                      .get();
9170b57cec5SDimitry Andric       }
9180b57cec5SDimitry Andric 
9190b57cec5SDimitry Andric       if (thread == nullptr) {
9200b57cec5SDimitry Andric         const uint32_t num_threads = process->GetThreadList().GetSize();
9210b57cec5SDimitry Andric         result.AppendErrorWithFormat(
9220b57cec5SDimitry Andric             "Thread index %u is out of range (valid values are 0 - %u).\n",
9230b57cec5SDimitry Andric             m_options.m_thread_idx, num_threads);
9245f757f3fSDimitry Andric         return;
9250b57cec5SDimitry Andric       }
9260b57cec5SDimitry Andric 
9270b57cec5SDimitry Andric       const bool abort_other_plans = false;
9280b57cec5SDimitry Andric 
9290b57cec5SDimitry Andric       StackFrame *frame =
9300b57cec5SDimitry Andric           thread->GetStackFrameAtIndex(m_options.m_frame_idx).get();
9310b57cec5SDimitry Andric       if (frame == nullptr) {
9320b57cec5SDimitry Andric         result.AppendErrorWithFormat(
93381ad6265SDimitry Andric             "Frame index %u is out of range for thread id %" PRIu64 ".\n",
93481ad6265SDimitry Andric             m_options.m_frame_idx, thread->GetID());
9355f757f3fSDimitry Andric         return;
9360b57cec5SDimitry Andric       }
9370b57cec5SDimitry Andric 
9380b57cec5SDimitry Andric       ThreadPlanSP new_plan_sp;
9390b57cec5SDimitry Andric       Status new_plan_status;
9400b57cec5SDimitry Andric 
9410b57cec5SDimitry Andric       if (frame->HasDebugInformation()) {
9420b57cec5SDimitry Andric         // Finally we got here...  Translate the given line number to a bunch
9430b57cec5SDimitry Andric         // of addresses:
9440b57cec5SDimitry Andric         SymbolContext sc(frame->GetSymbolContext(eSymbolContextCompUnit));
9450b57cec5SDimitry Andric         LineTable *line_table = nullptr;
9460b57cec5SDimitry Andric         if (sc.comp_unit)
9470b57cec5SDimitry Andric           line_table = sc.comp_unit->GetLineTable();
9480b57cec5SDimitry Andric 
9490b57cec5SDimitry Andric         if (line_table == nullptr) {
9500b57cec5SDimitry Andric           result.AppendErrorWithFormat("Failed to resolve the line table for "
95181ad6265SDimitry Andric                                        "frame %u of thread id %" PRIu64 ".\n",
95281ad6265SDimitry Andric                                        m_options.m_frame_idx, thread->GetID());
9535f757f3fSDimitry Andric           return;
9540b57cec5SDimitry Andric         }
9550b57cec5SDimitry Andric 
9560b57cec5SDimitry Andric         LineEntry function_start;
957bdd1243dSDimitry Andric         uint32_t index_ptr = 0, end_ptr = UINT32_MAX;
9580b57cec5SDimitry Andric         std::vector<addr_t> address_list;
9590b57cec5SDimitry Andric 
96081ad6265SDimitry Andric         // Find the beginning & end index of the function, but first make
96181ad6265SDimitry Andric         // sure it is valid:
96281ad6265SDimitry Andric         if (!sc.function) {
96381ad6265SDimitry Andric           result.AppendErrorWithFormat("Have debug information but no "
96481ad6265SDimitry Andric                                        "function info - can't get until range.");
9655f757f3fSDimitry Andric           return;
96681ad6265SDimitry Andric         }
96781ad6265SDimitry Andric 
9680b57cec5SDimitry Andric         AddressRange fun_addr_range = sc.function->GetAddressRange();
9690b57cec5SDimitry Andric         Address fun_start_addr = fun_addr_range.GetBaseAddress();
9700b57cec5SDimitry Andric         line_table->FindLineEntryByAddress(fun_start_addr, function_start,
9710b57cec5SDimitry Andric                                            &index_ptr);
9720b57cec5SDimitry Andric 
9730b57cec5SDimitry Andric         Address fun_end_addr(fun_start_addr.GetSection(),
9740b57cec5SDimitry Andric                              fun_start_addr.GetOffset() +
9750b57cec5SDimitry Andric                                  fun_addr_range.GetByteSize());
9760b57cec5SDimitry Andric 
9770b57cec5SDimitry Andric         bool all_in_function = true;
9780b57cec5SDimitry Andric 
9790b57cec5SDimitry Andric         line_table->FindLineEntryByAddress(fun_end_addr, function_start,
9800b57cec5SDimitry Andric                                            &end_ptr);
9810b57cec5SDimitry Andric 
982753f127fSDimitry Andric         // Since not all source lines will contribute code, check if we are
983753f127fSDimitry Andric         // setting the breakpoint on the exact line number or the nearest
984753f127fSDimitry Andric         // subsequent line number and set breakpoints at all the line table
985753f127fSDimitry Andric         // entries of the chosen line number (exact or nearest subsequent).
9860b57cec5SDimitry Andric         for (uint32_t line_number : line_numbers) {
9870b57cec5SDimitry Andric           LineEntry line_entry;
988753f127fSDimitry Andric           bool exact = false;
989753f127fSDimitry Andric           uint32_t start_idx_ptr = index_ptr;
990753f127fSDimitry Andric           start_idx_ptr = sc.comp_unit->FindLineEntry(
991753f127fSDimitry Andric               index_ptr, line_number, nullptr, exact, &line_entry);
992753f127fSDimitry Andric           if (start_idx_ptr != UINT32_MAX)
993753f127fSDimitry Andric             line_number = line_entry.line;
994753f127fSDimitry Andric           exact = true;
995753f127fSDimitry Andric           start_idx_ptr = index_ptr;
996753f127fSDimitry Andric           while (start_idx_ptr <= end_ptr) {
9970b57cec5SDimitry Andric             start_idx_ptr = sc.comp_unit->FindLineEntry(
998480093f4SDimitry Andric                 start_idx_ptr, line_number, nullptr, exact, &line_entry);
9990b57cec5SDimitry Andric             if (start_idx_ptr == UINT32_MAX)
10000b57cec5SDimitry Andric               break;
10010b57cec5SDimitry Andric 
10020b57cec5SDimitry Andric             addr_t address =
10030b57cec5SDimitry Andric                 line_entry.range.GetBaseAddress().GetLoadAddress(target);
10040b57cec5SDimitry Andric             if (address != LLDB_INVALID_ADDRESS) {
10050b57cec5SDimitry Andric               if (fun_addr_range.ContainsLoadAddress(address, target))
10060b57cec5SDimitry Andric                 address_list.push_back(address);
10070b57cec5SDimitry Andric               else
10080b57cec5SDimitry Andric                 all_in_function = false;
10090b57cec5SDimitry Andric             }
10100b57cec5SDimitry Andric             start_idx_ptr++;
10110b57cec5SDimitry Andric           }
10120b57cec5SDimitry Andric         }
10130b57cec5SDimitry Andric 
10140b57cec5SDimitry Andric         for (lldb::addr_t address : m_options.m_until_addrs) {
10150b57cec5SDimitry Andric           if (fun_addr_range.ContainsLoadAddress(address, target))
10160b57cec5SDimitry Andric             address_list.push_back(address);
10170b57cec5SDimitry Andric           else
10180b57cec5SDimitry Andric             all_in_function = false;
10190b57cec5SDimitry Andric         }
10200b57cec5SDimitry Andric 
10210b57cec5SDimitry Andric         if (address_list.empty()) {
10220b57cec5SDimitry Andric           if (all_in_function)
10230b57cec5SDimitry Andric             result.AppendErrorWithFormat(
10240b57cec5SDimitry Andric                 "No line entries matching until target.\n");
10250b57cec5SDimitry Andric           else
10260b57cec5SDimitry Andric             result.AppendErrorWithFormat(
10270b57cec5SDimitry Andric                 "Until target outside of the current function.\n");
10280b57cec5SDimitry Andric 
10295f757f3fSDimitry Andric           return;
10300b57cec5SDimitry Andric         }
10310b57cec5SDimitry Andric 
10320b57cec5SDimitry Andric         new_plan_sp = thread->QueueThreadPlanForStepUntil(
10330b57cec5SDimitry Andric             abort_other_plans, &address_list.front(), address_list.size(),
10340b57cec5SDimitry Andric             m_options.m_stop_others, m_options.m_frame_idx, new_plan_status);
10350b57cec5SDimitry Andric         if (new_plan_sp) {
1036349cc55cSDimitry Andric           // User level plans should be controlling plans so they can be
1037349cc55cSDimitry Andric           // interrupted
10380b57cec5SDimitry Andric           // (e.g. by hitting a breakpoint) and other plans executed by the
10390b57cec5SDimitry Andric           // user (stepping around the breakpoint) and then a "continue" will
10400b57cec5SDimitry Andric           // resume the original plan.
1041349cc55cSDimitry Andric           new_plan_sp->SetIsControllingPlan(true);
10420b57cec5SDimitry Andric           new_plan_sp->SetOkayToDiscard(false);
10430b57cec5SDimitry Andric         } else {
10440b57cec5SDimitry Andric           result.SetError(new_plan_status);
10455f757f3fSDimitry Andric           return;
10460b57cec5SDimitry Andric         }
10470b57cec5SDimitry Andric       } else {
104881ad6265SDimitry Andric         result.AppendErrorWithFormat("Frame index %u of thread id %" PRIu64
104981ad6265SDimitry Andric                                      " has no debug information.\n",
105081ad6265SDimitry Andric                                      m_options.m_frame_idx, thread->GetID());
10515f757f3fSDimitry Andric         return;
10520b57cec5SDimitry Andric       }
10530b57cec5SDimitry Andric 
105481ad6265SDimitry Andric       if (!process->GetThreadList().SetSelectedThreadByID(thread->GetID())) {
105581ad6265SDimitry Andric         result.AppendErrorWithFormat(
105681ad6265SDimitry Andric             "Failed to set the selected thread to thread id %" PRIu64 ".\n",
105781ad6265SDimitry Andric             thread->GetID());
10585f757f3fSDimitry Andric         return;
105981ad6265SDimitry Andric       }
10600b57cec5SDimitry Andric 
10610b57cec5SDimitry Andric       StreamString stream;
10620b57cec5SDimitry Andric       Status error;
10630b57cec5SDimitry Andric       if (synchronous_execution)
10640b57cec5SDimitry Andric         error = process->ResumeSynchronous(&stream);
10650b57cec5SDimitry Andric       else
10660b57cec5SDimitry Andric         error = process->Resume();
10670b57cec5SDimitry Andric 
10680b57cec5SDimitry Andric       if (error.Success()) {
10690b57cec5SDimitry Andric         result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",
10700b57cec5SDimitry Andric                                        process->GetID());
10710b57cec5SDimitry Andric         if (synchronous_execution) {
10720b57cec5SDimitry Andric           // If any state changed events had anything to say, add that to the
10730b57cec5SDimitry Andric           // result
10740b57cec5SDimitry Andric           if (stream.GetSize() > 0)
10750b57cec5SDimitry Andric             result.AppendMessage(stream.GetString());
10760b57cec5SDimitry Andric 
10770b57cec5SDimitry Andric           result.SetDidChangeProcessState(true);
10780b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishNoResult);
10790b57cec5SDimitry Andric         } else {
10800b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessContinuingNoResult);
10810b57cec5SDimitry Andric         }
10820b57cec5SDimitry Andric       } else {
10830b57cec5SDimitry Andric         result.AppendErrorWithFormat("Failed to resume process: %s.\n",
10840b57cec5SDimitry Andric                                      error.AsCString());
10850b57cec5SDimitry Andric       }
10860b57cec5SDimitry Andric     }
10870b57cec5SDimitry Andric   }
10880b57cec5SDimitry Andric 
10890b57cec5SDimitry Andric   CommandOptions m_options;
10900b57cec5SDimitry Andric };
10910b57cec5SDimitry Andric 
10920b57cec5SDimitry Andric // CommandObjectThreadSelect
10930b57cec5SDimitry Andric 
10945f757f3fSDimitry Andric #define LLDB_OPTIONS_thread_select
10955f757f3fSDimitry Andric #include "CommandOptions.inc"
10965f757f3fSDimitry Andric 
10970b57cec5SDimitry Andric class CommandObjectThreadSelect : public CommandObjectParsed {
10980b57cec5SDimitry Andric public:
10995f757f3fSDimitry Andric   class OptionGroupThreadSelect : public OptionGroup {
11005f757f3fSDimitry Andric   public:
11015f757f3fSDimitry Andric     OptionGroupThreadSelect() { OptionParsingStarting(nullptr); }
11025f757f3fSDimitry Andric 
11035f757f3fSDimitry Andric     ~OptionGroupThreadSelect() override = default;
11045f757f3fSDimitry Andric 
11055f757f3fSDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
11065f757f3fSDimitry Andric       m_thread_id = LLDB_INVALID_THREAD_ID;
11075f757f3fSDimitry Andric     }
11085f757f3fSDimitry Andric 
11095f757f3fSDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
11105f757f3fSDimitry Andric                           ExecutionContext *execution_context) override {
11115f757f3fSDimitry Andric       const int short_option = g_thread_select_options[option_idx].short_option;
11125f757f3fSDimitry Andric       switch (short_option) {
11135f757f3fSDimitry Andric       case 't': {
11145f757f3fSDimitry Andric         if (option_arg.getAsInteger(0, m_thread_id)) {
11155f757f3fSDimitry Andric           m_thread_id = LLDB_INVALID_THREAD_ID;
11165f757f3fSDimitry Andric           return Status("Invalid thread ID: '%s'.", option_arg.str().c_str());
11175f757f3fSDimitry Andric         }
11185f757f3fSDimitry Andric         break;
11195f757f3fSDimitry Andric       }
11205f757f3fSDimitry Andric 
11215f757f3fSDimitry Andric       default:
11225f757f3fSDimitry Andric         llvm_unreachable("Unimplemented option");
11235f757f3fSDimitry Andric       }
11245f757f3fSDimitry Andric 
11255f757f3fSDimitry Andric       return {};
11265f757f3fSDimitry Andric     }
11275f757f3fSDimitry Andric 
11285f757f3fSDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
11295f757f3fSDimitry Andric       return llvm::ArrayRef(g_thread_select_options);
11305f757f3fSDimitry Andric     }
11315f757f3fSDimitry Andric 
11325f757f3fSDimitry Andric     lldb::tid_t m_thread_id;
11335f757f3fSDimitry Andric   };
11345f757f3fSDimitry Andric 
11350b57cec5SDimitry Andric   CommandObjectThreadSelect(CommandInterpreter &interpreter)
11360b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "thread select",
11375f757f3fSDimitry Andric                             "Change the currently selected thread.",
11385f757f3fSDimitry Andric                             "thread select <thread-index> (or -t <thread-id>)",
11390b57cec5SDimitry Andric                             eCommandRequiresProcess | eCommandTryTargetAPILock |
11400b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched |
11410b57cec5SDimitry Andric                                 eCommandProcessMustBePaused) {
11420b57cec5SDimitry Andric     CommandArgumentEntry arg;
11430b57cec5SDimitry Andric     CommandArgumentData thread_idx_arg;
11440b57cec5SDimitry Andric 
11450b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
11460b57cec5SDimitry Andric     thread_idx_arg.arg_type = eArgTypeThreadIndex;
11470b57cec5SDimitry Andric     thread_idx_arg.arg_repetition = eArgRepeatPlain;
11485f757f3fSDimitry Andric     thread_idx_arg.arg_opt_set_association = LLDB_OPT_SET_1;
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
11510b57cec5SDimitry Andric     // argument entry.
11520b57cec5SDimitry Andric     arg.push_back(thread_idx_arg);
11530b57cec5SDimitry Andric 
11540b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
11550b57cec5SDimitry Andric     m_arguments.push_back(arg);
11565f757f3fSDimitry Andric 
11575f757f3fSDimitry Andric     m_option_group.Append(&m_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
11585f757f3fSDimitry Andric     m_option_group.Finalize();
11590b57cec5SDimitry Andric   }
11600b57cec5SDimitry Andric 
11610b57cec5SDimitry Andric   ~CommandObjectThreadSelect() override = default;
11620b57cec5SDimitry Andric 
1163e8d8bef9SDimitry Andric   void
1164e8d8bef9SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
1165e8d8bef9SDimitry Andric                            OptionElementVector &opt_element_vector) override {
1166e8d8bef9SDimitry Andric     if (request.GetCursorIndex())
1167e8d8bef9SDimitry Andric       return;
1168e8d8bef9SDimitry Andric 
116906c3fb27SDimitry Andric     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
117006c3fb27SDimitry Andric         GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,
117106c3fb27SDimitry Andric         nullptr);
1172e8d8bef9SDimitry Andric   }
1173e8d8bef9SDimitry Andric 
11745f757f3fSDimitry Andric   Options *GetOptions() override { return &m_option_group; }
11755f757f3fSDimitry Andric 
11760b57cec5SDimitry Andric protected:
11775f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
11780b57cec5SDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
11790b57cec5SDimitry Andric     if (process == nullptr) {
11800b57cec5SDimitry Andric       result.AppendError("no process");
11815f757f3fSDimitry Andric       return;
11825f757f3fSDimitry Andric     } else if (m_options.m_thread_id == LLDB_INVALID_THREAD_ID &&
11835f757f3fSDimitry Andric                command.GetArgumentCount() != 1) {
11840b57cec5SDimitry Andric       result.AppendErrorWithFormat(
11855f757f3fSDimitry Andric           "'%s' takes exactly one thread index argument, or a thread ID "
11865f757f3fSDimitry Andric           "option:\nUsage: %s\n",
11870b57cec5SDimitry Andric           m_cmd_name.c_str(), m_cmd_syntax.c_str());
11885f757f3fSDimitry Andric       return;
11895f757f3fSDimitry Andric     } else if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID &&
11905f757f3fSDimitry Andric                command.GetArgumentCount() != 0) {
11915f757f3fSDimitry Andric       result.AppendErrorWithFormat("'%s' cannot take both a thread ID option "
11925f757f3fSDimitry Andric                                    "and a thread index argument:\nUsage: %s\n",
11935f757f3fSDimitry Andric                                    m_cmd_name.c_str(), m_cmd_syntax.c_str());
11945f757f3fSDimitry Andric       return;
11950b57cec5SDimitry Andric     }
11960b57cec5SDimitry Andric 
11975f757f3fSDimitry Andric     Thread *new_thread = nullptr;
11985f757f3fSDimitry Andric     if (command.GetArgumentCount() == 1) {
11995ffd83dbSDimitry Andric       uint32_t index_id;
12005ffd83dbSDimitry Andric       if (!llvm::to_integer(command.GetArgumentAtIndex(0), index_id)) {
12015ffd83dbSDimitry Andric         result.AppendErrorWithFormat("Invalid thread index '%s'",
12025ffd83dbSDimitry Andric                                      command.GetArgumentAtIndex(0));
12035f757f3fSDimitry Andric         return;
12045ffd83dbSDimitry Andric       }
12055f757f3fSDimitry Andric       new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get();
12060b57cec5SDimitry Andric       if (new_thread == nullptr) {
12075f757f3fSDimitry Andric         result.AppendErrorWithFormat("Invalid thread index #%s.\n",
12080b57cec5SDimitry Andric                                      command.GetArgumentAtIndex(0));
12095f757f3fSDimitry Andric         return;
12105f757f3fSDimitry Andric       }
12115f757f3fSDimitry Andric     } else {
12125f757f3fSDimitry Andric       new_thread =
12135f757f3fSDimitry Andric           process->GetThreadList().FindThreadByID(m_options.m_thread_id).get();
12145f757f3fSDimitry Andric       if (new_thread == nullptr) {
12155f757f3fSDimitry Andric         result.AppendErrorWithFormat("Invalid thread ID %" PRIu64 ".\n",
12165f757f3fSDimitry Andric                                      m_options.m_thread_id);
12175f757f3fSDimitry Andric         return;
12185f757f3fSDimitry Andric       }
12190b57cec5SDimitry Andric     }
12200b57cec5SDimitry Andric 
12210b57cec5SDimitry Andric     process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true);
12220b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
12230b57cec5SDimitry Andric   }
12245f757f3fSDimitry Andric 
12255f757f3fSDimitry Andric   OptionGroupThreadSelect m_options;
12265f757f3fSDimitry Andric   OptionGroupOptions m_option_group;
12270b57cec5SDimitry Andric };
12280b57cec5SDimitry Andric 
12290b57cec5SDimitry Andric // CommandObjectThreadList
12300b57cec5SDimitry Andric 
12310b57cec5SDimitry Andric class CommandObjectThreadList : public CommandObjectParsed {
12320b57cec5SDimitry Andric public:
12330b57cec5SDimitry Andric   CommandObjectThreadList(CommandInterpreter &interpreter)
12340b57cec5SDimitry Andric       : CommandObjectParsed(
12350b57cec5SDimitry Andric             interpreter, "thread list",
12360b57cec5SDimitry Andric             "Show a summary of each thread in the current target process.  "
12370b57cec5SDimitry Andric             "Use 'settings set thread-format' to customize the individual "
12380b57cec5SDimitry Andric             "thread listings.",
12390b57cec5SDimitry Andric             "thread list",
12400b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
12410b57cec5SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
12420b57cec5SDimitry Andric 
12430b57cec5SDimitry Andric   ~CommandObjectThreadList() override = default;
12440b57cec5SDimitry Andric 
12450b57cec5SDimitry Andric protected:
12465f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
12470b57cec5SDimitry Andric     Stream &strm = result.GetOutputStream();
12480b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
12490b57cec5SDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
12500b57cec5SDimitry Andric     const bool only_threads_with_stop_reason = false;
12510b57cec5SDimitry Andric     const uint32_t start_frame = 0;
12520b57cec5SDimitry Andric     const uint32_t num_frames = 0;
12530b57cec5SDimitry Andric     const uint32_t num_frames_with_source = 0;
12540b57cec5SDimitry Andric     process->GetStatus(strm);
12550b57cec5SDimitry Andric     process->GetThreadStatus(strm, only_threads_with_stop_reason, start_frame,
12560b57cec5SDimitry Andric                              num_frames, num_frames_with_source, false);
12570b57cec5SDimitry Andric   }
12580b57cec5SDimitry Andric };
12590b57cec5SDimitry Andric 
12600b57cec5SDimitry Andric // CommandObjectThreadInfo
12610b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_info
12620b57cec5SDimitry Andric #include "CommandOptions.inc"
12630b57cec5SDimitry Andric 
12640b57cec5SDimitry Andric class CommandObjectThreadInfo : public CommandObjectIterateOverThreads {
12650b57cec5SDimitry Andric public:
12660b57cec5SDimitry Andric   class CommandOptions : public Options {
12670b57cec5SDimitry Andric   public:
126804eeddc0SDimitry Andric     CommandOptions() { OptionParsingStarting(nullptr); }
12690b57cec5SDimitry Andric 
12700b57cec5SDimitry Andric     ~CommandOptions() override = default;
12710b57cec5SDimitry Andric 
12720b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
12730b57cec5SDimitry Andric       m_json_thread = false;
12740b57cec5SDimitry Andric       m_json_stopinfo = false;
12750b57cec5SDimitry Andric     }
12760b57cec5SDimitry Andric 
12770b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
12780b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
12790b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
12800b57cec5SDimitry Andric       Status error;
12810b57cec5SDimitry Andric 
12820b57cec5SDimitry Andric       switch (short_option) {
12830b57cec5SDimitry Andric       case 'j':
12840b57cec5SDimitry Andric         m_json_thread = true;
12850b57cec5SDimitry Andric         break;
12860b57cec5SDimitry Andric 
12870b57cec5SDimitry Andric       case 's':
12880b57cec5SDimitry Andric         m_json_stopinfo = true;
12890b57cec5SDimitry Andric         break;
12900b57cec5SDimitry Andric 
12910b57cec5SDimitry Andric       default:
12929dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
12930b57cec5SDimitry Andric       }
12940b57cec5SDimitry Andric       return error;
12950b57cec5SDimitry Andric     }
12960b57cec5SDimitry Andric 
12970b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1298bdd1243dSDimitry Andric       return llvm::ArrayRef(g_thread_info_options);
12990b57cec5SDimitry Andric     }
13000b57cec5SDimitry Andric 
13010b57cec5SDimitry Andric     bool m_json_thread;
13020b57cec5SDimitry Andric     bool m_json_stopinfo;
13030b57cec5SDimitry Andric   };
13040b57cec5SDimitry Andric 
13050b57cec5SDimitry Andric   CommandObjectThreadInfo(CommandInterpreter &interpreter)
13060b57cec5SDimitry Andric       : CommandObjectIterateOverThreads(
1307480093f4SDimitry Andric             interpreter, "thread info",
1308480093f4SDimitry Andric             "Show an extended summary of one or "
13090b57cec5SDimitry Andric             "more threads.  Defaults to the "
13100b57cec5SDimitry Andric             "current thread.",
13110b57cec5SDimitry Andric             "thread info",
13120b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
131304eeddc0SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
13140b57cec5SDimitry Andric     m_add_return = false;
13150b57cec5SDimitry Andric   }
13160b57cec5SDimitry Andric 
13170b57cec5SDimitry Andric   ~CommandObjectThreadInfo() override = default;
13180b57cec5SDimitry Andric 
1319e8d8bef9SDimitry Andric   void
1320e8d8bef9SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
1321e8d8bef9SDimitry Andric                            OptionElementVector &opt_element_vector) override {
132206c3fb27SDimitry Andric     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
132306c3fb27SDimitry Andric         GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,
132406c3fb27SDimitry Andric         nullptr);
1325e8d8bef9SDimitry Andric   }
1326e8d8bef9SDimitry Andric 
13270b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
13280b57cec5SDimitry Andric 
13290b57cec5SDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
13300b57cec5SDimitry Andric     ThreadSP thread_sp =
13310b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
13320b57cec5SDimitry Andric     if (!thread_sp) {
13330b57cec5SDimitry Andric       result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
13340b57cec5SDimitry Andric                                    tid);
13350b57cec5SDimitry Andric       return false;
13360b57cec5SDimitry Andric     }
13370b57cec5SDimitry Andric 
13380b57cec5SDimitry Andric     Thread *thread = thread_sp.get();
13390b57cec5SDimitry Andric 
13400b57cec5SDimitry Andric     Stream &strm = result.GetOutputStream();
13410b57cec5SDimitry Andric     if (!thread->GetDescription(strm, eDescriptionLevelFull,
13420b57cec5SDimitry Andric                                 m_options.m_json_thread,
13430b57cec5SDimitry Andric                                 m_options.m_json_stopinfo)) {
13440b57cec5SDimitry Andric       result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n",
13450b57cec5SDimitry Andric                                    thread->GetIndexID());
13460b57cec5SDimitry Andric       return false;
13470b57cec5SDimitry Andric     }
13480b57cec5SDimitry Andric     return true;
13490b57cec5SDimitry Andric   }
13500b57cec5SDimitry Andric 
13510b57cec5SDimitry Andric   CommandOptions m_options;
13520b57cec5SDimitry Andric };
13530b57cec5SDimitry Andric 
13540b57cec5SDimitry Andric // CommandObjectThreadException
13550b57cec5SDimitry Andric 
13560b57cec5SDimitry Andric class CommandObjectThreadException : public CommandObjectIterateOverThreads {
13570b57cec5SDimitry Andric public:
13580b57cec5SDimitry Andric   CommandObjectThreadException(CommandInterpreter &interpreter)
13590b57cec5SDimitry Andric       : CommandObjectIterateOverThreads(
13600b57cec5SDimitry Andric             interpreter, "thread exception",
13610b57cec5SDimitry Andric             "Display the current exception object for a thread. Defaults to "
13620b57cec5SDimitry Andric             "the current thread.",
13630b57cec5SDimitry Andric             "thread exception",
13640b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
13650b57cec5SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
13660b57cec5SDimitry Andric 
13670b57cec5SDimitry Andric   ~CommandObjectThreadException() override = default;
13680b57cec5SDimitry Andric 
1369e8d8bef9SDimitry Andric   void
1370e8d8bef9SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
1371e8d8bef9SDimitry Andric                            OptionElementVector &opt_element_vector) override {
137206c3fb27SDimitry Andric     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
137306c3fb27SDimitry Andric         GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,
137406c3fb27SDimitry Andric         nullptr);
1375e8d8bef9SDimitry Andric   }
1376e8d8bef9SDimitry Andric 
13770b57cec5SDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
13780b57cec5SDimitry Andric     ThreadSP thread_sp =
13790b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
13800b57cec5SDimitry Andric     if (!thread_sp) {
13810b57cec5SDimitry Andric       result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
13820b57cec5SDimitry Andric                                    tid);
13830b57cec5SDimitry Andric       return false;
13840b57cec5SDimitry Andric     }
13850b57cec5SDimitry Andric 
13860b57cec5SDimitry Andric     Stream &strm = result.GetOutputStream();
13870b57cec5SDimitry Andric     ValueObjectSP exception_object_sp = thread_sp->GetCurrentException();
13880b57cec5SDimitry Andric     if (exception_object_sp) {
1389*0fca6ea1SDimitry Andric       if (llvm::Error error = exception_object_sp->Dump(strm)) {
1390*0fca6ea1SDimitry Andric         result.AppendError(toString(std::move(error)));
1391*0fca6ea1SDimitry Andric         return false;
1392*0fca6ea1SDimitry Andric       }
13930b57cec5SDimitry Andric     }
13940b57cec5SDimitry Andric 
13950b57cec5SDimitry Andric     ThreadSP exception_thread_sp = thread_sp->GetCurrentExceptionBacktrace();
13960b57cec5SDimitry Andric     if (exception_thread_sp && exception_thread_sp->IsValid()) {
13970b57cec5SDimitry Andric       const uint32_t num_frames_with_source = 0;
13980b57cec5SDimitry Andric       const bool stop_format = false;
13990b57cec5SDimitry Andric       exception_thread_sp->GetStatus(strm, 0, UINT32_MAX,
14000b57cec5SDimitry Andric                                      num_frames_with_source, stop_format);
14010b57cec5SDimitry Andric     }
14020b57cec5SDimitry Andric 
14030b57cec5SDimitry Andric     return true;
14040b57cec5SDimitry Andric   }
14050b57cec5SDimitry Andric };
14060b57cec5SDimitry Andric 
1407d56accc7SDimitry Andric class CommandObjectThreadSiginfo : public CommandObjectIterateOverThreads {
1408d56accc7SDimitry Andric public:
1409d56accc7SDimitry Andric   CommandObjectThreadSiginfo(CommandInterpreter &interpreter)
1410d56accc7SDimitry Andric       : CommandObjectIterateOverThreads(
1411d56accc7SDimitry Andric             interpreter, "thread siginfo",
1412d56accc7SDimitry Andric             "Display the current siginfo object for a thread. Defaults to "
1413d56accc7SDimitry Andric             "the current thread.",
1414d56accc7SDimitry Andric             "thread siginfo",
1415d56accc7SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
1416d56accc7SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
1417d56accc7SDimitry Andric 
1418d56accc7SDimitry Andric   ~CommandObjectThreadSiginfo() override = default;
1419d56accc7SDimitry Andric 
1420d56accc7SDimitry Andric   void
1421d56accc7SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
1422d56accc7SDimitry Andric                            OptionElementVector &opt_element_vector) override {
142306c3fb27SDimitry Andric     lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
142406c3fb27SDimitry Andric         GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,
142506c3fb27SDimitry Andric         nullptr);
1426d56accc7SDimitry Andric   }
1427d56accc7SDimitry Andric 
1428d56accc7SDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
1429d56accc7SDimitry Andric     ThreadSP thread_sp =
1430d56accc7SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
1431d56accc7SDimitry Andric     if (!thread_sp) {
1432d56accc7SDimitry Andric       result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
1433d56accc7SDimitry Andric                                    tid);
1434d56accc7SDimitry Andric       return false;
1435d56accc7SDimitry Andric     }
1436d56accc7SDimitry Andric 
1437d56accc7SDimitry Andric     Stream &strm = result.GetOutputStream();
1438d56accc7SDimitry Andric     if (!thread_sp->GetDescription(strm, eDescriptionLevelFull, false, false)) {
1439d56accc7SDimitry Andric       result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n",
1440d56accc7SDimitry Andric                                    thread_sp->GetIndexID());
1441d56accc7SDimitry Andric       return false;
1442d56accc7SDimitry Andric     }
1443d56accc7SDimitry Andric     ValueObjectSP exception_object_sp = thread_sp->GetSiginfoValue();
1444*0fca6ea1SDimitry Andric     if (exception_object_sp) {
1445*0fca6ea1SDimitry Andric       if (llvm::Error error = exception_object_sp->Dump(strm)) {
1446*0fca6ea1SDimitry Andric         result.AppendError(toString(std::move(error)));
1447*0fca6ea1SDimitry Andric         return false;
1448*0fca6ea1SDimitry Andric       }
1449*0fca6ea1SDimitry Andric     } else
1450d56accc7SDimitry Andric       strm.Printf("(no siginfo)\n");
1451d56accc7SDimitry Andric     strm.PutChar('\n');
1452d56accc7SDimitry Andric 
1453d56accc7SDimitry Andric     return true;
1454d56accc7SDimitry Andric   }
1455d56accc7SDimitry Andric };
1456d56accc7SDimitry Andric 
14570b57cec5SDimitry Andric // CommandObjectThreadReturn
14580b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_return
14590b57cec5SDimitry Andric #include "CommandOptions.inc"
14600b57cec5SDimitry Andric 
14610b57cec5SDimitry Andric class CommandObjectThreadReturn : public CommandObjectRaw {
14620b57cec5SDimitry Andric public:
14630b57cec5SDimitry Andric   class CommandOptions : public Options {
14640b57cec5SDimitry Andric   public:
146504eeddc0SDimitry Andric     CommandOptions() {
14660b57cec5SDimitry Andric       // Keep default values of all options in one place: OptionParsingStarting
14670b57cec5SDimitry Andric       // ()
14680b57cec5SDimitry Andric       OptionParsingStarting(nullptr);
14690b57cec5SDimitry Andric     }
14700b57cec5SDimitry Andric 
14710b57cec5SDimitry Andric     ~CommandOptions() override = default;
14720b57cec5SDimitry Andric 
14730b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
14740b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
14750b57cec5SDimitry Andric       Status error;
14760b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
14770b57cec5SDimitry Andric 
14780b57cec5SDimitry Andric       switch (short_option) {
14790b57cec5SDimitry Andric       case 'x': {
14800b57cec5SDimitry Andric         bool success;
14810b57cec5SDimitry Andric         bool tmp_value =
14820b57cec5SDimitry Andric             OptionArgParser::ToBoolean(option_arg, false, &success);
14830b57cec5SDimitry Andric         if (success)
14840b57cec5SDimitry Andric           m_from_expression = tmp_value;
14850b57cec5SDimitry Andric         else {
14860b57cec5SDimitry Andric           error.SetErrorStringWithFormat(
14870b57cec5SDimitry Andric               "invalid boolean value '%s' for 'x' option",
14880b57cec5SDimitry Andric               option_arg.str().c_str());
14890b57cec5SDimitry Andric         }
14900b57cec5SDimitry Andric       } break;
14910b57cec5SDimitry Andric       default:
14929dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
14930b57cec5SDimitry Andric       }
14940b57cec5SDimitry Andric       return error;
14950b57cec5SDimitry Andric     }
14960b57cec5SDimitry Andric 
14970b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
14980b57cec5SDimitry Andric       m_from_expression = false;
14990b57cec5SDimitry Andric     }
15000b57cec5SDimitry Andric 
15010b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1502bdd1243dSDimitry Andric       return llvm::ArrayRef(g_thread_return_options);
15030b57cec5SDimitry Andric     }
15040b57cec5SDimitry Andric 
1505fe6060f1SDimitry Andric     bool m_from_expression = false;
15060b57cec5SDimitry Andric 
15070b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
15080b57cec5SDimitry Andric   };
15090b57cec5SDimitry Andric 
15100b57cec5SDimitry Andric   CommandObjectThreadReturn(CommandInterpreter &interpreter)
15110b57cec5SDimitry Andric       : CommandObjectRaw(interpreter, "thread return",
15120b57cec5SDimitry Andric                          "Prematurely return from a stack frame, "
15130b57cec5SDimitry Andric                          "short-circuiting execution of newer frames "
15140b57cec5SDimitry Andric                          "and optionally yielding a specified value.  Defaults "
15150b57cec5SDimitry Andric                          "to the exiting the current stack "
15160b57cec5SDimitry Andric                          "frame.",
15170b57cec5SDimitry Andric                          "thread return",
15180b57cec5SDimitry Andric                          eCommandRequiresFrame | eCommandTryTargetAPILock |
15190b57cec5SDimitry Andric                              eCommandProcessMustBeLaunched |
152004eeddc0SDimitry Andric                              eCommandProcessMustBePaused) {
1521*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeExpression, eArgRepeatOptional);
15220b57cec5SDimitry Andric   }
15230b57cec5SDimitry Andric 
15240b57cec5SDimitry Andric   ~CommandObjectThreadReturn() override = default;
15250b57cec5SDimitry Andric 
15260b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
15270b57cec5SDimitry Andric 
15280b57cec5SDimitry Andric protected:
15295f757f3fSDimitry Andric   void DoExecute(llvm::StringRef command,
15300b57cec5SDimitry Andric                  CommandReturnObject &result) override {
15310b57cec5SDimitry Andric     // I am going to handle this by hand, because I don't want you to have to
15320b57cec5SDimitry Andric     // say:
15330b57cec5SDimitry Andric     // "thread return -- -5".
15345f757f3fSDimitry Andric     if (command.starts_with("-x")) {
15350b57cec5SDimitry Andric       if (command.size() != 2U)
15360b57cec5SDimitry Andric         result.AppendWarning("Return values ignored when returning from user "
15370b57cec5SDimitry Andric                              "called expressions");
15380b57cec5SDimitry Andric 
15390b57cec5SDimitry Andric       Thread *thread = m_exe_ctx.GetThreadPtr();
15400b57cec5SDimitry Andric       Status error;
15410b57cec5SDimitry Andric       error = thread->UnwindInnermostExpression();
15420b57cec5SDimitry Andric       if (!error.Success()) {
15430b57cec5SDimitry Andric         result.AppendErrorWithFormat("Unwinding expression failed - %s.",
15440b57cec5SDimitry Andric                                      error.AsCString());
15450b57cec5SDimitry Andric       } else {
15460b57cec5SDimitry Andric         bool success =
15470b57cec5SDimitry Andric             thread->SetSelectedFrameByIndexNoisily(0, result.GetOutputStream());
15480b57cec5SDimitry Andric         if (success) {
154906c3fb27SDimitry Andric           m_exe_ctx.SetFrameSP(
155006c3fb27SDimitry Andric               thread->GetSelectedFrame(DoNoSelectMostRelevantFrame));
15510b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
15520b57cec5SDimitry Andric         } else {
15530b57cec5SDimitry Andric           result.AppendErrorWithFormat(
15540b57cec5SDimitry Andric               "Could not select 0th frame after unwinding expression.");
15550b57cec5SDimitry Andric         }
15560b57cec5SDimitry Andric       }
15575f757f3fSDimitry Andric       return;
15580b57cec5SDimitry Andric     }
15590b57cec5SDimitry Andric 
15600b57cec5SDimitry Andric     ValueObjectSP return_valobj_sp;
15610b57cec5SDimitry Andric 
15620b57cec5SDimitry Andric     StackFrameSP frame_sp = m_exe_ctx.GetFrameSP();
15630b57cec5SDimitry Andric     uint32_t frame_idx = frame_sp->GetFrameIndex();
15640b57cec5SDimitry Andric 
15650b57cec5SDimitry Andric     if (frame_sp->IsInlined()) {
15660b57cec5SDimitry Andric       result.AppendError("Don't know how to return from inlined frames.");
15675f757f3fSDimitry Andric       return;
15680b57cec5SDimitry Andric     }
15690b57cec5SDimitry Andric 
15700b57cec5SDimitry Andric     if (!command.empty()) {
15710b57cec5SDimitry Andric       Target *target = m_exe_ctx.GetTargetPtr();
15720b57cec5SDimitry Andric       EvaluateExpressionOptions options;
15730b57cec5SDimitry Andric 
15740b57cec5SDimitry Andric       options.SetUnwindOnError(true);
15750b57cec5SDimitry Andric       options.SetUseDynamic(eNoDynamicValues);
15760b57cec5SDimitry Andric 
15770b57cec5SDimitry Andric       ExpressionResults exe_results = eExpressionSetupError;
15780b57cec5SDimitry Andric       exe_results = target->EvaluateExpression(command, frame_sp.get(),
15790b57cec5SDimitry Andric                                                return_valobj_sp, options);
15800b57cec5SDimitry Andric       if (exe_results != eExpressionCompleted) {
15810b57cec5SDimitry Andric         if (return_valobj_sp)
15820b57cec5SDimitry Andric           result.AppendErrorWithFormat(
15830b57cec5SDimitry Andric               "Error evaluating result expression: %s",
15840b57cec5SDimitry Andric               return_valobj_sp->GetError().AsCString());
15850b57cec5SDimitry Andric         else
15860b57cec5SDimitry Andric           result.AppendErrorWithFormat(
15870b57cec5SDimitry Andric               "Unknown error evaluating result expression.");
15885f757f3fSDimitry Andric         return;
15890b57cec5SDimitry Andric       }
15900b57cec5SDimitry Andric     }
15910b57cec5SDimitry Andric 
15920b57cec5SDimitry Andric     Status error;
15930b57cec5SDimitry Andric     ThreadSP thread_sp = m_exe_ctx.GetThreadSP();
15940b57cec5SDimitry Andric     const bool broadcast = true;
15950b57cec5SDimitry Andric     error = thread_sp->ReturnFromFrame(frame_sp, return_valobj_sp, broadcast);
15960b57cec5SDimitry Andric     if (!error.Success()) {
15970b57cec5SDimitry Andric       result.AppendErrorWithFormat(
15980b57cec5SDimitry Andric           "Error returning from frame %d of thread %d: %s.", frame_idx,
15990b57cec5SDimitry Andric           thread_sp->GetIndexID(), error.AsCString());
16005f757f3fSDimitry Andric       return;
16010b57cec5SDimitry Andric     }
16020b57cec5SDimitry Andric 
16030b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
16040b57cec5SDimitry Andric   }
16050b57cec5SDimitry Andric 
16060b57cec5SDimitry Andric   CommandOptions m_options;
16070b57cec5SDimitry Andric };
16080b57cec5SDimitry Andric 
16090b57cec5SDimitry Andric // CommandObjectThreadJump
16100b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_jump
16110b57cec5SDimitry Andric #include "CommandOptions.inc"
16120b57cec5SDimitry Andric 
16130b57cec5SDimitry Andric class CommandObjectThreadJump : public CommandObjectParsed {
16140b57cec5SDimitry Andric public:
16150b57cec5SDimitry Andric   class CommandOptions : public Options {
16160b57cec5SDimitry Andric   public:
161704eeddc0SDimitry Andric     CommandOptions() { OptionParsingStarting(nullptr); }
16180b57cec5SDimitry Andric 
16190b57cec5SDimitry Andric     ~CommandOptions() override = default;
16200b57cec5SDimitry Andric 
16210b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
16220b57cec5SDimitry Andric       m_filenames.Clear();
16230b57cec5SDimitry Andric       m_line_num = 0;
16240b57cec5SDimitry Andric       m_line_offset = 0;
16250b57cec5SDimitry Andric       m_load_addr = LLDB_INVALID_ADDRESS;
16260b57cec5SDimitry Andric       m_force = false;
16270b57cec5SDimitry Andric     }
16280b57cec5SDimitry Andric 
16290b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
16300b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
16310b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
16320b57cec5SDimitry Andric       Status error;
16330b57cec5SDimitry Andric 
16340b57cec5SDimitry Andric       switch (short_option) {
16350b57cec5SDimitry Andric       case 'f':
16360b57cec5SDimitry Andric         m_filenames.AppendIfUnique(FileSpec(option_arg));
16370b57cec5SDimitry Andric         if (m_filenames.GetSize() > 1)
16380b57cec5SDimitry Andric           return Status("only one source file expected.");
16390b57cec5SDimitry Andric         break;
16400b57cec5SDimitry Andric       case 'l':
16410b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_line_num))
16420b57cec5SDimitry Andric           return Status("invalid line number: '%s'.", option_arg.str().c_str());
16430b57cec5SDimitry Andric         break;
16440b57cec5SDimitry Andric       case 'b':
16450b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_line_offset))
16460b57cec5SDimitry Andric           return Status("invalid line offset: '%s'.", option_arg.str().c_str());
16470b57cec5SDimitry Andric         break;
16480b57cec5SDimitry Andric       case 'a':
16490b57cec5SDimitry Andric         m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg,
16500b57cec5SDimitry Andric                                                  LLDB_INVALID_ADDRESS, &error);
16510b57cec5SDimitry Andric         break;
16520b57cec5SDimitry Andric       case 'r':
16530b57cec5SDimitry Andric         m_force = true;
16540b57cec5SDimitry Andric         break;
16550b57cec5SDimitry Andric       default:
16569dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
16570b57cec5SDimitry Andric       }
16580b57cec5SDimitry Andric       return error;
16590b57cec5SDimitry Andric     }
16600b57cec5SDimitry Andric 
16610b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1662bdd1243dSDimitry Andric       return llvm::ArrayRef(g_thread_jump_options);
16630b57cec5SDimitry Andric     }
16640b57cec5SDimitry Andric 
16650b57cec5SDimitry Andric     FileSpecList m_filenames;
16660b57cec5SDimitry Andric     uint32_t m_line_num;
16670b57cec5SDimitry Andric     int32_t m_line_offset;
16680b57cec5SDimitry Andric     lldb::addr_t m_load_addr;
16690b57cec5SDimitry Andric     bool m_force;
16700b57cec5SDimitry Andric   };
16710b57cec5SDimitry Andric 
16720b57cec5SDimitry Andric   CommandObjectThreadJump(CommandInterpreter &interpreter)
16730b57cec5SDimitry Andric       : CommandObjectParsed(
16740b57cec5SDimitry Andric             interpreter, "thread jump",
16750b57cec5SDimitry Andric             "Sets the program counter to a new address.", "thread jump",
16760b57cec5SDimitry Andric             eCommandRequiresFrame | eCommandTryTargetAPILock |
167704eeddc0SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
16780b57cec5SDimitry Andric 
16790b57cec5SDimitry Andric   ~CommandObjectThreadJump() override = default;
16800b57cec5SDimitry Andric 
16810b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
16820b57cec5SDimitry Andric 
16830b57cec5SDimitry Andric protected:
16845f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
16850b57cec5SDimitry Andric     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
16860b57cec5SDimitry Andric     StackFrame *frame = m_exe_ctx.GetFramePtr();
16870b57cec5SDimitry Andric     Thread *thread = m_exe_ctx.GetThreadPtr();
16880b57cec5SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
16890b57cec5SDimitry Andric     const SymbolContext &sym_ctx =
16900b57cec5SDimitry Andric         frame->GetSymbolContext(eSymbolContextLineEntry);
16910b57cec5SDimitry Andric 
16920b57cec5SDimitry Andric     if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) {
16930b57cec5SDimitry Andric       // Use this address directly.
16940b57cec5SDimitry Andric       Address dest = Address(m_options.m_load_addr);
16950b57cec5SDimitry Andric 
16960b57cec5SDimitry Andric       lldb::addr_t callAddr = dest.GetCallableLoadAddress(target);
16970b57cec5SDimitry Andric       if (callAddr == LLDB_INVALID_ADDRESS) {
16980b57cec5SDimitry Andric         result.AppendErrorWithFormat("Invalid destination address.");
16995f757f3fSDimitry Andric         return;
17000b57cec5SDimitry Andric       }
17010b57cec5SDimitry Andric 
17020b57cec5SDimitry Andric       if (!reg_ctx->SetPC(callAddr)) {
17030b57cec5SDimitry Andric         result.AppendErrorWithFormat("Error changing PC value for thread %d.",
17040b57cec5SDimitry Andric                                      thread->GetIndexID());
17055f757f3fSDimitry Andric         return;
17060b57cec5SDimitry Andric       }
17070b57cec5SDimitry Andric     } else {
17080b57cec5SDimitry Andric       // Pick either the absolute line, or work out a relative one.
17090b57cec5SDimitry Andric       int32_t line = (int32_t)m_options.m_line_num;
17100b57cec5SDimitry Andric       if (line == 0)
17110b57cec5SDimitry Andric         line = sym_ctx.line_entry.line + m_options.m_line_offset;
17120b57cec5SDimitry Andric 
17130b57cec5SDimitry Andric       // Try the current file, but override if asked.
1714*0fca6ea1SDimitry Andric       FileSpec file = sym_ctx.line_entry.GetFile();
17150b57cec5SDimitry Andric       if (m_options.m_filenames.GetSize() == 1)
17160b57cec5SDimitry Andric         file = m_options.m_filenames.GetFileSpecAtIndex(0);
17170b57cec5SDimitry Andric 
17180b57cec5SDimitry Andric       if (!file) {
17190b57cec5SDimitry Andric         result.AppendErrorWithFormat(
17200b57cec5SDimitry Andric             "No source file available for the current location.");
17215f757f3fSDimitry Andric         return;
17220b57cec5SDimitry Andric       }
17230b57cec5SDimitry Andric 
17240b57cec5SDimitry Andric       std::string warnings;
17250b57cec5SDimitry Andric       Status err = thread->JumpToLine(file, line, m_options.m_force, &warnings);
17260b57cec5SDimitry Andric 
17270b57cec5SDimitry Andric       if (err.Fail()) {
17280b57cec5SDimitry Andric         result.SetError(err);
17295f757f3fSDimitry Andric         return;
17300b57cec5SDimitry Andric       }
17310b57cec5SDimitry Andric 
17320b57cec5SDimitry Andric       if (!warnings.empty())
17330b57cec5SDimitry Andric         result.AppendWarning(warnings.c_str());
17340b57cec5SDimitry Andric     }
17350b57cec5SDimitry Andric 
17360b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
17370b57cec5SDimitry Andric   }
17380b57cec5SDimitry Andric 
17390b57cec5SDimitry Andric   CommandOptions m_options;
17400b57cec5SDimitry Andric };
17410b57cec5SDimitry Andric 
17420b57cec5SDimitry Andric // Next are the subcommands of CommandObjectMultiwordThreadPlan
17430b57cec5SDimitry Andric 
17440b57cec5SDimitry Andric // CommandObjectThreadPlanList
17450b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_plan_list
17460b57cec5SDimitry Andric #include "CommandOptions.inc"
17470b57cec5SDimitry Andric 
17480b57cec5SDimitry Andric class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads {
17490b57cec5SDimitry Andric public:
17500b57cec5SDimitry Andric   class CommandOptions : public Options {
17510b57cec5SDimitry Andric   public:
175204eeddc0SDimitry Andric     CommandOptions() {
17530b57cec5SDimitry Andric       // Keep default values of all options in one place: OptionParsingStarting
17540b57cec5SDimitry Andric       // ()
17550b57cec5SDimitry Andric       OptionParsingStarting(nullptr);
17560b57cec5SDimitry Andric     }
17570b57cec5SDimitry Andric 
17580b57cec5SDimitry Andric     ~CommandOptions() override = default;
17590b57cec5SDimitry Andric 
17600b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
17610b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
17620b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
17630b57cec5SDimitry Andric 
17640b57cec5SDimitry Andric       switch (short_option) {
17650b57cec5SDimitry Andric       case 'i':
17660b57cec5SDimitry Andric         m_internal = true;
17670b57cec5SDimitry Andric         break;
17685ffd83dbSDimitry Andric       case 't':
17695ffd83dbSDimitry Andric         lldb::tid_t tid;
17705ffd83dbSDimitry Andric         if (option_arg.getAsInteger(0, tid))
17715ffd83dbSDimitry Andric           return Status("invalid tid: '%s'.", option_arg.str().c_str());
17725ffd83dbSDimitry Andric         m_tids.push_back(tid);
17735ffd83dbSDimitry Andric         break;
17745ffd83dbSDimitry Andric       case 'u':
17755ffd83dbSDimitry Andric         m_unreported = false;
17765ffd83dbSDimitry Andric         break;
17770b57cec5SDimitry Andric       case 'v':
17780b57cec5SDimitry Andric         m_verbose = true;
17790b57cec5SDimitry Andric         break;
17800b57cec5SDimitry Andric       default:
17819dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
17820b57cec5SDimitry Andric       }
17835ffd83dbSDimitry Andric       return {};
17840b57cec5SDimitry Andric     }
17850b57cec5SDimitry Andric 
17860b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
17870b57cec5SDimitry Andric       m_verbose = false;
17880b57cec5SDimitry Andric       m_internal = false;
17895ffd83dbSDimitry Andric       m_unreported = true; // The variable is "skip unreported" and we want to
17905ffd83dbSDimitry Andric                            // skip unreported by default.
17915ffd83dbSDimitry Andric       m_tids.clear();
17920b57cec5SDimitry Andric     }
17930b57cec5SDimitry Andric 
17940b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1795bdd1243dSDimitry Andric       return llvm::ArrayRef(g_thread_plan_list_options);
17960b57cec5SDimitry Andric     }
17970b57cec5SDimitry Andric 
17980b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
17990b57cec5SDimitry Andric     bool m_verbose;
18000b57cec5SDimitry Andric     bool m_internal;
18015ffd83dbSDimitry Andric     bool m_unreported;
18025ffd83dbSDimitry Andric     std::vector<lldb::tid_t> m_tids;
18030b57cec5SDimitry Andric   };
18040b57cec5SDimitry Andric 
18050b57cec5SDimitry Andric   CommandObjectThreadPlanList(CommandInterpreter &interpreter)
18060b57cec5SDimitry Andric       : CommandObjectIterateOverThreads(
18070b57cec5SDimitry Andric             interpreter, "thread plan list",
18080b57cec5SDimitry Andric             "Show thread plans for one or more threads.  If no threads are "
18090b57cec5SDimitry Andric             "specified, show the "
18100b57cec5SDimitry Andric             "current thread.  Use the thread-index \"all\" to see all threads.",
18110b57cec5SDimitry Andric             nullptr,
18120b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandRequiresThread |
18130b57cec5SDimitry Andric                 eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
181404eeddc0SDimitry Andric                 eCommandProcessMustBePaused) {}
18150b57cec5SDimitry Andric 
18160b57cec5SDimitry Andric   ~CommandObjectThreadPlanList() override = default;
18170b57cec5SDimitry Andric 
18180b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
18190b57cec5SDimitry Andric 
18205f757f3fSDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
18215ffd83dbSDimitry Andric     // If we are reporting all threads, dispatch to the Process to do that:
18225ffd83dbSDimitry Andric     if (command.GetArgumentCount() == 0 && m_options.m_tids.empty()) {
18235ffd83dbSDimitry Andric       Stream &strm = result.GetOutputStream();
18245ffd83dbSDimitry Andric       DescriptionLevel desc_level = m_options.m_verbose
18255ffd83dbSDimitry Andric                                         ? eDescriptionLevelVerbose
18265ffd83dbSDimitry Andric                                         : eDescriptionLevelFull;
18275ffd83dbSDimitry Andric       m_exe_ctx.GetProcessPtr()->DumpThreadPlans(
18285ffd83dbSDimitry Andric           strm, desc_level, m_options.m_internal, true, m_options.m_unreported);
18295ffd83dbSDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
18305f757f3fSDimitry Andric       return;
18315ffd83dbSDimitry Andric     } else {
18325ffd83dbSDimitry Andric       // Do any TID's that the user may have specified as TID, then do any
18335ffd83dbSDimitry Andric       // Thread Indexes...
18345ffd83dbSDimitry Andric       if (!m_options.m_tids.empty()) {
18355ffd83dbSDimitry Andric         Process *process = m_exe_ctx.GetProcessPtr();
18365ffd83dbSDimitry Andric         StreamString tmp_strm;
18375ffd83dbSDimitry Andric         for (lldb::tid_t tid : m_options.m_tids) {
18385ffd83dbSDimitry Andric           bool success = process->DumpThreadPlansForTID(
18395ffd83dbSDimitry Andric               tmp_strm, tid, eDescriptionLevelFull, m_options.m_internal,
18405ffd83dbSDimitry Andric               true /* condense_trivial */, m_options.m_unreported);
18415ffd83dbSDimitry Andric           // If we didn't find a TID, stop here and return an error.
18425ffd83dbSDimitry Andric           if (!success) {
1843fe6060f1SDimitry Andric             result.AppendError("Error dumping plans:");
18445ffd83dbSDimitry Andric             result.AppendError(tmp_strm.GetString());
18455f757f3fSDimitry Andric             return;
18460b57cec5SDimitry Andric           }
18475ffd83dbSDimitry Andric           // Otherwise, add our data to the output:
18485ffd83dbSDimitry Andric           result.GetOutputStream() << tmp_strm.GetString();
18495ffd83dbSDimitry Andric         }
18505ffd83dbSDimitry Andric       }
18515ffd83dbSDimitry Andric       return CommandObjectIterateOverThreads::DoExecute(command, result);
18525ffd83dbSDimitry Andric     }
18535ffd83dbSDimitry Andric   }
18540b57cec5SDimitry Andric 
18555ffd83dbSDimitry Andric protected:
18565ffd83dbSDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
18575ffd83dbSDimitry Andric     // If we have already handled this from a -t option, skip it here.
1858e8d8bef9SDimitry Andric     if (llvm::is_contained(m_options.m_tids, tid))
18595ffd83dbSDimitry Andric       return true;
18605ffd83dbSDimitry Andric 
18615ffd83dbSDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
18620b57cec5SDimitry Andric 
18630b57cec5SDimitry Andric     Stream &strm = result.GetOutputStream();
18640b57cec5SDimitry Andric     DescriptionLevel desc_level = eDescriptionLevelFull;
18650b57cec5SDimitry Andric     if (m_options.m_verbose)
18660b57cec5SDimitry Andric       desc_level = eDescriptionLevelVerbose;
18670b57cec5SDimitry Andric 
18685ffd83dbSDimitry Andric     process->DumpThreadPlansForTID(strm, tid, desc_level, m_options.m_internal,
18695ffd83dbSDimitry Andric                                    true /* condense_trivial */,
18705ffd83dbSDimitry Andric                                    m_options.m_unreported);
18710b57cec5SDimitry Andric     return true;
18720b57cec5SDimitry Andric   }
18730b57cec5SDimitry Andric 
18740b57cec5SDimitry Andric   CommandOptions m_options;
18750b57cec5SDimitry Andric };
18760b57cec5SDimitry Andric 
18770b57cec5SDimitry Andric class CommandObjectThreadPlanDiscard : public CommandObjectParsed {
18780b57cec5SDimitry Andric public:
18790b57cec5SDimitry Andric   CommandObjectThreadPlanDiscard(CommandInterpreter &interpreter)
18800b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "thread plan discard",
18810b57cec5SDimitry Andric                             "Discards thread plans up to and including the "
18820b57cec5SDimitry Andric                             "specified index (see 'thread plan list'.)  "
18830b57cec5SDimitry Andric                             "Only user visible plans can be discarded.",
18840b57cec5SDimitry Andric                             nullptr,
18850b57cec5SDimitry Andric                             eCommandRequiresProcess | eCommandRequiresThread |
18860b57cec5SDimitry Andric                                 eCommandTryTargetAPILock |
18870b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched |
18880b57cec5SDimitry Andric                                 eCommandProcessMustBePaused) {
1889*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeUnsignedInteger);
18900b57cec5SDimitry Andric   }
18910b57cec5SDimitry Andric 
18920b57cec5SDimitry Andric   ~CommandObjectThreadPlanDiscard() override = default;
18930b57cec5SDimitry Andric 
1894e8d8bef9SDimitry Andric   void
1895e8d8bef9SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
1896e8d8bef9SDimitry Andric                            OptionElementVector &opt_element_vector) override {
1897e8d8bef9SDimitry Andric     if (!m_exe_ctx.HasThreadScope() || request.GetCursorIndex())
1898e8d8bef9SDimitry Andric       return;
1899e8d8bef9SDimitry Andric 
1900e8d8bef9SDimitry Andric     m_exe_ctx.GetThreadPtr()->AutoCompleteThreadPlans(request);
1901e8d8bef9SDimitry Andric   }
1902e8d8bef9SDimitry Andric 
19035f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
19040b57cec5SDimitry Andric     Thread *thread = m_exe_ctx.GetThreadPtr();
19050b57cec5SDimitry Andric     if (args.GetArgumentCount() != 1) {
19060b57cec5SDimitry Andric       result.AppendErrorWithFormat("Too many arguments, expected one - the "
19070b57cec5SDimitry Andric                                    "thread plan index - but got %zu.",
19080b57cec5SDimitry Andric                                    args.GetArgumentCount());
19095f757f3fSDimitry Andric       return;
19100b57cec5SDimitry Andric     }
19110b57cec5SDimitry Andric 
19125ffd83dbSDimitry Andric     uint32_t thread_plan_idx;
19135ffd83dbSDimitry Andric     if (!llvm::to_integer(args.GetArgumentAtIndex(0), thread_plan_idx)) {
19140b57cec5SDimitry Andric       result.AppendErrorWithFormat(
19150b57cec5SDimitry Andric           "Invalid thread index: \"%s\" - should be unsigned int.",
19160b57cec5SDimitry Andric           args.GetArgumentAtIndex(0));
19175f757f3fSDimitry Andric       return;
19180b57cec5SDimitry Andric     }
19190b57cec5SDimitry Andric 
19200b57cec5SDimitry Andric     if (thread_plan_idx == 0) {
19210b57cec5SDimitry Andric       result.AppendErrorWithFormat(
19220b57cec5SDimitry Andric           "You wouldn't really want me to discard the base thread plan.");
19235f757f3fSDimitry Andric       return;
19240b57cec5SDimitry Andric     }
19250b57cec5SDimitry Andric 
19260b57cec5SDimitry Andric     if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) {
19270b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
19280b57cec5SDimitry Andric     } else {
19290b57cec5SDimitry Andric       result.AppendErrorWithFormat(
19300b57cec5SDimitry Andric           "Could not find User thread plan with index %s.",
19310b57cec5SDimitry Andric           args.GetArgumentAtIndex(0));
19320b57cec5SDimitry Andric     }
19330b57cec5SDimitry Andric   }
19340b57cec5SDimitry Andric };
19350b57cec5SDimitry Andric 
19365ffd83dbSDimitry Andric class CommandObjectThreadPlanPrune : public CommandObjectParsed {
19375ffd83dbSDimitry Andric public:
19385ffd83dbSDimitry Andric   CommandObjectThreadPlanPrune(CommandInterpreter &interpreter)
19395ffd83dbSDimitry Andric       : CommandObjectParsed(interpreter, "thread plan prune",
19405ffd83dbSDimitry Andric                             "Removes any thread plans associated with "
19415ffd83dbSDimitry Andric                             "currently unreported threads.  "
19425ffd83dbSDimitry Andric                             "Specify one or more TID's to remove, or if no "
19435ffd83dbSDimitry Andric                             "TID's are provides, remove threads for all "
19445ffd83dbSDimitry Andric                             "unreported threads",
19455ffd83dbSDimitry Andric                             nullptr,
19465ffd83dbSDimitry Andric                             eCommandRequiresProcess |
19475ffd83dbSDimitry Andric                                 eCommandTryTargetAPILock |
19485ffd83dbSDimitry Andric                                 eCommandProcessMustBeLaunched |
19495ffd83dbSDimitry Andric                                 eCommandProcessMustBePaused) {
1950*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeThreadID, eArgRepeatStar);
19515ffd83dbSDimitry Andric   }
19525ffd83dbSDimitry Andric 
19535ffd83dbSDimitry Andric   ~CommandObjectThreadPlanPrune() override = default;
19545ffd83dbSDimitry Andric 
19555f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
19565ffd83dbSDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
19575ffd83dbSDimitry Andric 
19585ffd83dbSDimitry Andric     if (args.GetArgumentCount() == 0) {
19595ffd83dbSDimitry Andric       process->PruneThreadPlans();
19605ffd83dbSDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
19615f757f3fSDimitry Andric       return;
19625ffd83dbSDimitry Andric     }
19635ffd83dbSDimitry Andric 
19645ffd83dbSDimitry Andric     const size_t num_args = args.GetArgumentCount();
19655ffd83dbSDimitry Andric 
19665ffd83dbSDimitry Andric     std::lock_guard<std::recursive_mutex> guard(
19675ffd83dbSDimitry Andric         process->GetThreadList().GetMutex());
19685ffd83dbSDimitry Andric 
19695ffd83dbSDimitry Andric     for (size_t i = 0; i < num_args; i++) {
19705ffd83dbSDimitry Andric       lldb::tid_t tid;
19715ffd83dbSDimitry Andric       if (!llvm::to_integer(args.GetArgumentAtIndex(i), tid)) {
19725ffd83dbSDimitry Andric         result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
19735ffd83dbSDimitry Andric                                      args.GetArgumentAtIndex(i));
19745f757f3fSDimitry Andric         return;
19755ffd83dbSDimitry Andric       }
19765ffd83dbSDimitry Andric       if (!process->PruneThreadPlansForTID(tid)) {
19775ffd83dbSDimitry Andric         result.AppendErrorWithFormat("Could not find unreported tid: \"%s\"\n",
19785ffd83dbSDimitry Andric                                      args.GetArgumentAtIndex(i));
19795f757f3fSDimitry Andric         return;
19805ffd83dbSDimitry Andric       }
19815ffd83dbSDimitry Andric     }
19825ffd83dbSDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
19835ffd83dbSDimitry Andric   }
19845ffd83dbSDimitry Andric };
19855ffd83dbSDimitry Andric 
19860b57cec5SDimitry Andric // CommandObjectMultiwordThreadPlan
19870b57cec5SDimitry Andric 
19880b57cec5SDimitry Andric class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword {
19890b57cec5SDimitry Andric public:
19900b57cec5SDimitry Andric   CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter)
19910b57cec5SDimitry Andric       : CommandObjectMultiword(
19920b57cec5SDimitry Andric             interpreter, "plan",
19930b57cec5SDimitry Andric             "Commands for managing thread plans that control execution.",
19940b57cec5SDimitry Andric             "thread plan <subcommand> [<subcommand objects]") {
19950b57cec5SDimitry Andric     LoadSubCommand(
19960b57cec5SDimitry Andric         "list", CommandObjectSP(new CommandObjectThreadPlanList(interpreter)));
19970b57cec5SDimitry Andric     LoadSubCommand(
19980b57cec5SDimitry Andric         "discard",
19990b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectThreadPlanDiscard(interpreter)));
20005ffd83dbSDimitry Andric     LoadSubCommand(
20015ffd83dbSDimitry Andric         "prune",
20025ffd83dbSDimitry Andric         CommandObjectSP(new CommandObjectThreadPlanPrune(interpreter)));
20030b57cec5SDimitry Andric   }
20040b57cec5SDimitry Andric 
20050b57cec5SDimitry Andric   ~CommandObjectMultiwordThreadPlan() override = default;
20060b57cec5SDimitry Andric };
20070b57cec5SDimitry Andric 
2008e8d8bef9SDimitry Andric // Next are the subcommands of CommandObjectMultiwordTrace
2009e8d8bef9SDimitry Andric 
2010fe6060f1SDimitry Andric // CommandObjectTraceExport
2011fe6060f1SDimitry Andric 
2012fe6060f1SDimitry Andric class CommandObjectTraceExport : public CommandObjectMultiword {
2013fe6060f1SDimitry Andric public:
2014fe6060f1SDimitry Andric   CommandObjectTraceExport(CommandInterpreter &interpreter)
2015fe6060f1SDimitry Andric       : CommandObjectMultiword(
2016fe6060f1SDimitry Andric             interpreter, "trace thread export",
2017fe6060f1SDimitry Andric             "Commands for exporting traces of the threads in the current "
2018fe6060f1SDimitry Andric             "process to different formats.",
2019fe6060f1SDimitry Andric             "thread trace export <export-plugin> [<subcommand objects>]") {
2020fe6060f1SDimitry Andric 
2021349cc55cSDimitry Andric     unsigned i = 0;
2022349cc55cSDimitry Andric     for (llvm::StringRef plugin_name =
202381ad6265SDimitry Andric              PluginManager::GetTraceExporterPluginNameAtIndex(i);
2024349cc55cSDimitry Andric          !plugin_name.empty();
2025349cc55cSDimitry Andric          plugin_name = PluginManager::GetTraceExporterPluginNameAtIndex(i++)) {
2026fe6060f1SDimitry Andric       if (ThreadTraceExportCommandCreator command_creator =
2027fe6060f1SDimitry Andric               PluginManager::GetThreadTraceExportCommandCreatorAtIndex(i)) {
2028fe6060f1SDimitry Andric         LoadSubCommand(plugin_name, command_creator(interpreter));
2029fe6060f1SDimitry Andric       }
2030fe6060f1SDimitry Andric     }
2031fe6060f1SDimitry Andric   }
2032fe6060f1SDimitry Andric };
2033fe6060f1SDimitry Andric 
2034e8d8bef9SDimitry Andric // CommandObjectTraceStart
2035e8d8bef9SDimitry Andric 
2036fe6060f1SDimitry Andric class CommandObjectTraceStart : public CommandObjectTraceProxy {
2037e8d8bef9SDimitry Andric public:
2038e8d8bef9SDimitry Andric   CommandObjectTraceStart(CommandInterpreter &interpreter)
2039fe6060f1SDimitry Andric       : CommandObjectTraceProxy(
2040fe6060f1SDimitry Andric             /*live_debug_session_only=*/true, interpreter, "thread trace start",
2041e8d8bef9SDimitry Andric             "Start tracing threads with the corresponding trace "
2042e8d8bef9SDimitry Andric             "plug-in for the current process.",
2043e8d8bef9SDimitry Andric             "thread trace start [<trace-options>]") {}
2044e8d8bef9SDimitry Andric 
2045e8d8bef9SDimitry Andric protected:
2046fe6060f1SDimitry Andric   lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override {
2047fe6060f1SDimitry Andric     return trace.GetThreadTraceStartCommand(m_interpreter);
2048e8d8bef9SDimitry Andric   }
2049e8d8bef9SDimitry Andric };
2050e8d8bef9SDimitry Andric 
2051e8d8bef9SDimitry Andric // CommandObjectTraceStop
2052e8d8bef9SDimitry Andric 
2053fe6060f1SDimitry Andric class CommandObjectTraceStop : public CommandObjectMultipleThreads {
2054e8d8bef9SDimitry Andric public:
2055e8d8bef9SDimitry Andric   CommandObjectTraceStop(CommandInterpreter &interpreter)
2056fe6060f1SDimitry Andric       : CommandObjectMultipleThreads(
2057e8d8bef9SDimitry Andric             interpreter, "thread trace stop",
2058fe6060f1SDimitry Andric             "Stop tracing threads, including the ones traced with the "
2059fe6060f1SDimitry Andric             "\"process trace start\" command."
2060e8d8bef9SDimitry Andric             "Defaults to the current thread. Thread indices can be "
2061fe6060f1SDimitry Andric             "specified as arguments.\n Use the thread-index \"all\" to stop "
2062fe6060f1SDimitry Andric             "tracing "
2063fe6060f1SDimitry Andric             "for all existing threads.",
2064e8d8bef9SDimitry Andric             "thread trace stop [<thread-index> <thread-index> ...]",
2065e8d8bef9SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
2066e8d8bef9SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
2067e8d8bef9SDimitry Andric                 eCommandProcessMustBeTraced) {}
2068e8d8bef9SDimitry Andric 
2069e8d8bef9SDimitry Andric   ~CommandObjectTraceStop() override = default;
2070e8d8bef9SDimitry Andric 
2071fe6060f1SDimitry Andric   bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
2072fe6060f1SDimitry Andric                           llvm::ArrayRef<lldb::tid_t> tids) override {
2073fe6060f1SDimitry Andric     ProcessSP process_sp = m_exe_ctx.GetProcessSP();
2074e8d8bef9SDimitry Andric 
2075fe6060f1SDimitry Andric     TraceSP trace_sp = process_sp->GetTarget().GetTrace();
2076e8d8bef9SDimitry Andric 
2077fe6060f1SDimitry Andric     if (llvm::Error err = trace_sp->Stop(tids))
2078fe6060f1SDimitry Andric       result.AppendError(toString(std::move(err)));
2079fe6060f1SDimitry Andric     else
2080fe6060f1SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
2081fe6060f1SDimitry Andric 
2082fe6060f1SDimitry Andric     return result.Succeeded();
2083e8d8bef9SDimitry Andric   }
2084e8d8bef9SDimitry Andric };
2085e8d8bef9SDimitry Andric 
2086bdd1243dSDimitry Andric static ThreadSP GetSingleThreadFromArgs(ExecutionContext &exe_ctx, Args &args,
2087bdd1243dSDimitry Andric                                         CommandReturnObject &result) {
2088bdd1243dSDimitry Andric   if (args.GetArgumentCount() == 0)
2089bdd1243dSDimitry Andric     return exe_ctx.GetThreadSP();
2090bdd1243dSDimitry Andric 
2091bdd1243dSDimitry Andric   const char *arg = args.GetArgumentAtIndex(0);
2092bdd1243dSDimitry Andric   uint32_t thread_idx;
2093bdd1243dSDimitry Andric 
2094bdd1243dSDimitry Andric   if (!llvm::to_integer(arg, thread_idx)) {
2095bdd1243dSDimitry Andric     result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", arg);
2096bdd1243dSDimitry Andric     return nullptr;
2097bdd1243dSDimitry Andric   }
2098bdd1243dSDimitry Andric   ThreadSP thread_sp =
2099bdd1243dSDimitry Andric       exe_ctx.GetProcessRef().GetThreadList().FindThreadByIndexID(thread_idx);
2100bdd1243dSDimitry Andric   if (!thread_sp)
2101bdd1243dSDimitry Andric     result.AppendErrorWithFormat("no thread with index: \"%s\"\n", arg);
2102bdd1243dSDimitry Andric   return thread_sp;
2103bdd1243dSDimitry Andric }
2104bdd1243dSDimitry Andric 
2105bdd1243dSDimitry Andric // CommandObjectTraceDumpFunctionCalls
2106bdd1243dSDimitry Andric #define LLDB_OPTIONS_thread_trace_dump_function_calls
2107bdd1243dSDimitry Andric #include "CommandOptions.inc"
2108bdd1243dSDimitry Andric 
2109bdd1243dSDimitry Andric class CommandObjectTraceDumpFunctionCalls : public CommandObjectParsed {
2110bdd1243dSDimitry Andric public:
2111bdd1243dSDimitry Andric   class CommandOptions : public Options {
2112bdd1243dSDimitry Andric   public:
2113bdd1243dSDimitry Andric     CommandOptions() { OptionParsingStarting(nullptr); }
2114bdd1243dSDimitry Andric 
2115bdd1243dSDimitry Andric     ~CommandOptions() override = default;
2116bdd1243dSDimitry Andric 
2117bdd1243dSDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2118bdd1243dSDimitry Andric                           ExecutionContext *execution_context) override {
2119bdd1243dSDimitry Andric       Status error;
2120bdd1243dSDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
2121bdd1243dSDimitry Andric 
2122bdd1243dSDimitry Andric       switch (short_option) {
2123bdd1243dSDimitry Andric       case 'j': {
2124bdd1243dSDimitry Andric         m_dumper_options.json = true;
2125bdd1243dSDimitry Andric         break;
2126bdd1243dSDimitry Andric       }
2127bdd1243dSDimitry Andric       case 'J': {
2128bdd1243dSDimitry Andric         m_dumper_options.json = true;
2129bdd1243dSDimitry Andric         m_dumper_options.pretty_print_json = true;
2130bdd1243dSDimitry Andric         break;
2131bdd1243dSDimitry Andric       }
2132bdd1243dSDimitry Andric       case 'F': {
2133bdd1243dSDimitry Andric         m_output_file.emplace(option_arg);
2134bdd1243dSDimitry Andric         break;
2135bdd1243dSDimitry Andric       }
2136bdd1243dSDimitry Andric       default:
2137bdd1243dSDimitry Andric         llvm_unreachable("Unimplemented option");
2138bdd1243dSDimitry Andric       }
2139bdd1243dSDimitry Andric       return error;
2140bdd1243dSDimitry Andric     }
2141bdd1243dSDimitry Andric 
2142bdd1243dSDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
2143bdd1243dSDimitry Andric       m_dumper_options = {};
2144bdd1243dSDimitry Andric       m_output_file = std::nullopt;
2145bdd1243dSDimitry Andric     }
2146bdd1243dSDimitry Andric 
2147bdd1243dSDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2148bdd1243dSDimitry Andric       return llvm::ArrayRef(g_thread_trace_dump_function_calls_options);
2149bdd1243dSDimitry Andric     }
2150bdd1243dSDimitry Andric 
2151bdd1243dSDimitry Andric     static const size_t kDefaultCount = 20;
2152bdd1243dSDimitry Andric 
2153bdd1243dSDimitry Andric     // Instance variables to hold the values for command options.
2154bdd1243dSDimitry Andric     TraceDumperOptions m_dumper_options;
2155bdd1243dSDimitry Andric     std::optional<FileSpec> m_output_file;
2156bdd1243dSDimitry Andric   };
2157bdd1243dSDimitry Andric 
2158bdd1243dSDimitry Andric   CommandObjectTraceDumpFunctionCalls(CommandInterpreter &interpreter)
2159bdd1243dSDimitry Andric       : CommandObjectParsed(
2160bdd1243dSDimitry Andric             interpreter, "thread trace dump function-calls",
2161bdd1243dSDimitry Andric             "Dump the traced function-calls for one thread. If no "
2162bdd1243dSDimitry Andric             "thread is specified, the current thread is used.",
2163bdd1243dSDimitry Andric             nullptr,
2164bdd1243dSDimitry Andric             eCommandRequiresProcess | eCommandRequiresThread |
2165bdd1243dSDimitry Andric                 eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
2166bdd1243dSDimitry Andric                 eCommandProcessMustBePaused | eCommandProcessMustBeTraced) {
2167*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatOptional);
2168bdd1243dSDimitry Andric   }
2169bdd1243dSDimitry Andric 
2170bdd1243dSDimitry Andric   ~CommandObjectTraceDumpFunctionCalls() override = default;
2171bdd1243dSDimitry Andric 
2172bdd1243dSDimitry Andric   Options *GetOptions() override { return &m_options; }
2173bdd1243dSDimitry Andric 
2174bdd1243dSDimitry Andric protected:
21755f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
2176bdd1243dSDimitry Andric     ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);
2177bdd1243dSDimitry Andric     if (!thread_sp) {
2178bdd1243dSDimitry Andric       result.AppendError("invalid thread\n");
21795f757f3fSDimitry Andric       return;
2180bdd1243dSDimitry Andric     }
2181bdd1243dSDimitry Andric 
2182bdd1243dSDimitry Andric     llvm::Expected<TraceCursorSP> cursor_or_error =
2183bdd1243dSDimitry Andric         m_exe_ctx.GetTargetSP()->GetTrace()->CreateNewCursor(*thread_sp);
2184bdd1243dSDimitry Andric 
2185bdd1243dSDimitry Andric     if (!cursor_or_error) {
2186bdd1243dSDimitry Andric       result.AppendError(llvm::toString(cursor_or_error.takeError()));
21875f757f3fSDimitry Andric       return;
2188bdd1243dSDimitry Andric     }
2189bdd1243dSDimitry Andric     TraceCursorSP &cursor_sp = *cursor_or_error;
2190bdd1243dSDimitry Andric 
2191bdd1243dSDimitry Andric     std::optional<StreamFile> out_file;
2192bdd1243dSDimitry Andric     if (m_options.m_output_file) {
2193bdd1243dSDimitry Andric       out_file.emplace(m_options.m_output_file->GetPath().c_str(),
2194bdd1243dSDimitry Andric                        File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |
2195bdd1243dSDimitry Andric                            File::eOpenOptionTruncate);
2196bdd1243dSDimitry Andric     }
2197bdd1243dSDimitry Andric 
2198bdd1243dSDimitry Andric     m_options.m_dumper_options.forwards = true;
2199bdd1243dSDimitry Andric 
2200bdd1243dSDimitry Andric     TraceDumper dumper(std::move(cursor_sp),
2201bdd1243dSDimitry Andric                        out_file ? *out_file : result.GetOutputStream(),
2202bdd1243dSDimitry Andric                        m_options.m_dumper_options);
2203bdd1243dSDimitry Andric 
2204bdd1243dSDimitry Andric     dumper.DumpFunctionCalls();
2205bdd1243dSDimitry Andric   }
2206bdd1243dSDimitry Andric 
2207bdd1243dSDimitry Andric   CommandOptions m_options;
2208bdd1243dSDimitry Andric };
2209bdd1243dSDimitry Andric 
2210e8d8bef9SDimitry Andric // CommandObjectTraceDumpInstructions
2211e8d8bef9SDimitry Andric #define LLDB_OPTIONS_thread_trace_dump_instructions
2212e8d8bef9SDimitry Andric #include "CommandOptions.inc"
2213e8d8bef9SDimitry Andric 
221481ad6265SDimitry Andric class CommandObjectTraceDumpInstructions : public CommandObjectParsed {
2215e8d8bef9SDimitry Andric public:
2216e8d8bef9SDimitry Andric   class CommandOptions : public Options {
2217e8d8bef9SDimitry Andric   public:
221804eeddc0SDimitry Andric     CommandOptions() { OptionParsingStarting(nullptr); }
2219e8d8bef9SDimitry Andric 
2220e8d8bef9SDimitry Andric     ~CommandOptions() override = default;
2221e8d8bef9SDimitry Andric 
2222e8d8bef9SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2223e8d8bef9SDimitry Andric                           ExecutionContext *execution_context) override {
2224e8d8bef9SDimitry Andric       Status error;
2225e8d8bef9SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
2226e8d8bef9SDimitry Andric 
2227e8d8bef9SDimitry Andric       switch (short_option) {
2228e8d8bef9SDimitry Andric       case 'c': {
2229e8d8bef9SDimitry Andric         int32_t count;
2230e8d8bef9SDimitry Andric         if (option_arg.empty() || option_arg.getAsInteger(0, count) ||
2231e8d8bef9SDimitry Andric             count < 0)
2232e8d8bef9SDimitry Andric           error.SetErrorStringWithFormat(
2233e8d8bef9SDimitry Andric               "invalid integer value for option '%s'",
2234e8d8bef9SDimitry Andric               option_arg.str().c_str());
2235e8d8bef9SDimitry Andric         else
2236e8d8bef9SDimitry Andric           m_count = count;
2237e8d8bef9SDimitry Andric         break;
2238e8d8bef9SDimitry Andric       }
223981ad6265SDimitry Andric       case 'a': {
224081ad6265SDimitry Andric         m_count = std::numeric_limits<decltype(m_count)>::max();
224181ad6265SDimitry Andric         break;
224281ad6265SDimitry Andric       }
2243fe6060f1SDimitry Andric       case 's': {
2244fe6060f1SDimitry Andric         int32_t skip;
2245fe6060f1SDimitry Andric         if (option_arg.empty() || option_arg.getAsInteger(0, skip) || skip < 0)
2246e8d8bef9SDimitry Andric           error.SetErrorStringWithFormat(
2247e8d8bef9SDimitry Andric               "invalid integer value for option '%s'",
2248e8d8bef9SDimitry Andric               option_arg.str().c_str());
2249e8d8bef9SDimitry Andric         else
225081ad6265SDimitry Andric           m_dumper_options.skip = skip;
225181ad6265SDimitry Andric         break;
225281ad6265SDimitry Andric       }
225381ad6265SDimitry Andric       case 'i': {
225481ad6265SDimitry Andric         uint64_t id;
225581ad6265SDimitry Andric         if (option_arg.empty() || option_arg.getAsInteger(0, id))
225681ad6265SDimitry Andric           error.SetErrorStringWithFormat(
225781ad6265SDimitry Andric               "invalid integer value for option '%s'",
225881ad6265SDimitry Andric               option_arg.str().c_str());
225981ad6265SDimitry Andric         else
226081ad6265SDimitry Andric           m_dumper_options.id = id;
226181ad6265SDimitry Andric         break;
226281ad6265SDimitry Andric       }
226381ad6265SDimitry Andric       case 'F': {
226481ad6265SDimitry Andric         m_output_file.emplace(option_arg);
2265e8d8bef9SDimitry Andric         break;
2266e8d8bef9SDimitry Andric       }
2267e8d8bef9SDimitry Andric       case 'r': {
226881ad6265SDimitry Andric         m_dumper_options.raw = true;
2269e8d8bef9SDimitry Andric         break;
2270e8d8bef9SDimitry Andric       }
2271fe6060f1SDimitry Andric       case 'f': {
227281ad6265SDimitry Andric         m_dumper_options.forwards = true;
2273fe6060f1SDimitry Andric         break;
2274fe6060f1SDimitry Andric       }
2275753f127fSDimitry Andric       case 'k': {
2276753f127fSDimitry Andric         m_dumper_options.show_control_flow_kind = true;
2277753f127fSDimitry Andric         break;
2278753f127fSDimitry Andric       }
2279fe6060f1SDimitry Andric       case 't': {
2280972a253aSDimitry Andric         m_dumper_options.show_timestamps = true;
228181ad6265SDimitry Andric         break;
228281ad6265SDimitry Andric       }
228381ad6265SDimitry Andric       case 'e': {
228481ad6265SDimitry Andric         m_dumper_options.show_events = true;
228581ad6265SDimitry Andric         break;
228681ad6265SDimitry Andric       }
228781ad6265SDimitry Andric       case 'j': {
228881ad6265SDimitry Andric         m_dumper_options.json = true;
228981ad6265SDimitry Andric         break;
229081ad6265SDimitry Andric       }
229181ad6265SDimitry Andric       case 'J': {
229281ad6265SDimitry Andric         m_dumper_options.pretty_print_json = true;
229381ad6265SDimitry Andric         m_dumper_options.json = true;
229481ad6265SDimitry Andric         break;
229581ad6265SDimitry Andric       }
2296bdd1243dSDimitry Andric       case 'E': {
2297bdd1243dSDimitry Andric         m_dumper_options.only_events = true;
2298bdd1243dSDimitry Andric         m_dumper_options.show_events = true;
2299bdd1243dSDimitry Andric         break;
2300bdd1243dSDimitry Andric       }
230181ad6265SDimitry Andric       case 'C': {
230281ad6265SDimitry Andric         m_continue = true;
2303fe6060f1SDimitry Andric         break;
2304fe6060f1SDimitry Andric       }
2305e8d8bef9SDimitry Andric       default:
2306e8d8bef9SDimitry Andric         llvm_unreachable("Unimplemented option");
2307e8d8bef9SDimitry Andric       }
2308e8d8bef9SDimitry Andric       return error;
2309e8d8bef9SDimitry Andric     }
2310e8d8bef9SDimitry Andric 
2311e8d8bef9SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
2312e8d8bef9SDimitry Andric       m_count = kDefaultCount;
231381ad6265SDimitry Andric       m_continue = false;
2314bdd1243dSDimitry Andric       m_output_file = std::nullopt;
231581ad6265SDimitry Andric       m_dumper_options = {};
2316e8d8bef9SDimitry Andric     }
2317e8d8bef9SDimitry Andric 
2318e8d8bef9SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2319bdd1243dSDimitry Andric       return llvm::ArrayRef(g_thread_trace_dump_instructions_options);
2320e8d8bef9SDimitry Andric     }
2321e8d8bef9SDimitry Andric 
2322e8d8bef9SDimitry Andric     static const size_t kDefaultCount = 20;
2323e8d8bef9SDimitry Andric 
2324e8d8bef9SDimitry Andric     // Instance variables to hold the values for command options.
2325e8d8bef9SDimitry Andric     size_t m_count;
232681ad6265SDimitry Andric     size_t m_continue;
2327bdd1243dSDimitry Andric     std::optional<FileSpec> m_output_file;
232881ad6265SDimitry Andric     TraceDumperOptions m_dumper_options;
2329e8d8bef9SDimitry Andric   };
2330e8d8bef9SDimitry Andric 
2331e8d8bef9SDimitry Andric   CommandObjectTraceDumpInstructions(CommandInterpreter &interpreter)
233281ad6265SDimitry Andric       : CommandObjectParsed(
2333e8d8bef9SDimitry Andric             interpreter, "thread trace dump instructions",
233481ad6265SDimitry Andric             "Dump the traced instructions for one thread. If no "
233581ad6265SDimitry Andric             "thread is specified, show the current thread.",
2336e8d8bef9SDimitry Andric             nullptr,
233781ad6265SDimitry Andric             eCommandRequiresProcess | eCommandRequiresThread |
233881ad6265SDimitry Andric                 eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
233981ad6265SDimitry Andric                 eCommandProcessMustBePaused | eCommandProcessMustBeTraced) {
2340*0fca6ea1SDimitry Andric     AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatOptional);
234181ad6265SDimitry Andric   }
2342e8d8bef9SDimitry Andric 
2343e8d8bef9SDimitry Andric   ~CommandObjectTraceDumpInstructions() override = default;
2344e8d8bef9SDimitry Andric 
2345e8d8bef9SDimitry Andric   Options *GetOptions() override { return &m_options; }
2346e8d8bef9SDimitry Andric 
2347bdd1243dSDimitry Andric   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
2348e8d8bef9SDimitry Andric                                               uint32_t index) override {
234981ad6265SDimitry Andric     std::string cmd;
235081ad6265SDimitry Andric     current_command_args.GetCommandString(cmd);
235181ad6265SDimitry Andric     if (cmd.find(" --continue") == std::string::npos)
235281ad6265SDimitry Andric       cmd += " --continue";
235381ad6265SDimitry Andric     return cmd;
2354e8d8bef9SDimitry Andric   }
2355e8d8bef9SDimitry Andric 
2356e8d8bef9SDimitry Andric protected:
23575f757f3fSDimitry Andric   void DoExecute(Args &args, CommandReturnObject &result) override {
2358bdd1243dSDimitry Andric     ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);
235981ad6265SDimitry Andric     if (!thread_sp) {
236081ad6265SDimitry Andric       result.AppendError("invalid thread\n");
23615f757f3fSDimitry Andric       return;
236281ad6265SDimitry Andric     }
236381ad6265SDimitry Andric 
236481ad6265SDimitry Andric     if (m_options.m_continue && m_last_id) {
236581ad6265SDimitry Andric       // We set up the options to continue one instruction past where
236681ad6265SDimitry Andric       // the previous iteration stopped.
236781ad6265SDimitry Andric       m_options.m_dumper_options.skip = 1;
236881ad6265SDimitry Andric       m_options.m_dumper_options.id = m_last_id;
236981ad6265SDimitry Andric     }
237081ad6265SDimitry Andric 
2371bdd1243dSDimitry Andric     llvm::Expected<TraceCursorSP> cursor_or_error =
237281ad6265SDimitry Andric         m_exe_ctx.GetTargetSP()->GetTrace()->CreateNewCursor(*thread_sp);
237381ad6265SDimitry Andric 
237481ad6265SDimitry Andric     if (!cursor_or_error) {
237581ad6265SDimitry Andric       result.AppendError(llvm::toString(cursor_or_error.takeError()));
23765f757f3fSDimitry Andric       return;
237781ad6265SDimitry Andric     }
2378bdd1243dSDimitry Andric     TraceCursorSP &cursor_sp = *cursor_or_error;
237981ad6265SDimitry Andric 
238081ad6265SDimitry Andric     if (m_options.m_dumper_options.id &&
2381bdd1243dSDimitry Andric         !cursor_sp->HasId(*m_options.m_dumper_options.id)) {
238281ad6265SDimitry Andric       result.AppendError("invalid instruction id\n");
23835f757f3fSDimitry Andric       return;
238481ad6265SDimitry Andric     }
238581ad6265SDimitry Andric 
2386bdd1243dSDimitry Andric     std::optional<StreamFile> out_file;
238781ad6265SDimitry Andric     if (m_options.m_output_file) {
238881ad6265SDimitry Andric       out_file.emplace(m_options.m_output_file->GetPath().c_str(),
2389bdd1243dSDimitry Andric                        File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |
2390bdd1243dSDimitry Andric                            File::eOpenOptionTruncate);
239181ad6265SDimitry Andric     }
239281ad6265SDimitry Andric 
239381ad6265SDimitry Andric     if (m_options.m_continue && !m_last_id) {
239481ad6265SDimitry Andric       // We need to stop processing data when we already ran out of instructions
239581ad6265SDimitry Andric       // in a previous command. We can fake this by setting the cursor past the
239681ad6265SDimitry Andric       // end of the trace.
2397bdd1243dSDimitry Andric       cursor_sp->Seek(1, lldb::eTraceCursorSeekTypeEnd);
239881ad6265SDimitry Andric     }
239981ad6265SDimitry Andric 
2400bdd1243dSDimitry Andric     TraceDumper dumper(std::move(cursor_sp),
240181ad6265SDimitry Andric                        out_file ? *out_file : result.GetOutputStream(),
240281ad6265SDimitry Andric                        m_options.m_dumper_options);
240381ad6265SDimitry Andric 
240481ad6265SDimitry Andric     m_last_id = dumper.DumpInstructions(m_options.m_count);
2405e8d8bef9SDimitry Andric   }
2406e8d8bef9SDimitry Andric 
2407e8d8bef9SDimitry Andric   CommandOptions m_options;
240806c3fb27SDimitry Andric   // Last traversed id used to continue a repeat command. std::nullopt means
240981ad6265SDimitry Andric   // that all the trace has been consumed.
2410bdd1243dSDimitry Andric   std::optional<lldb::user_id_t> m_last_id;
2411fe6060f1SDimitry Andric };
2412fe6060f1SDimitry Andric 
2413fe6060f1SDimitry Andric // CommandObjectTraceDumpInfo
2414fe6060f1SDimitry Andric #define LLDB_OPTIONS_thread_trace_dump_info
2415fe6060f1SDimitry Andric #include "CommandOptions.inc"
2416fe6060f1SDimitry Andric 
2417fe6060f1SDimitry Andric class CommandObjectTraceDumpInfo : public CommandObjectIterateOverThreads {
2418fe6060f1SDimitry Andric public:
2419fe6060f1SDimitry Andric   class CommandOptions : public Options {
2420fe6060f1SDimitry Andric   public:
242104eeddc0SDimitry Andric     CommandOptions() { OptionParsingStarting(nullptr); }
2422fe6060f1SDimitry Andric 
2423fe6060f1SDimitry Andric     ~CommandOptions() override = default;
2424fe6060f1SDimitry Andric 
2425fe6060f1SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2426fe6060f1SDimitry Andric                           ExecutionContext *execution_context) override {
2427fe6060f1SDimitry Andric       Status error;
2428fe6060f1SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
2429fe6060f1SDimitry Andric 
2430fe6060f1SDimitry Andric       switch (short_option) {
2431fe6060f1SDimitry Andric       case 'v': {
2432fe6060f1SDimitry Andric         m_verbose = true;
2433fe6060f1SDimitry Andric         break;
2434fe6060f1SDimitry Andric       }
2435753f127fSDimitry Andric       case 'j': {
2436753f127fSDimitry Andric         m_json = true;
2437753f127fSDimitry Andric         break;
2438753f127fSDimitry Andric       }
2439fe6060f1SDimitry Andric       default:
2440fe6060f1SDimitry Andric         llvm_unreachable("Unimplemented option");
2441fe6060f1SDimitry Andric       }
2442fe6060f1SDimitry Andric       return error;
2443fe6060f1SDimitry Andric     }
2444fe6060f1SDimitry Andric 
2445fe6060f1SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
2446fe6060f1SDimitry Andric       m_verbose = false;
2447753f127fSDimitry Andric       m_json = false;
2448fe6060f1SDimitry Andric     }
2449fe6060f1SDimitry Andric 
2450fe6060f1SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2451bdd1243dSDimitry Andric       return llvm::ArrayRef(g_thread_trace_dump_info_options);
2452fe6060f1SDimitry Andric     }
2453fe6060f1SDimitry Andric 
2454fe6060f1SDimitry Andric     // Instance variables to hold the values for command options.
2455fe6060f1SDimitry Andric     bool m_verbose;
2456753f127fSDimitry Andric     bool m_json;
2457fe6060f1SDimitry Andric   };
2458fe6060f1SDimitry Andric 
2459fe6060f1SDimitry Andric   CommandObjectTraceDumpInfo(CommandInterpreter &interpreter)
2460fe6060f1SDimitry Andric       : CommandObjectIterateOverThreads(
2461fe6060f1SDimitry Andric             interpreter, "thread trace dump info",
2462fe6060f1SDimitry Andric             "Dump the traced information for one or more threads.  If no "
2463fe6060f1SDimitry Andric             "threads are specified, show the current thread. Use the "
2464fe6060f1SDimitry Andric             "thread-index \"all\" to see all threads.",
2465fe6060f1SDimitry Andric             nullptr,
2466fe6060f1SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
2467fe6060f1SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
246804eeddc0SDimitry Andric                 eCommandProcessMustBeTraced) {}
2469fe6060f1SDimitry Andric 
2470fe6060f1SDimitry Andric   ~CommandObjectTraceDumpInfo() override = default;
2471fe6060f1SDimitry Andric 
2472fe6060f1SDimitry Andric   Options *GetOptions() override { return &m_options; }
2473fe6060f1SDimitry Andric 
2474fe6060f1SDimitry Andric protected:
2475fe6060f1SDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
2476fe6060f1SDimitry Andric     const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace();
2477fe6060f1SDimitry Andric     ThreadSP thread_sp =
2478fe6060f1SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
2479fe6060f1SDimitry Andric     trace_sp->DumpTraceInfo(*thread_sp, result.GetOutputStream(),
2480753f127fSDimitry Andric                             m_options.m_verbose, m_options.m_json);
2481fe6060f1SDimitry Andric     return true;
2482fe6060f1SDimitry Andric   }
2483fe6060f1SDimitry Andric 
2484fe6060f1SDimitry Andric   CommandOptions m_options;
2485e8d8bef9SDimitry Andric };
2486e8d8bef9SDimitry Andric 
2487e8d8bef9SDimitry Andric // CommandObjectMultiwordTraceDump
2488e8d8bef9SDimitry Andric class CommandObjectMultiwordTraceDump : public CommandObjectMultiword {
2489e8d8bef9SDimitry Andric public:
2490e8d8bef9SDimitry Andric   CommandObjectMultiwordTraceDump(CommandInterpreter &interpreter)
2491e8d8bef9SDimitry Andric       : CommandObjectMultiword(
2492e8d8bef9SDimitry Andric             interpreter, "dump",
2493e8d8bef9SDimitry Andric             "Commands for displaying trace information of the threads "
2494e8d8bef9SDimitry Andric             "in the current process.",
2495e8d8bef9SDimitry Andric             "thread trace dump <subcommand> [<subcommand objects>]") {
2496e8d8bef9SDimitry Andric     LoadSubCommand(
2497e8d8bef9SDimitry Andric         "instructions",
2498e8d8bef9SDimitry Andric         CommandObjectSP(new CommandObjectTraceDumpInstructions(interpreter)));
2499fe6060f1SDimitry Andric     LoadSubCommand(
2500bdd1243dSDimitry Andric         "function-calls",
2501bdd1243dSDimitry Andric         CommandObjectSP(new CommandObjectTraceDumpFunctionCalls(interpreter)));
2502bdd1243dSDimitry Andric     LoadSubCommand(
2503fe6060f1SDimitry Andric         "info", CommandObjectSP(new CommandObjectTraceDumpInfo(interpreter)));
2504e8d8bef9SDimitry Andric   }
2505e8d8bef9SDimitry Andric   ~CommandObjectMultiwordTraceDump() override = default;
2506e8d8bef9SDimitry Andric };
2507e8d8bef9SDimitry Andric 
2508e8d8bef9SDimitry Andric // CommandObjectMultiwordTrace
2509e8d8bef9SDimitry Andric class CommandObjectMultiwordTrace : public CommandObjectMultiword {
2510e8d8bef9SDimitry Andric public:
2511e8d8bef9SDimitry Andric   CommandObjectMultiwordTrace(CommandInterpreter &interpreter)
2512e8d8bef9SDimitry Andric       : CommandObjectMultiword(
2513e8d8bef9SDimitry Andric             interpreter, "trace",
2514e8d8bef9SDimitry Andric             "Commands for operating on traces of the threads in the current "
2515e8d8bef9SDimitry Andric             "process.",
2516e8d8bef9SDimitry Andric             "thread trace <subcommand> [<subcommand objects>]") {
2517e8d8bef9SDimitry Andric     LoadSubCommand("dump", CommandObjectSP(new CommandObjectMultiwordTraceDump(
2518e8d8bef9SDimitry Andric                                interpreter)));
2519e8d8bef9SDimitry Andric     LoadSubCommand("start",
2520e8d8bef9SDimitry Andric                    CommandObjectSP(new CommandObjectTraceStart(interpreter)));
2521e8d8bef9SDimitry Andric     LoadSubCommand("stop",
2522e8d8bef9SDimitry Andric                    CommandObjectSP(new CommandObjectTraceStop(interpreter)));
2523fe6060f1SDimitry Andric     LoadSubCommand("export",
2524fe6060f1SDimitry Andric                    CommandObjectSP(new CommandObjectTraceExport(interpreter)));
2525e8d8bef9SDimitry Andric   }
2526e8d8bef9SDimitry Andric 
2527e8d8bef9SDimitry Andric   ~CommandObjectMultiwordTrace() override = default;
2528e8d8bef9SDimitry Andric };
2529e8d8bef9SDimitry Andric 
25300b57cec5SDimitry Andric // CommandObjectMultiwordThread
25310b57cec5SDimitry Andric 
25320b57cec5SDimitry Andric CommandObjectMultiwordThread::CommandObjectMultiwordThread(
25330b57cec5SDimitry Andric     CommandInterpreter &interpreter)
2534480093f4SDimitry Andric     : CommandObjectMultiword(interpreter, "thread",
2535480093f4SDimitry Andric                              "Commands for operating on "
25360b57cec5SDimitry Andric                              "one or more threads in "
25370b57cec5SDimitry Andric                              "the current process.",
25380b57cec5SDimitry Andric                              "thread <subcommand> [<subcommand-options>]") {
25390b57cec5SDimitry Andric   LoadSubCommand("backtrace", CommandObjectSP(new CommandObjectThreadBacktrace(
25400b57cec5SDimitry Andric                                   interpreter)));
25410b57cec5SDimitry Andric   LoadSubCommand("continue",
25420b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadContinue(interpreter)));
25430b57cec5SDimitry Andric   LoadSubCommand("list",
25440b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadList(interpreter)));
25450b57cec5SDimitry Andric   LoadSubCommand("return",
25460b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadReturn(interpreter)));
25470b57cec5SDimitry Andric   LoadSubCommand("jump",
25480b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadJump(interpreter)));
25490b57cec5SDimitry Andric   LoadSubCommand("select",
25500b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadSelect(interpreter)));
25510b57cec5SDimitry Andric   LoadSubCommand("until",
25520b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadUntil(interpreter)));
25530b57cec5SDimitry Andric   LoadSubCommand("info",
25540b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadInfo(interpreter)));
2555480093f4SDimitry Andric   LoadSubCommand("exception", CommandObjectSP(new CommandObjectThreadException(
2556480093f4SDimitry Andric                                   interpreter)));
2557d56accc7SDimitry Andric   LoadSubCommand("siginfo",
2558d56accc7SDimitry Andric                  CommandObjectSP(new CommandObjectThreadSiginfo(interpreter)));
25590b57cec5SDimitry Andric   LoadSubCommand("step-in",
25600b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
25610b57cec5SDimitry Andric                      interpreter, "thread step-in",
25620b57cec5SDimitry Andric                      "Source level single step, stepping into calls.  Defaults "
25630b57cec5SDimitry Andric                      "to current thread unless specified.",
25640b57cec5SDimitry Andric                      nullptr, eStepTypeInto, eStepScopeSource)));
25650b57cec5SDimitry Andric 
25660b57cec5SDimitry Andric   LoadSubCommand("step-out",
25670b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
25680b57cec5SDimitry Andric                      interpreter, "thread step-out",
25690b57cec5SDimitry Andric                      "Finish executing the current stack frame and stop after "
25700b57cec5SDimitry Andric                      "returning.  Defaults to current thread unless specified.",
25710b57cec5SDimitry Andric                      nullptr, eStepTypeOut, eStepScopeSource)));
25720b57cec5SDimitry Andric 
25730b57cec5SDimitry Andric   LoadSubCommand("step-over",
25740b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
25750b57cec5SDimitry Andric                      interpreter, "thread step-over",
25760b57cec5SDimitry Andric                      "Source level single step, stepping over calls.  Defaults "
25770b57cec5SDimitry Andric                      "to current thread unless specified.",
25780b57cec5SDimitry Andric                      nullptr, eStepTypeOver, eStepScopeSource)));
25790b57cec5SDimitry Andric 
25800b57cec5SDimitry Andric   LoadSubCommand("step-inst",
25810b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
25820b57cec5SDimitry Andric                      interpreter, "thread step-inst",
25830b57cec5SDimitry Andric                      "Instruction level single step, stepping into calls.  "
25840b57cec5SDimitry Andric                      "Defaults to current thread unless specified.",
25850b57cec5SDimitry Andric                      nullptr, eStepTypeTrace, eStepScopeInstruction)));
25860b57cec5SDimitry Andric 
25870b57cec5SDimitry Andric   LoadSubCommand("step-inst-over",
25880b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
25890b57cec5SDimitry Andric                      interpreter, "thread step-inst-over",
25900b57cec5SDimitry Andric                      "Instruction level single step, stepping over calls.  "
25910b57cec5SDimitry Andric                      "Defaults to current thread unless specified.",
25920b57cec5SDimitry Andric                      nullptr, eStepTypeTraceOver, eStepScopeInstruction)));
25930b57cec5SDimitry Andric 
25940b57cec5SDimitry Andric   LoadSubCommand(
25950b57cec5SDimitry Andric       "step-scripted",
25960b57cec5SDimitry Andric       CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
25970b57cec5SDimitry Andric           interpreter, "thread step-scripted",
25989dba64beSDimitry Andric           "Step as instructed by the script class passed in the -C option.  "
25999dba64beSDimitry Andric           "You can also specify a dictionary of key (-k) and value (-v) pairs "
26009dba64beSDimitry Andric           "that will be used to populate an SBStructuredData Dictionary, which "
26019dba64beSDimitry Andric           "will be passed to the constructor of the class implementing the "
26029dba64beSDimitry Andric           "scripted step.  See the Python Reference for more details.",
26030b57cec5SDimitry Andric           nullptr, eStepTypeScripted, eStepScopeSource)));
26040b57cec5SDimitry Andric 
26050b57cec5SDimitry Andric   LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan(
26060b57cec5SDimitry Andric                              interpreter)));
2607e8d8bef9SDimitry Andric   LoadSubCommand("trace",
2608e8d8bef9SDimitry Andric                  CommandObjectSP(new CommandObjectMultiwordTrace(interpreter)));
26090b57cec5SDimitry Andric }
26100b57cec5SDimitry Andric 
26110b57cec5SDimitry Andric CommandObjectMultiwordThread::~CommandObjectMultiwordThread() = default;
2612