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 
11*5f7ddb14SDimitry Andric #include <memory>
12af732203SDimitry Andric #include <sstream>
13af732203SDimitry Andric 
14af732203SDimitry Andric #include "CommandObjectThreadUtil.h"
15*5f7ddb14SDimitry Andric #include "CommandObjectTrace.h"
16af732203SDimitry Andric #include "lldb/Core/PluginManager.h"
170b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h"
180b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h"
190b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
200b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
210b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
229dba64beSDimitry Andric #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
230b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h"
240b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
250b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
260b57cec5SDimitry Andric #include "lldb/Symbol/LineEntry.h"
270b57cec5SDimitry Andric #include "lldb/Symbol/LineTable.h"
280b57cec5SDimitry Andric #include "lldb/Target/Process.h"
290b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
300b57cec5SDimitry Andric #include "lldb/Target/SystemRuntime.h"
310b57cec5SDimitry Andric #include "lldb/Target/Target.h"
320b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
330b57cec5SDimitry Andric #include "lldb/Target/ThreadPlan.h"
340b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanStepInRange.h"
35af732203SDimitry Andric #include "lldb/Target/Trace.h"
36*5f7ddb14SDimitry Andric #include "lldb/Target/TraceInstructionDumper.h"
370b57cec5SDimitry Andric #include "lldb/Utility/State.h"
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric using namespace lldb;
400b57cec5SDimitry Andric using namespace lldb_private;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric // CommandObjectThreadBacktrace
430b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_backtrace
440b57cec5SDimitry Andric #include "CommandOptions.inc"
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads {
470b57cec5SDimitry Andric public:
480b57cec5SDimitry Andric   class CommandOptions : public Options {
490b57cec5SDimitry Andric   public:
CommandOptions()500b57cec5SDimitry Andric     CommandOptions() : Options() {
510b57cec5SDimitry Andric       // Keep default values of all options in one place: OptionParsingStarting
520b57cec5SDimitry Andric       // ()
530b57cec5SDimitry Andric       OptionParsingStarting(nullptr);
540b57cec5SDimitry Andric     }
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric     ~CommandOptions() override = default;
570b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)580b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
590b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
600b57cec5SDimitry Andric       Status error;
610b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric       switch (short_option) {
640b57cec5SDimitry Andric       case 'c': {
650b57cec5SDimitry Andric         int32_t input_count = 0;
660b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_count)) {
670b57cec5SDimitry Andric           m_count = UINT32_MAX;
680b57cec5SDimitry Andric           error.SetErrorStringWithFormat(
690b57cec5SDimitry Andric               "invalid integer value for option '%c'", short_option);
700b57cec5SDimitry Andric         } else if (input_count < 0)
710b57cec5SDimitry Andric           m_count = UINT32_MAX;
720b57cec5SDimitry Andric       } break;
730b57cec5SDimitry Andric       case 's':
740b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_start))
750b57cec5SDimitry Andric           error.SetErrorStringWithFormat(
760b57cec5SDimitry Andric               "invalid integer value for option '%c'", short_option);
770b57cec5SDimitry Andric         break;
780b57cec5SDimitry Andric       case 'e': {
790b57cec5SDimitry Andric         bool success;
800b57cec5SDimitry Andric         m_extended_backtrace =
810b57cec5SDimitry Andric             OptionArgParser::ToBoolean(option_arg, false, &success);
820b57cec5SDimitry Andric         if (!success)
830b57cec5SDimitry Andric           error.SetErrorStringWithFormat(
840b57cec5SDimitry Andric               "invalid boolean value for option '%c'", short_option);
850b57cec5SDimitry Andric       } break;
860b57cec5SDimitry Andric       default:
879dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
880b57cec5SDimitry Andric       }
890b57cec5SDimitry Andric       return error;
900b57cec5SDimitry Andric     }
910b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)920b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
930b57cec5SDimitry Andric       m_count = UINT32_MAX;
940b57cec5SDimitry Andric       m_start = 0;
950b57cec5SDimitry Andric       m_extended_backtrace = false;
960b57cec5SDimitry Andric     }
970b57cec5SDimitry Andric 
GetDefinitions()980b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
990b57cec5SDimitry Andric       return llvm::makeArrayRef(g_thread_backtrace_options);
1000b57cec5SDimitry Andric     }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
1030b57cec5SDimitry Andric     uint32_t m_count;
1040b57cec5SDimitry Andric     uint32_t m_start;
1050b57cec5SDimitry Andric     bool m_extended_backtrace;
1060b57cec5SDimitry Andric   };
1070b57cec5SDimitry Andric 
CommandObjectThreadBacktrace(CommandInterpreter & interpreter)1080b57cec5SDimitry Andric   CommandObjectThreadBacktrace(CommandInterpreter &interpreter)
1090b57cec5SDimitry Andric       : CommandObjectIterateOverThreads(
1100b57cec5SDimitry Andric             interpreter, "thread backtrace",
1110b57cec5SDimitry Andric             "Show thread call stacks.  Defaults to the current thread, thread "
1120b57cec5SDimitry Andric             "indexes can be specified as arguments.\n"
1130b57cec5SDimitry Andric             "Use the thread-index \"all\" to see all threads.\n"
1140b57cec5SDimitry Andric             "Use the thread-index \"unique\" to see threads grouped by unique "
1150b57cec5SDimitry Andric             "call stacks.\n"
1160b57cec5SDimitry Andric             "Use 'settings set frame-format' to customize the printing of "
1170b57cec5SDimitry Andric             "frames in the backtrace and 'settings set thread-format' to "
1180b57cec5SDimitry Andric             "customize the thread header.",
1190b57cec5SDimitry Andric             nullptr,
1200b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandRequiresThread |
1210b57cec5SDimitry Andric                 eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
1220b57cec5SDimitry Andric                 eCommandProcessMustBePaused),
1230b57cec5SDimitry Andric         m_options() {}
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   ~CommandObjectThreadBacktrace() override = default;
1260b57cec5SDimitry Andric 
GetOptions()1270b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric protected:
DoExtendedBacktrace(Thread * thread,CommandReturnObject & result)1300b57cec5SDimitry Andric   void DoExtendedBacktrace(Thread *thread, CommandReturnObject &result) {
1310b57cec5SDimitry Andric     SystemRuntime *runtime = thread->GetProcess()->GetSystemRuntime();
1320b57cec5SDimitry Andric     if (runtime) {
1330b57cec5SDimitry Andric       Stream &strm = result.GetOutputStream();
1340b57cec5SDimitry Andric       const std::vector<ConstString> &types =
1350b57cec5SDimitry Andric           runtime->GetExtendedBacktraceTypes();
1360b57cec5SDimitry Andric       for (auto type : types) {
1370b57cec5SDimitry Andric         ThreadSP ext_thread_sp = runtime->GetExtendedBacktraceThread(
1380b57cec5SDimitry Andric             thread->shared_from_this(), type);
1390b57cec5SDimitry Andric         if (ext_thread_sp && ext_thread_sp->IsValid()) {
1400b57cec5SDimitry Andric           const uint32_t num_frames_with_source = 0;
1410b57cec5SDimitry Andric           const bool stop_format = false;
1420b57cec5SDimitry Andric           if (ext_thread_sp->GetStatus(strm, m_options.m_start,
1430b57cec5SDimitry Andric                                        m_options.m_count,
144480093f4SDimitry Andric                                        num_frames_with_source, stop_format)) {
1450b57cec5SDimitry Andric             DoExtendedBacktrace(ext_thread_sp.get(), result);
1460b57cec5SDimitry Andric           }
1470b57cec5SDimitry Andric         }
1480b57cec5SDimitry Andric       }
1490b57cec5SDimitry Andric     }
1500b57cec5SDimitry Andric   }
1510b57cec5SDimitry Andric 
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)1520b57cec5SDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
1530b57cec5SDimitry Andric     ThreadSP thread_sp =
1540b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
1550b57cec5SDimitry Andric     if (!thread_sp) {
1560b57cec5SDimitry Andric       result.AppendErrorWithFormat(
1570b57cec5SDimitry Andric           "thread disappeared while computing backtraces: 0x%" PRIx64 "\n",
1580b57cec5SDimitry Andric           tid);
1590b57cec5SDimitry Andric       return false;
1600b57cec5SDimitry Andric     }
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric     Thread *thread = thread_sp.get();
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric     Stream &strm = result.GetOutputStream();
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric     // Only dump stack info if we processing unique stacks.
1670b57cec5SDimitry Andric     const bool only_stacks = m_unique_stacks;
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric     // Don't show source context when doing backtraces.
1700b57cec5SDimitry Andric     const uint32_t num_frames_with_source = 0;
1710b57cec5SDimitry Andric     const bool stop_format = true;
1720b57cec5SDimitry Andric     if (!thread->GetStatus(strm, m_options.m_start, m_options.m_count,
1730b57cec5SDimitry Andric                            num_frames_with_source, stop_format, only_stacks)) {
1740b57cec5SDimitry Andric       result.AppendErrorWithFormat(
1750b57cec5SDimitry Andric           "error displaying backtrace for thread: \"0x%4.4x\"\n",
1760b57cec5SDimitry Andric           thread->GetIndexID());
1770b57cec5SDimitry Andric       return false;
1780b57cec5SDimitry Andric     }
1790b57cec5SDimitry Andric     if (m_options.m_extended_backtrace) {
1800b57cec5SDimitry Andric       DoExtendedBacktrace(thread, result);
1810b57cec5SDimitry Andric     }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric     return true;
1840b57cec5SDimitry Andric   }
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   CommandOptions m_options;
1870b57cec5SDimitry Andric };
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric enum StepScope { eStepScopeSource, eStepScopeInstruction };
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric static constexpr OptionEnumValueElement g_tri_running_mode[] = {
1920b57cec5SDimitry Andric     {eOnlyThisThread, "this-thread", "Run only this thread"},
1930b57cec5SDimitry Andric     {eAllThreads, "all-threads", "Run all threads"},
1940b57cec5SDimitry Andric     {eOnlyDuringStepping, "while-stepping",
1950b57cec5SDimitry Andric      "Run only this thread while stepping"}};
1960b57cec5SDimitry Andric 
TriRunningModes()1970b57cec5SDimitry Andric static constexpr OptionEnumValues TriRunningModes() {
1980b57cec5SDimitry Andric   return OptionEnumValues(g_tri_running_mode);
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_step_scope
2020b57cec5SDimitry Andric #include "CommandOptions.inc"
2030b57cec5SDimitry Andric 
2049dba64beSDimitry Andric class ThreadStepScopeOptionGroup : public OptionGroup {
2050b57cec5SDimitry Andric public:
ThreadStepScopeOptionGroup()2069dba64beSDimitry Andric   ThreadStepScopeOptionGroup() : OptionGroup() {
2070b57cec5SDimitry Andric     // Keep default values of all options in one place: OptionParsingStarting
2080b57cec5SDimitry Andric     // ()
2090b57cec5SDimitry Andric     OptionParsingStarting(nullptr);
2100b57cec5SDimitry Andric   }
2110b57cec5SDimitry Andric 
2129dba64beSDimitry Andric   ~ThreadStepScopeOptionGroup() override = default;
2139dba64beSDimitry Andric 
GetDefinitions()2149dba64beSDimitry Andric   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2159dba64beSDimitry Andric     return llvm::makeArrayRef(g_thread_step_scope_options);
2169dba64beSDimitry Andric   }
2170b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2180b57cec5SDimitry Andric   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2190b57cec5SDimitry Andric                         ExecutionContext *execution_context) override {
2200b57cec5SDimitry Andric     Status error;
221480093f4SDimitry Andric     const int short_option =
222480093f4SDimitry Andric         g_thread_step_scope_options[option_idx].short_option;
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric     switch (short_option) {
2250b57cec5SDimitry Andric     case 'a': {
2260b57cec5SDimitry Andric       bool success;
2270b57cec5SDimitry Andric       bool avoid_no_debug =
2280b57cec5SDimitry Andric           OptionArgParser::ToBoolean(option_arg, true, &success);
2290b57cec5SDimitry Andric       if (!success)
230480093f4SDimitry Andric         error.SetErrorStringWithFormat("invalid boolean value for option '%c'",
231480093f4SDimitry Andric                                        short_option);
2320b57cec5SDimitry Andric       else {
233480093f4SDimitry Andric         m_step_in_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
2340b57cec5SDimitry Andric       }
2350b57cec5SDimitry Andric     } break;
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric     case 'A': {
2380b57cec5SDimitry Andric       bool success;
2390b57cec5SDimitry Andric       bool avoid_no_debug =
2400b57cec5SDimitry Andric           OptionArgParser::ToBoolean(option_arg, true, &success);
2410b57cec5SDimitry Andric       if (!success)
242480093f4SDimitry Andric         error.SetErrorStringWithFormat("invalid boolean value for option '%c'",
243480093f4SDimitry Andric                                        short_option);
2440b57cec5SDimitry Andric       else {
245480093f4SDimitry Andric         m_step_out_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;
2460b57cec5SDimitry Andric       }
2470b57cec5SDimitry Andric     } break;
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric     case 'c':
2500b57cec5SDimitry Andric       if (option_arg.getAsInteger(0, m_step_count))
2510b57cec5SDimitry Andric         error.SetErrorStringWithFormat("invalid step count '%s'",
2520b57cec5SDimitry Andric                                        option_arg.str().c_str());
2530b57cec5SDimitry Andric       break;
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric     case 'm': {
2560b57cec5SDimitry Andric       auto enum_values = GetDefinitions()[option_idx].enum_values;
2570b57cec5SDimitry Andric       m_run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(
2580b57cec5SDimitry Andric           option_arg, enum_values, eOnlyDuringStepping, error);
2590b57cec5SDimitry Andric     } break;
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric     case 'e':
2620b57cec5SDimitry Andric       if (option_arg == "block") {
2630b57cec5SDimitry Andric         m_end_line_is_block_end = true;
2640b57cec5SDimitry Andric         break;
2650b57cec5SDimitry Andric       }
2660b57cec5SDimitry Andric       if (option_arg.getAsInteger(0, m_end_line))
2670b57cec5SDimitry Andric         error.SetErrorStringWithFormat("invalid end line number '%s'",
2680b57cec5SDimitry Andric                                        option_arg.str().c_str());
2690b57cec5SDimitry Andric       break;
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric     case 'r':
2720b57cec5SDimitry Andric       m_avoid_regexp.clear();
2735ffd83dbSDimitry Andric       m_avoid_regexp.assign(std::string(option_arg));
2740b57cec5SDimitry Andric       break;
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric     case 't':
2770b57cec5SDimitry Andric       m_step_in_target.clear();
2785ffd83dbSDimitry Andric       m_step_in_target.assign(std::string(option_arg));
2790b57cec5SDimitry Andric       break;
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric     default:
2829dba64beSDimitry Andric       llvm_unreachable("Unimplemented option");
2830b57cec5SDimitry Andric     }
2840b57cec5SDimitry Andric     return error;
2850b57cec5SDimitry Andric   }
2860b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)2870b57cec5SDimitry Andric   void OptionParsingStarting(ExecutionContext *execution_context) override {
2880b57cec5SDimitry Andric     m_step_in_avoid_no_debug = eLazyBoolCalculate;
2890b57cec5SDimitry Andric     m_step_out_avoid_no_debug = eLazyBoolCalculate;
2900b57cec5SDimitry Andric     m_run_mode = eOnlyDuringStepping;
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric     // Check if we are in Non-Stop mode
2930b57cec5SDimitry Andric     TargetSP target_sp =
2940b57cec5SDimitry Andric         execution_context ? execution_context->GetTargetSP() : TargetSP();
295af732203SDimitry Andric     if (target_sp && target_sp->GetNonStopModeEnabled()) {
296af732203SDimitry Andric       // NonStopMode runs all threads by definition, so when it is on we don't
297af732203SDimitry Andric       // need to check the process setting for runs all threads.
2980b57cec5SDimitry Andric       m_run_mode = eOnlyThisThread;
299af732203SDimitry Andric     } else {
300af732203SDimitry Andric       ProcessSP process_sp =
301af732203SDimitry Andric           execution_context ? execution_context->GetProcessSP() : ProcessSP();
302af732203SDimitry Andric       if (process_sp && process_sp->GetSteppingRunsAllThreads())
303af732203SDimitry Andric         m_run_mode = eAllThreads;
304af732203SDimitry Andric     }
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric     m_avoid_regexp.clear();
3070b57cec5SDimitry Andric     m_step_in_target.clear();
3080b57cec5SDimitry Andric     m_step_count = 1;
3090b57cec5SDimitry Andric     m_end_line = LLDB_INVALID_LINE_NUMBER;
3100b57cec5SDimitry Andric     m_end_line_is_block_end = false;
3110b57cec5SDimitry Andric   }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   // Instance variables to hold the values for command options.
3140b57cec5SDimitry Andric   LazyBool m_step_in_avoid_no_debug;
3150b57cec5SDimitry Andric   LazyBool m_step_out_avoid_no_debug;
3160b57cec5SDimitry Andric   RunMode m_run_mode;
3170b57cec5SDimitry Andric   std::string m_avoid_regexp;
3180b57cec5SDimitry Andric   std::string m_step_in_target;
3190b57cec5SDimitry Andric   uint32_t m_step_count;
3200b57cec5SDimitry Andric   uint32_t m_end_line;
3210b57cec5SDimitry Andric   bool m_end_line_is_block_end;
3220b57cec5SDimitry Andric };
3230b57cec5SDimitry Andric 
3249dba64beSDimitry Andric class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed {
3259dba64beSDimitry Andric public:
CommandObjectThreadStepWithTypeAndScope(CommandInterpreter & interpreter,const char * name,const char * help,const char * syntax,StepType step_type,StepScope step_scope)3260b57cec5SDimitry Andric   CommandObjectThreadStepWithTypeAndScope(CommandInterpreter &interpreter,
3270b57cec5SDimitry Andric                                           const char *name, const char *help,
3280b57cec5SDimitry Andric                                           const char *syntax,
3290b57cec5SDimitry Andric                                           StepType step_type,
3300b57cec5SDimitry Andric                                           StepScope step_scope)
3310b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, name, help, syntax,
3320b57cec5SDimitry Andric                             eCommandRequiresProcess | eCommandRequiresThread |
3330b57cec5SDimitry Andric                                 eCommandTryTargetAPILock |
3340b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched |
3350b57cec5SDimitry Andric                                 eCommandProcessMustBePaused),
3369dba64beSDimitry Andric         m_step_type(step_type), m_step_scope(step_scope), m_options(),
337480093f4SDimitry Andric         m_class_options("scripted step") {
3380b57cec5SDimitry Andric     CommandArgumentEntry arg;
3390b57cec5SDimitry Andric     CommandArgumentData thread_id_arg;
3400b57cec5SDimitry Andric 
3410b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
3420b57cec5SDimitry Andric     thread_id_arg.arg_type = eArgTypeThreadID;
3430b57cec5SDimitry Andric     thread_id_arg.arg_repetition = eArgRepeatOptional;
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
3460b57cec5SDimitry Andric     // argument entry.
3470b57cec5SDimitry Andric     arg.push_back(thread_id_arg);
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
3500b57cec5SDimitry Andric     m_arguments.push_back(arg);
3519dba64beSDimitry Andric 
3529dba64beSDimitry Andric     if (step_type == eStepTypeScripted) {
353480093f4SDimitry Andric       m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
354480093f4SDimitry Andric                            LLDB_OPT_SET_1);
3559dba64beSDimitry Andric     }
3569dba64beSDimitry Andric     m_all_options.Append(&m_options);
3579dba64beSDimitry Andric     m_all_options.Finalize();
3580b57cec5SDimitry Andric   }
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric   ~CommandObjectThreadStepWithTypeAndScope() override = default;
3610b57cec5SDimitry Andric 
362af732203SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)363af732203SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
364af732203SDimitry Andric                            OptionElementVector &opt_element_vector) override {
365af732203SDimitry Andric     if (request.GetCursorIndex())
366af732203SDimitry Andric       return;
367af732203SDimitry Andric 
368af732203SDimitry Andric     CommandCompletions::InvokeCommonCompletionCallbacks(
369af732203SDimitry Andric         GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion,
370af732203SDimitry Andric         request, nullptr);
371af732203SDimitry Andric   }
372af732203SDimitry Andric 
GetOptions()373480093f4SDimitry Andric   Options *GetOptions() override { return &m_all_options; }
3740b57cec5SDimitry Andric 
3750b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)3760b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
3770b57cec5SDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
3780b57cec5SDimitry Andric     bool synchronous_execution = m_interpreter.GetSynchronous();
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric     const uint32_t num_threads = process->GetThreadList().GetSize();
3810b57cec5SDimitry Andric     Thread *thread = nullptr;
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric     if (command.GetArgumentCount() == 0) {
3840b57cec5SDimitry Andric       thread = GetDefaultThread();
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric       if (thread == nullptr) {
3870b57cec5SDimitry Andric         result.AppendError("no selected thread in process");
3880b57cec5SDimitry Andric         return false;
3890b57cec5SDimitry Andric       }
3900b57cec5SDimitry Andric     } else {
3910b57cec5SDimitry Andric       const char *thread_idx_cstr = command.GetArgumentAtIndex(0);
3925ffd83dbSDimitry Andric       uint32_t step_thread_idx;
3935ffd83dbSDimitry Andric 
3945ffd83dbSDimitry Andric       if (!llvm::to_integer(thread_idx_cstr, step_thread_idx)) {
3950b57cec5SDimitry Andric         result.AppendErrorWithFormat("invalid thread index '%s'.\n",
3960b57cec5SDimitry Andric                                      thread_idx_cstr);
3970b57cec5SDimitry Andric         return false;
3980b57cec5SDimitry Andric       }
3990b57cec5SDimitry Andric       thread =
4000b57cec5SDimitry Andric           process->GetThreadList().FindThreadByIndexID(step_thread_idx).get();
4010b57cec5SDimitry Andric       if (thread == nullptr) {
4020b57cec5SDimitry Andric         result.AppendErrorWithFormat(
4030b57cec5SDimitry Andric             "Thread index %u is out of range (valid values are 0 - %u).\n",
4040b57cec5SDimitry Andric             step_thread_idx, num_threads);
4050b57cec5SDimitry Andric         return false;
4060b57cec5SDimitry Andric       }
4070b57cec5SDimitry Andric     }
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric     if (m_step_type == eStepTypeScripted) {
410480093f4SDimitry Andric       if (m_class_options.GetName().empty()) {
4110b57cec5SDimitry Andric         result.AppendErrorWithFormat("empty class name for scripted step.");
4120b57cec5SDimitry Andric         return false;
4130b57cec5SDimitry Andric       } else if (!GetDebugger().GetScriptInterpreter()->CheckObjectExists(
414480093f4SDimitry Andric                      m_class_options.GetName().c_str())) {
4150b57cec5SDimitry Andric         result.AppendErrorWithFormat(
4160b57cec5SDimitry Andric             "class for scripted step: \"%s\" does not exist.",
417480093f4SDimitry Andric             m_class_options.GetName().c_str());
4180b57cec5SDimitry Andric         return false;
4190b57cec5SDimitry Andric       }
4200b57cec5SDimitry Andric     }
4210b57cec5SDimitry Andric 
4220b57cec5SDimitry Andric     if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER &&
4230b57cec5SDimitry Andric         m_step_type != eStepTypeInto) {
4240b57cec5SDimitry Andric       result.AppendErrorWithFormat(
4250b57cec5SDimitry Andric           "end line option is only valid for step into");
4260b57cec5SDimitry Andric       return false;
4270b57cec5SDimitry Andric     }
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric     const bool abort_other_plans = false;
4300b57cec5SDimitry Andric     const lldb::RunMode stop_other_threads = m_options.m_run_mode;
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric     // This is a bit unfortunate, but not all the commands in this command
4330b57cec5SDimitry Andric     // object support only while stepping, so I use the bool for them.
4340b57cec5SDimitry Andric     bool bool_stop_other_threads;
4350b57cec5SDimitry Andric     if (m_options.m_run_mode == eAllThreads)
4360b57cec5SDimitry Andric       bool_stop_other_threads = false;
4370b57cec5SDimitry Andric     else if (m_options.m_run_mode == eOnlyDuringStepping)
438af732203SDimitry Andric       bool_stop_other_threads = (m_step_type != eStepTypeOut);
4390b57cec5SDimitry Andric     else
4400b57cec5SDimitry Andric       bool_stop_other_threads = true;
4410b57cec5SDimitry Andric 
4420b57cec5SDimitry Andric     ThreadPlanSP new_plan_sp;
4430b57cec5SDimitry Andric     Status new_plan_status;
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric     if (m_step_type == eStepTypeInto) {
4460b57cec5SDimitry Andric       StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
4470b57cec5SDimitry Andric       assert(frame != nullptr);
4480b57cec5SDimitry Andric 
4490b57cec5SDimitry Andric       if (frame->HasDebugInformation()) {
4500b57cec5SDimitry Andric         AddressRange range;
4510b57cec5SDimitry Andric         SymbolContext sc = frame->GetSymbolContext(eSymbolContextEverything);
4520b57cec5SDimitry Andric         if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER) {
4530b57cec5SDimitry Andric           Status error;
4540b57cec5SDimitry Andric           if (!sc.GetAddressRangeFromHereToEndLine(m_options.m_end_line, range,
4550b57cec5SDimitry Andric                                                    error)) {
4560b57cec5SDimitry Andric             result.AppendErrorWithFormat("invalid end-line option: %s.",
4570b57cec5SDimitry Andric                                          error.AsCString());
4580b57cec5SDimitry Andric             return false;
4590b57cec5SDimitry Andric           }
4600b57cec5SDimitry Andric         } else if (m_options.m_end_line_is_block_end) {
4610b57cec5SDimitry Andric           Status error;
4620b57cec5SDimitry Andric           Block *block = frame->GetSymbolContext(eSymbolContextBlock).block;
4630b57cec5SDimitry Andric           if (!block) {
4640b57cec5SDimitry Andric             result.AppendErrorWithFormat("Could not find the current block.");
4650b57cec5SDimitry Andric             return false;
4660b57cec5SDimitry Andric           }
4670b57cec5SDimitry Andric 
4680b57cec5SDimitry Andric           AddressRange block_range;
4690b57cec5SDimitry Andric           Address pc_address = frame->GetFrameCodeAddress();
4700b57cec5SDimitry Andric           block->GetRangeContainingAddress(pc_address, block_range);
4710b57cec5SDimitry Andric           if (!block_range.GetBaseAddress().IsValid()) {
4720b57cec5SDimitry Andric             result.AppendErrorWithFormat(
4730b57cec5SDimitry Andric                 "Could not find the current block address.");
4740b57cec5SDimitry Andric             return false;
4750b57cec5SDimitry Andric           }
4760b57cec5SDimitry Andric           lldb::addr_t pc_offset_in_block =
4770b57cec5SDimitry Andric               pc_address.GetFileAddress() -
4780b57cec5SDimitry Andric               block_range.GetBaseAddress().GetFileAddress();
4790b57cec5SDimitry Andric           lldb::addr_t range_length =
4800b57cec5SDimitry Andric               block_range.GetByteSize() - pc_offset_in_block;
4810b57cec5SDimitry Andric           range = AddressRange(pc_address, range_length);
4820b57cec5SDimitry Andric         } else {
4830b57cec5SDimitry Andric           range = sc.line_entry.range;
4840b57cec5SDimitry Andric         }
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric         new_plan_sp = thread->QueueThreadPlanForStepInRange(
4870b57cec5SDimitry Andric             abort_other_plans, range,
4880b57cec5SDimitry Andric             frame->GetSymbolContext(eSymbolContextEverything),
4890b57cec5SDimitry Andric             m_options.m_step_in_target.c_str(), stop_other_threads,
4900b57cec5SDimitry Andric             new_plan_status, m_options.m_step_in_avoid_no_debug,
4910b57cec5SDimitry Andric             m_options.m_step_out_avoid_no_debug);
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric         if (new_plan_sp && !m_options.m_avoid_regexp.empty()) {
4940b57cec5SDimitry Andric           ThreadPlanStepInRange *step_in_range_plan =
4950b57cec5SDimitry Andric               static_cast<ThreadPlanStepInRange *>(new_plan_sp.get());
4960b57cec5SDimitry Andric           step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str());
4970b57cec5SDimitry Andric         }
4980b57cec5SDimitry Andric       } else
4990b57cec5SDimitry Andric         new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
5000b57cec5SDimitry Andric             false, abort_other_plans, bool_stop_other_threads, new_plan_status);
5010b57cec5SDimitry Andric     } else if (m_step_type == eStepTypeOver) {
5020b57cec5SDimitry Andric       StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
5030b57cec5SDimitry Andric 
5040b57cec5SDimitry Andric       if (frame->HasDebugInformation())
5050b57cec5SDimitry Andric         new_plan_sp = thread->QueueThreadPlanForStepOverRange(
5060b57cec5SDimitry Andric             abort_other_plans,
5070b57cec5SDimitry Andric             frame->GetSymbolContext(eSymbolContextEverything).line_entry,
5080b57cec5SDimitry Andric             frame->GetSymbolContext(eSymbolContextEverything),
5090b57cec5SDimitry Andric             stop_other_threads, new_plan_status,
5100b57cec5SDimitry Andric             m_options.m_step_out_avoid_no_debug);
5110b57cec5SDimitry Andric       else
5120b57cec5SDimitry Andric         new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
5130b57cec5SDimitry Andric             true, abort_other_plans, bool_stop_other_threads, new_plan_status);
5140b57cec5SDimitry Andric     } else if (m_step_type == eStepTypeTrace) {
5150b57cec5SDimitry Andric       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
5160b57cec5SDimitry Andric           false, abort_other_plans, bool_stop_other_threads, new_plan_status);
5170b57cec5SDimitry Andric     } else if (m_step_type == eStepTypeTraceOver) {
5180b57cec5SDimitry Andric       new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(
5190b57cec5SDimitry Andric           true, abort_other_plans, bool_stop_other_threads, new_plan_status);
5200b57cec5SDimitry Andric     } else if (m_step_type == eStepTypeOut) {
5210b57cec5SDimitry Andric       new_plan_sp = thread->QueueThreadPlanForStepOut(
5220b57cec5SDimitry Andric           abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes,
5230b57cec5SDimitry Andric           eVoteNoOpinion, thread->GetSelectedFrameIndex(), new_plan_status,
5240b57cec5SDimitry Andric           m_options.m_step_out_avoid_no_debug);
5250b57cec5SDimitry Andric     } else if (m_step_type == eStepTypeScripted) {
5260b57cec5SDimitry Andric       new_plan_sp = thread->QueueThreadPlanForStepScripted(
527480093f4SDimitry Andric           abort_other_plans, m_class_options.GetName().c_str(),
528480093f4SDimitry Andric           m_class_options.GetStructuredData(), bool_stop_other_threads,
529480093f4SDimitry Andric           new_plan_status);
5300b57cec5SDimitry Andric     } else {
5310b57cec5SDimitry Andric       result.AppendError("step type is not supported");
5320b57cec5SDimitry Andric       return false;
5330b57cec5SDimitry Andric     }
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric     // If we got a new plan, then set it to be a master plan (User level Plans
5360b57cec5SDimitry Andric     // should be master plans so that they can be interruptible).  Then resume
5370b57cec5SDimitry Andric     // the process.
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric     if (new_plan_sp) {
5400b57cec5SDimitry Andric       new_plan_sp->SetIsMasterPlan(true);
5410b57cec5SDimitry Andric       new_plan_sp->SetOkayToDiscard(false);
5420b57cec5SDimitry Andric 
5430b57cec5SDimitry Andric       if (m_options.m_step_count > 1) {
5440b57cec5SDimitry Andric         if (!new_plan_sp->SetIterationCount(m_options.m_step_count)) {
5450b57cec5SDimitry Andric           result.AppendWarning(
5460b57cec5SDimitry Andric               "step operation does not support iteration count.");
5470b57cec5SDimitry Andric         }
5480b57cec5SDimitry Andric       }
5490b57cec5SDimitry Andric 
5500b57cec5SDimitry Andric       process->GetThreadList().SetSelectedThreadByID(thread->GetID());
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric       const uint32_t iohandler_id = process->GetIOHandlerID();
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric       StreamString stream;
5550b57cec5SDimitry Andric       Status error;
5560b57cec5SDimitry Andric       if (synchronous_execution)
5570b57cec5SDimitry Andric         error = process->ResumeSynchronous(&stream);
5580b57cec5SDimitry Andric       else
5590b57cec5SDimitry Andric         error = process->Resume();
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric       if (!error.Success()) {
5620b57cec5SDimitry Andric         result.AppendMessage(error.AsCString());
5630b57cec5SDimitry Andric         return false;
5640b57cec5SDimitry Andric       }
5650b57cec5SDimitry Andric 
5660b57cec5SDimitry Andric       // There is a race condition where this thread will return up the call
5670b57cec5SDimitry Andric       // stack to the main command handler and show an (lldb) prompt before
5680b57cec5SDimitry Andric       // HandlePrivateEvent (from PrivateStateThread) has a chance to call
5690b57cec5SDimitry Andric       // PushProcessIOHandler().
5700b57cec5SDimitry Andric       process->SyncIOHandler(iohandler_id, std::chrono::seconds(2));
5710b57cec5SDimitry Andric 
5720b57cec5SDimitry Andric       if (synchronous_execution) {
5730b57cec5SDimitry Andric         // If any state changed events had anything to say, add that to the
5740b57cec5SDimitry Andric         // result
5750b57cec5SDimitry Andric         if (stream.GetSize() > 0)
5760b57cec5SDimitry Andric           result.AppendMessage(stream.GetString());
5770b57cec5SDimitry Andric 
5780b57cec5SDimitry Andric         process->GetThreadList().SetSelectedThreadByID(thread->GetID());
5790b57cec5SDimitry Andric         result.SetDidChangeProcessState(true);
5800b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessFinishNoResult);
5810b57cec5SDimitry Andric       } else {
5820b57cec5SDimitry Andric         result.SetStatus(eReturnStatusSuccessContinuingNoResult);
5830b57cec5SDimitry Andric       }
5840b57cec5SDimitry Andric     } else {
5850b57cec5SDimitry Andric       result.SetError(new_plan_status);
5860b57cec5SDimitry Andric     }
5870b57cec5SDimitry Andric     return result.Succeeded();
5880b57cec5SDimitry Andric   }
5890b57cec5SDimitry Andric 
5900b57cec5SDimitry Andric   StepType m_step_type;
5910b57cec5SDimitry Andric   StepScope m_step_scope;
5929dba64beSDimitry Andric   ThreadStepScopeOptionGroup m_options;
5939dba64beSDimitry Andric   OptionGroupPythonClassWithDict m_class_options;
5949dba64beSDimitry Andric   OptionGroupOptions m_all_options;
5950b57cec5SDimitry Andric };
5960b57cec5SDimitry Andric 
5970b57cec5SDimitry Andric // CommandObjectThreadContinue
5980b57cec5SDimitry Andric 
5990b57cec5SDimitry Andric class CommandObjectThreadContinue : public CommandObjectParsed {
6000b57cec5SDimitry Andric public:
CommandObjectThreadContinue(CommandInterpreter & interpreter)6010b57cec5SDimitry Andric   CommandObjectThreadContinue(CommandInterpreter &interpreter)
6020b57cec5SDimitry Andric       : CommandObjectParsed(
6030b57cec5SDimitry Andric             interpreter, "thread continue",
6040b57cec5SDimitry Andric             "Continue execution of the current target process.  One "
6050b57cec5SDimitry Andric             "or more threads may be specified, by default all "
6060b57cec5SDimitry Andric             "threads continue.",
6070b57cec5SDimitry Andric             nullptr,
6080b57cec5SDimitry Andric             eCommandRequiresThread | eCommandTryTargetAPILock |
6090b57cec5SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
6100b57cec5SDimitry Andric     CommandArgumentEntry arg;
6110b57cec5SDimitry Andric     CommandArgumentData thread_idx_arg;
6120b57cec5SDimitry Andric 
6130b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
6140b57cec5SDimitry Andric     thread_idx_arg.arg_type = eArgTypeThreadIndex;
6150b57cec5SDimitry Andric     thread_idx_arg.arg_repetition = eArgRepeatPlus;
6160b57cec5SDimitry Andric 
6170b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
6180b57cec5SDimitry Andric     // argument entry.
6190b57cec5SDimitry Andric     arg.push_back(thread_idx_arg);
6200b57cec5SDimitry Andric 
6210b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
6220b57cec5SDimitry Andric     m_arguments.push_back(arg);
6230b57cec5SDimitry Andric   }
6240b57cec5SDimitry Andric 
6250b57cec5SDimitry Andric   ~CommandObjectThreadContinue() override = default;
6260b57cec5SDimitry Andric 
627af732203SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)628af732203SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
629af732203SDimitry Andric                            OptionElementVector &opt_element_vector) override {
630af732203SDimitry Andric     CommandCompletions::InvokeCommonCompletionCallbacks(
631af732203SDimitry Andric         GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion,
632af732203SDimitry Andric         request, nullptr);
633af732203SDimitry Andric   }
634af732203SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)6350b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
6360b57cec5SDimitry Andric     bool synchronous_execution = m_interpreter.GetSynchronous();
6370b57cec5SDimitry Andric 
6380b57cec5SDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
6390b57cec5SDimitry Andric     if (process == nullptr) {
6400b57cec5SDimitry Andric       result.AppendError("no process exists. Cannot continue");
6410b57cec5SDimitry Andric       return false;
6420b57cec5SDimitry Andric     }
6430b57cec5SDimitry Andric 
6440b57cec5SDimitry Andric     StateType state = process->GetState();
6450b57cec5SDimitry Andric     if ((state == eStateCrashed) || (state == eStateStopped) ||
6460b57cec5SDimitry Andric         (state == eStateSuspended)) {
6470b57cec5SDimitry Andric       const size_t argc = command.GetArgumentCount();
6480b57cec5SDimitry Andric       if (argc > 0) {
6490b57cec5SDimitry Andric         // These two lines appear at the beginning of both blocks in this
6500b57cec5SDimitry Andric         // if..else, but that is because we need to release the lock before
6510b57cec5SDimitry Andric         // calling process->Resume below.
6520b57cec5SDimitry Andric         std::lock_guard<std::recursive_mutex> guard(
6530b57cec5SDimitry Andric             process->GetThreadList().GetMutex());
6540b57cec5SDimitry Andric         const uint32_t num_threads = process->GetThreadList().GetSize();
6550b57cec5SDimitry Andric         std::vector<Thread *> resume_threads;
6560b57cec5SDimitry Andric         for (auto &entry : command.entries()) {
6570b57cec5SDimitry Andric           uint32_t thread_idx;
6589dba64beSDimitry Andric           if (entry.ref().getAsInteger(0, thread_idx)) {
6590b57cec5SDimitry Andric             result.AppendErrorWithFormat(
6600b57cec5SDimitry Andric                 "invalid thread index argument: \"%s\".\n", entry.c_str());
6610b57cec5SDimitry Andric             return false;
6620b57cec5SDimitry Andric           }
6630b57cec5SDimitry Andric           Thread *thread =
6640b57cec5SDimitry Andric               process->GetThreadList().FindThreadByIndexID(thread_idx).get();
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric           if (thread) {
6670b57cec5SDimitry Andric             resume_threads.push_back(thread);
6680b57cec5SDimitry Andric           } else {
6690b57cec5SDimitry Andric             result.AppendErrorWithFormat("invalid thread index %u.\n",
6700b57cec5SDimitry Andric                                          thread_idx);
6710b57cec5SDimitry Andric             return false;
6720b57cec5SDimitry Andric           }
6730b57cec5SDimitry Andric         }
6740b57cec5SDimitry Andric 
6750b57cec5SDimitry Andric         if (resume_threads.empty()) {
6760b57cec5SDimitry Andric           result.AppendError("no valid thread indexes were specified");
6770b57cec5SDimitry Andric           return false;
6780b57cec5SDimitry Andric         } else {
6790b57cec5SDimitry Andric           if (resume_threads.size() == 1)
6800b57cec5SDimitry Andric             result.AppendMessageWithFormat("Resuming thread: ");
6810b57cec5SDimitry Andric           else
6820b57cec5SDimitry Andric             result.AppendMessageWithFormat("Resuming threads: ");
6830b57cec5SDimitry Andric 
6840b57cec5SDimitry Andric           for (uint32_t idx = 0; idx < num_threads; ++idx) {
6850b57cec5SDimitry Andric             Thread *thread =
6860b57cec5SDimitry Andric                 process->GetThreadList().GetThreadAtIndex(idx).get();
6870b57cec5SDimitry Andric             std::vector<Thread *>::iterator this_thread_pos =
6880b57cec5SDimitry Andric                 find(resume_threads.begin(), resume_threads.end(), thread);
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric             if (this_thread_pos != resume_threads.end()) {
6910b57cec5SDimitry Andric               resume_threads.erase(this_thread_pos);
6920b57cec5SDimitry Andric               if (!resume_threads.empty())
6930b57cec5SDimitry Andric                 result.AppendMessageWithFormat("%u, ", thread->GetIndexID());
6940b57cec5SDimitry Andric               else
6950b57cec5SDimitry Andric                 result.AppendMessageWithFormat("%u ", thread->GetIndexID());
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric               const bool override_suspend = true;
6980b57cec5SDimitry Andric               thread->SetResumeState(eStateRunning, override_suspend);
6990b57cec5SDimitry Andric             } else {
7000b57cec5SDimitry Andric               thread->SetResumeState(eStateSuspended);
7010b57cec5SDimitry Andric             }
7020b57cec5SDimitry Andric           }
7030b57cec5SDimitry Andric           result.AppendMessageWithFormat("in process %" PRIu64 "\n",
7040b57cec5SDimitry Andric                                          process->GetID());
7050b57cec5SDimitry Andric         }
7060b57cec5SDimitry Andric       } else {
7070b57cec5SDimitry Andric         // These two lines appear at the beginning of both blocks in this
7080b57cec5SDimitry Andric         // if..else, but that is because we need to release the lock before
7090b57cec5SDimitry Andric         // calling process->Resume below.
7100b57cec5SDimitry Andric         std::lock_guard<std::recursive_mutex> guard(
7110b57cec5SDimitry Andric             process->GetThreadList().GetMutex());
7120b57cec5SDimitry Andric         const uint32_t num_threads = process->GetThreadList().GetSize();
7130b57cec5SDimitry Andric         Thread *current_thread = GetDefaultThread();
7140b57cec5SDimitry Andric         if (current_thread == nullptr) {
7150b57cec5SDimitry Andric           result.AppendError("the process doesn't have a current thread");
7160b57cec5SDimitry Andric           return false;
7170b57cec5SDimitry Andric         }
7180b57cec5SDimitry Andric         // Set the actions that the threads should each take when resuming
7190b57cec5SDimitry Andric         for (uint32_t idx = 0; idx < num_threads; ++idx) {
7200b57cec5SDimitry Andric           Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
7210b57cec5SDimitry Andric           if (thread == current_thread) {
7220b57cec5SDimitry Andric             result.AppendMessageWithFormat("Resuming thread 0x%4.4" PRIx64
7230b57cec5SDimitry Andric                                            " in process %" PRIu64 "\n",
7240b57cec5SDimitry Andric                                            thread->GetID(), process->GetID());
7250b57cec5SDimitry Andric             const bool override_suspend = true;
7260b57cec5SDimitry Andric             thread->SetResumeState(eStateRunning, override_suspend);
7270b57cec5SDimitry Andric           } else {
7280b57cec5SDimitry Andric             thread->SetResumeState(eStateSuspended);
7290b57cec5SDimitry Andric           }
7300b57cec5SDimitry Andric         }
7310b57cec5SDimitry Andric       }
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric       StreamString stream;
7340b57cec5SDimitry Andric       Status error;
7350b57cec5SDimitry Andric       if (synchronous_execution)
7360b57cec5SDimitry Andric         error = process->ResumeSynchronous(&stream);
7370b57cec5SDimitry Andric       else
7380b57cec5SDimitry Andric         error = process->Resume();
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric       // We should not be holding the thread list lock when we do this.
7410b57cec5SDimitry Andric       if (error.Success()) {
7420b57cec5SDimitry Andric         result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",
7430b57cec5SDimitry Andric                                        process->GetID());
7440b57cec5SDimitry Andric         if (synchronous_execution) {
7450b57cec5SDimitry Andric           // If any state changed events had anything to say, add that to the
7460b57cec5SDimitry Andric           // result
7470b57cec5SDimitry Andric           if (stream.GetSize() > 0)
7480b57cec5SDimitry Andric             result.AppendMessage(stream.GetString());
7490b57cec5SDimitry Andric 
7500b57cec5SDimitry Andric           result.SetDidChangeProcessState(true);
7510b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishNoResult);
7520b57cec5SDimitry Andric         } else {
7530b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessContinuingNoResult);
7540b57cec5SDimitry Andric         }
7550b57cec5SDimitry Andric       } else {
7560b57cec5SDimitry Andric         result.AppendErrorWithFormat("Failed to resume process: %s\n",
7570b57cec5SDimitry Andric                                      error.AsCString());
7580b57cec5SDimitry Andric       }
7590b57cec5SDimitry Andric     } else {
7600b57cec5SDimitry Andric       result.AppendErrorWithFormat(
7610b57cec5SDimitry Andric           "Process cannot be continued from its current state (%s).\n",
7620b57cec5SDimitry Andric           StateAsCString(state));
7630b57cec5SDimitry Andric     }
7640b57cec5SDimitry Andric 
7650b57cec5SDimitry Andric     return result.Succeeded();
7660b57cec5SDimitry Andric   }
7670b57cec5SDimitry Andric };
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric // CommandObjectThreadUntil
7700b57cec5SDimitry Andric 
7710b57cec5SDimitry Andric static constexpr OptionEnumValueElement g_duo_running_mode[] = {
7720b57cec5SDimitry Andric     {eOnlyThisThread, "this-thread", "Run only this thread"},
7730b57cec5SDimitry Andric     {eAllThreads, "all-threads", "Run all threads"}};
7740b57cec5SDimitry Andric 
DuoRunningModes()7750b57cec5SDimitry Andric static constexpr OptionEnumValues DuoRunningModes() {
7760b57cec5SDimitry Andric   return OptionEnumValues(g_duo_running_mode);
7770b57cec5SDimitry Andric }
7780b57cec5SDimitry Andric 
7790b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_until
7800b57cec5SDimitry Andric #include "CommandOptions.inc"
7810b57cec5SDimitry Andric 
7820b57cec5SDimitry Andric class CommandObjectThreadUntil : public CommandObjectParsed {
7830b57cec5SDimitry Andric public:
7840b57cec5SDimitry Andric   class CommandOptions : public Options {
7850b57cec5SDimitry Andric   public:
786*5f7ddb14SDimitry Andric     uint32_t m_thread_idx = LLDB_INVALID_THREAD_ID;
787*5f7ddb14SDimitry Andric     uint32_t m_frame_idx = LLDB_INVALID_FRAME_ID;
7880b57cec5SDimitry Andric 
CommandOptions()789*5f7ddb14SDimitry Andric     CommandOptions() : Options() {
7900b57cec5SDimitry Andric       // Keep default values of all options in one place: OptionParsingStarting
7910b57cec5SDimitry Andric       // ()
7920b57cec5SDimitry Andric       OptionParsingStarting(nullptr);
7930b57cec5SDimitry Andric     }
7940b57cec5SDimitry Andric 
7950b57cec5SDimitry Andric     ~CommandOptions() override = default;
7960b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)7970b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
7980b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
7990b57cec5SDimitry Andric       Status error;
8000b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
8010b57cec5SDimitry Andric 
8020b57cec5SDimitry Andric       switch (short_option) {
8030b57cec5SDimitry Andric       case 'a': {
8040b57cec5SDimitry Andric         lldb::addr_t tmp_addr = OptionArgParser::ToAddress(
8050b57cec5SDimitry Andric             execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);
8060b57cec5SDimitry Andric         if (error.Success())
8070b57cec5SDimitry Andric           m_until_addrs.push_back(tmp_addr);
8080b57cec5SDimitry Andric       } break;
8090b57cec5SDimitry Andric       case 't':
8100b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_thread_idx)) {
8110b57cec5SDimitry Andric           m_thread_idx = LLDB_INVALID_INDEX32;
8120b57cec5SDimitry Andric           error.SetErrorStringWithFormat("invalid thread index '%s'",
8130b57cec5SDimitry Andric                                          option_arg.str().c_str());
8140b57cec5SDimitry Andric         }
8150b57cec5SDimitry Andric         break;
8160b57cec5SDimitry Andric       case 'f':
8170b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_frame_idx)) {
8180b57cec5SDimitry Andric           m_frame_idx = LLDB_INVALID_FRAME_ID;
8190b57cec5SDimitry Andric           error.SetErrorStringWithFormat("invalid frame index '%s'",
8200b57cec5SDimitry Andric                                          option_arg.str().c_str());
8210b57cec5SDimitry Andric         }
8220b57cec5SDimitry Andric         break;
8230b57cec5SDimitry Andric       case 'm': {
8240b57cec5SDimitry Andric         auto enum_values = GetDefinitions()[option_idx].enum_values;
8250b57cec5SDimitry Andric         lldb::RunMode run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(
8260b57cec5SDimitry Andric             option_arg, enum_values, eOnlyDuringStepping, error);
8270b57cec5SDimitry Andric 
8280b57cec5SDimitry Andric         if (error.Success()) {
8290b57cec5SDimitry Andric           if (run_mode == eAllThreads)
8300b57cec5SDimitry Andric             m_stop_others = false;
8310b57cec5SDimitry Andric           else
8320b57cec5SDimitry Andric             m_stop_others = true;
8330b57cec5SDimitry Andric         }
8340b57cec5SDimitry Andric       } break;
8350b57cec5SDimitry Andric       default:
8369dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
8370b57cec5SDimitry Andric       }
8380b57cec5SDimitry Andric       return error;
8390b57cec5SDimitry Andric     }
8400b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)8410b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
8420b57cec5SDimitry Andric       m_thread_idx = LLDB_INVALID_THREAD_ID;
8430b57cec5SDimitry Andric       m_frame_idx = 0;
8440b57cec5SDimitry Andric       m_stop_others = false;
8450b57cec5SDimitry Andric       m_until_addrs.clear();
8460b57cec5SDimitry Andric     }
8470b57cec5SDimitry Andric 
GetDefinitions()8480b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
8490b57cec5SDimitry Andric       return llvm::makeArrayRef(g_thread_until_options);
8500b57cec5SDimitry Andric     }
8510b57cec5SDimitry Andric 
8520b57cec5SDimitry Andric     uint32_t m_step_thread_idx;
8530b57cec5SDimitry Andric     bool m_stop_others;
8540b57cec5SDimitry Andric     std::vector<lldb::addr_t> m_until_addrs;
8550b57cec5SDimitry Andric 
8560b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
8570b57cec5SDimitry Andric   };
8580b57cec5SDimitry Andric 
CommandObjectThreadUntil(CommandInterpreter & interpreter)8590b57cec5SDimitry Andric   CommandObjectThreadUntil(CommandInterpreter &interpreter)
8600b57cec5SDimitry Andric       : CommandObjectParsed(
8610b57cec5SDimitry Andric             interpreter, "thread until",
8620b57cec5SDimitry Andric             "Continue until a line number or address is reached by the "
8630b57cec5SDimitry Andric             "current or specified thread.  Stops when returning from "
8640b57cec5SDimitry Andric             "the current function as a safety measure.  "
865480093f4SDimitry Andric             "The target line number(s) are given as arguments, and if more "
866480093f4SDimitry Andric             "than one"
8670b57cec5SDimitry Andric             " is provided, stepping will stop when the first one is hit.",
8680b57cec5SDimitry Andric             nullptr,
8690b57cec5SDimitry Andric             eCommandRequiresThread | eCommandTryTargetAPILock |
8700b57cec5SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
8710b57cec5SDimitry Andric         m_options() {
8720b57cec5SDimitry Andric     CommandArgumentEntry arg;
8730b57cec5SDimitry Andric     CommandArgumentData line_num_arg;
8740b57cec5SDimitry Andric 
8750b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
8760b57cec5SDimitry Andric     line_num_arg.arg_type = eArgTypeLineNum;
8770b57cec5SDimitry Andric     line_num_arg.arg_repetition = eArgRepeatPlain;
8780b57cec5SDimitry Andric 
8790b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
8800b57cec5SDimitry Andric     // argument entry.
8810b57cec5SDimitry Andric     arg.push_back(line_num_arg);
8820b57cec5SDimitry Andric 
8830b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
8840b57cec5SDimitry Andric     m_arguments.push_back(arg);
8850b57cec5SDimitry Andric   }
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric   ~CommandObjectThreadUntil() override = default;
8880b57cec5SDimitry Andric 
GetOptions()8890b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
8900b57cec5SDimitry Andric 
8910b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)8920b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
8930b57cec5SDimitry Andric     bool synchronous_execution = m_interpreter.GetSynchronous();
8940b57cec5SDimitry Andric 
8959dba64beSDimitry Andric     Target *target = &GetSelectedTarget();
8960b57cec5SDimitry Andric 
8970b57cec5SDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
8980b57cec5SDimitry Andric     if (process == nullptr) {
8990b57cec5SDimitry Andric       result.AppendError("need a valid process to step");
9000b57cec5SDimitry Andric     } else {
9010b57cec5SDimitry Andric       Thread *thread = nullptr;
9020b57cec5SDimitry Andric       std::vector<uint32_t> line_numbers;
9030b57cec5SDimitry Andric 
9040b57cec5SDimitry Andric       if (command.GetArgumentCount() >= 1) {
9050b57cec5SDimitry Andric         size_t num_args = command.GetArgumentCount();
9060b57cec5SDimitry Andric         for (size_t i = 0; i < num_args; i++) {
9070b57cec5SDimitry Andric           uint32_t line_number;
9085ffd83dbSDimitry Andric           if (!llvm::to_integer(command.GetArgumentAtIndex(i), line_number)) {
9090b57cec5SDimitry Andric             result.AppendErrorWithFormat("invalid line number: '%s'.\n",
9100b57cec5SDimitry Andric                                          command.GetArgumentAtIndex(i));
9110b57cec5SDimitry Andric             return false;
9120b57cec5SDimitry Andric           } else
9130b57cec5SDimitry Andric             line_numbers.push_back(line_number);
9140b57cec5SDimitry Andric         }
9150b57cec5SDimitry Andric       } else if (m_options.m_until_addrs.empty()) {
9160b57cec5SDimitry Andric         result.AppendErrorWithFormat("No line number or address provided:\n%s",
9170b57cec5SDimitry Andric                                      GetSyntax().str().c_str());
9180b57cec5SDimitry Andric         return false;
9190b57cec5SDimitry Andric       }
9200b57cec5SDimitry Andric 
9210b57cec5SDimitry Andric       if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) {
9220b57cec5SDimitry Andric         thread = GetDefaultThread();
9230b57cec5SDimitry Andric       } else {
9240b57cec5SDimitry Andric         thread = process->GetThreadList()
9250b57cec5SDimitry Andric                      .FindThreadByIndexID(m_options.m_thread_idx)
9260b57cec5SDimitry Andric                      .get();
9270b57cec5SDimitry Andric       }
9280b57cec5SDimitry Andric 
9290b57cec5SDimitry Andric       if (thread == nullptr) {
9300b57cec5SDimitry Andric         const uint32_t num_threads = process->GetThreadList().GetSize();
9310b57cec5SDimitry Andric         result.AppendErrorWithFormat(
9320b57cec5SDimitry Andric             "Thread index %u is out of range (valid values are 0 - %u).\n",
9330b57cec5SDimitry Andric             m_options.m_thread_idx, num_threads);
9340b57cec5SDimitry Andric         return false;
9350b57cec5SDimitry Andric       }
9360b57cec5SDimitry Andric 
9370b57cec5SDimitry Andric       const bool abort_other_plans = false;
9380b57cec5SDimitry Andric 
9390b57cec5SDimitry Andric       StackFrame *frame =
9400b57cec5SDimitry Andric           thread->GetStackFrameAtIndex(m_options.m_frame_idx).get();
9410b57cec5SDimitry Andric       if (frame == nullptr) {
9420b57cec5SDimitry Andric         result.AppendErrorWithFormat(
9430b57cec5SDimitry Andric             "Frame index %u is out of range for thread %u.\n",
9440b57cec5SDimitry Andric             m_options.m_frame_idx, m_options.m_thread_idx);
9450b57cec5SDimitry Andric         return false;
9460b57cec5SDimitry Andric       }
9470b57cec5SDimitry Andric 
9480b57cec5SDimitry Andric       ThreadPlanSP new_plan_sp;
9490b57cec5SDimitry Andric       Status new_plan_status;
9500b57cec5SDimitry Andric 
9510b57cec5SDimitry Andric       if (frame->HasDebugInformation()) {
9520b57cec5SDimitry Andric         // Finally we got here...  Translate the given line number to a bunch
9530b57cec5SDimitry Andric         // of addresses:
9540b57cec5SDimitry Andric         SymbolContext sc(frame->GetSymbolContext(eSymbolContextCompUnit));
9550b57cec5SDimitry Andric         LineTable *line_table = nullptr;
9560b57cec5SDimitry Andric         if (sc.comp_unit)
9570b57cec5SDimitry Andric           line_table = sc.comp_unit->GetLineTable();
9580b57cec5SDimitry Andric 
9590b57cec5SDimitry Andric         if (line_table == nullptr) {
9600b57cec5SDimitry Andric           result.AppendErrorWithFormat("Failed to resolve the line table for "
9610b57cec5SDimitry Andric                                        "frame %u of thread index %u.\n",
9620b57cec5SDimitry Andric                                        m_options.m_frame_idx,
9630b57cec5SDimitry Andric                                        m_options.m_thread_idx);
9640b57cec5SDimitry Andric           return false;
9650b57cec5SDimitry Andric         }
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric         LineEntry function_start;
9680b57cec5SDimitry Andric         uint32_t index_ptr = 0, end_ptr;
9690b57cec5SDimitry Andric         std::vector<addr_t> address_list;
9700b57cec5SDimitry Andric 
9710b57cec5SDimitry Andric         // Find the beginning & end index of the
9720b57cec5SDimitry Andric         AddressRange fun_addr_range = sc.function->GetAddressRange();
9730b57cec5SDimitry Andric         Address fun_start_addr = fun_addr_range.GetBaseAddress();
9740b57cec5SDimitry Andric         line_table->FindLineEntryByAddress(fun_start_addr, function_start,
9750b57cec5SDimitry Andric                                            &index_ptr);
9760b57cec5SDimitry Andric 
9770b57cec5SDimitry Andric         Address fun_end_addr(fun_start_addr.GetSection(),
9780b57cec5SDimitry Andric                              fun_start_addr.GetOffset() +
9790b57cec5SDimitry Andric                                  fun_addr_range.GetByteSize());
9800b57cec5SDimitry Andric 
9810b57cec5SDimitry Andric         bool all_in_function = true;
9820b57cec5SDimitry Andric 
9830b57cec5SDimitry Andric         line_table->FindLineEntryByAddress(fun_end_addr, function_start,
9840b57cec5SDimitry Andric                                            &end_ptr);
9850b57cec5SDimitry Andric 
9860b57cec5SDimitry Andric         for (uint32_t line_number : line_numbers) {
9870b57cec5SDimitry Andric           uint32_t start_idx_ptr = index_ptr;
9880b57cec5SDimitry Andric           while (start_idx_ptr <= end_ptr) {
9890b57cec5SDimitry Andric             LineEntry line_entry;
9900b57cec5SDimitry Andric             const bool exact = false;
9910b57cec5SDimitry Andric             start_idx_ptr = sc.comp_unit->FindLineEntry(
992480093f4SDimitry Andric                 start_idx_ptr, line_number, nullptr, exact, &line_entry);
9930b57cec5SDimitry Andric             if (start_idx_ptr == UINT32_MAX)
9940b57cec5SDimitry Andric               break;
9950b57cec5SDimitry Andric 
9960b57cec5SDimitry Andric             addr_t address =
9970b57cec5SDimitry Andric                 line_entry.range.GetBaseAddress().GetLoadAddress(target);
9980b57cec5SDimitry Andric             if (address != LLDB_INVALID_ADDRESS) {
9990b57cec5SDimitry Andric               if (fun_addr_range.ContainsLoadAddress(address, target))
10000b57cec5SDimitry Andric                 address_list.push_back(address);
10010b57cec5SDimitry Andric               else
10020b57cec5SDimitry Andric                 all_in_function = false;
10030b57cec5SDimitry Andric             }
10040b57cec5SDimitry Andric             start_idx_ptr++;
10050b57cec5SDimitry Andric           }
10060b57cec5SDimitry Andric         }
10070b57cec5SDimitry Andric 
10080b57cec5SDimitry Andric         for (lldb::addr_t address : m_options.m_until_addrs) {
10090b57cec5SDimitry Andric           if (fun_addr_range.ContainsLoadAddress(address, target))
10100b57cec5SDimitry Andric             address_list.push_back(address);
10110b57cec5SDimitry Andric           else
10120b57cec5SDimitry Andric             all_in_function = false;
10130b57cec5SDimitry Andric         }
10140b57cec5SDimitry Andric 
10150b57cec5SDimitry Andric         if (address_list.empty()) {
10160b57cec5SDimitry Andric           if (all_in_function)
10170b57cec5SDimitry Andric             result.AppendErrorWithFormat(
10180b57cec5SDimitry Andric                 "No line entries matching until target.\n");
10190b57cec5SDimitry Andric           else
10200b57cec5SDimitry Andric             result.AppendErrorWithFormat(
10210b57cec5SDimitry Andric                 "Until target outside of the current function.\n");
10220b57cec5SDimitry Andric 
10230b57cec5SDimitry Andric           return false;
10240b57cec5SDimitry Andric         }
10250b57cec5SDimitry Andric 
10260b57cec5SDimitry Andric         new_plan_sp = thread->QueueThreadPlanForStepUntil(
10270b57cec5SDimitry Andric             abort_other_plans, &address_list.front(), address_list.size(),
10280b57cec5SDimitry Andric             m_options.m_stop_others, m_options.m_frame_idx, new_plan_status);
10290b57cec5SDimitry Andric         if (new_plan_sp) {
10300b57cec5SDimitry Andric           // User level plans should be master plans so they can be interrupted
10310b57cec5SDimitry Andric           // (e.g. by hitting a breakpoint) and other plans executed by the
10320b57cec5SDimitry Andric           // user (stepping around the breakpoint) and then a "continue" will
10330b57cec5SDimitry Andric           // resume the original plan.
10340b57cec5SDimitry Andric           new_plan_sp->SetIsMasterPlan(true);
10350b57cec5SDimitry Andric           new_plan_sp->SetOkayToDiscard(false);
10360b57cec5SDimitry Andric         } else {
10370b57cec5SDimitry Andric           result.SetError(new_plan_status);
10380b57cec5SDimitry Andric           return false;
10390b57cec5SDimitry Andric         }
10400b57cec5SDimitry Andric       } else {
10410b57cec5SDimitry Andric         result.AppendErrorWithFormat(
10420b57cec5SDimitry Andric             "Frame index %u of thread %u has no debug information.\n",
10430b57cec5SDimitry Andric             m_options.m_frame_idx, m_options.m_thread_idx);
10440b57cec5SDimitry Andric         return false;
10450b57cec5SDimitry Andric       }
10460b57cec5SDimitry Andric 
10470b57cec5SDimitry Andric       process->GetThreadList().SetSelectedThreadByID(m_options.m_thread_idx);
10480b57cec5SDimitry Andric 
10490b57cec5SDimitry Andric       StreamString stream;
10500b57cec5SDimitry Andric       Status error;
10510b57cec5SDimitry Andric       if (synchronous_execution)
10520b57cec5SDimitry Andric         error = process->ResumeSynchronous(&stream);
10530b57cec5SDimitry Andric       else
10540b57cec5SDimitry Andric         error = process->Resume();
10550b57cec5SDimitry Andric 
10560b57cec5SDimitry Andric       if (error.Success()) {
10570b57cec5SDimitry Andric         result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",
10580b57cec5SDimitry Andric                                        process->GetID());
10590b57cec5SDimitry Andric         if (synchronous_execution) {
10600b57cec5SDimitry Andric           // If any state changed events had anything to say, add that to the
10610b57cec5SDimitry Andric           // result
10620b57cec5SDimitry Andric           if (stream.GetSize() > 0)
10630b57cec5SDimitry Andric             result.AppendMessage(stream.GetString());
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric           result.SetDidChangeProcessState(true);
10660b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishNoResult);
10670b57cec5SDimitry Andric         } else {
10680b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessContinuingNoResult);
10690b57cec5SDimitry Andric         }
10700b57cec5SDimitry Andric       } else {
10710b57cec5SDimitry Andric         result.AppendErrorWithFormat("Failed to resume process: %s.\n",
10720b57cec5SDimitry Andric                                      error.AsCString());
10730b57cec5SDimitry Andric       }
10740b57cec5SDimitry Andric     }
10750b57cec5SDimitry Andric     return result.Succeeded();
10760b57cec5SDimitry Andric   }
10770b57cec5SDimitry Andric 
10780b57cec5SDimitry Andric   CommandOptions m_options;
10790b57cec5SDimitry Andric };
10800b57cec5SDimitry Andric 
10810b57cec5SDimitry Andric // CommandObjectThreadSelect
10820b57cec5SDimitry Andric 
10830b57cec5SDimitry Andric class CommandObjectThreadSelect : public CommandObjectParsed {
10840b57cec5SDimitry Andric public:
CommandObjectThreadSelect(CommandInterpreter & interpreter)10850b57cec5SDimitry Andric   CommandObjectThreadSelect(CommandInterpreter &interpreter)
10860b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "thread select",
10870b57cec5SDimitry Andric                             "Change the currently selected thread.", nullptr,
10880b57cec5SDimitry Andric                             eCommandRequiresProcess | eCommandTryTargetAPILock |
10890b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched |
10900b57cec5SDimitry Andric                                 eCommandProcessMustBePaused) {
10910b57cec5SDimitry Andric     CommandArgumentEntry arg;
10920b57cec5SDimitry Andric     CommandArgumentData thread_idx_arg;
10930b57cec5SDimitry Andric 
10940b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
10950b57cec5SDimitry Andric     thread_idx_arg.arg_type = eArgTypeThreadIndex;
10960b57cec5SDimitry Andric     thread_idx_arg.arg_repetition = eArgRepeatPlain;
10970b57cec5SDimitry Andric 
10980b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
10990b57cec5SDimitry Andric     // argument entry.
11000b57cec5SDimitry Andric     arg.push_back(thread_idx_arg);
11010b57cec5SDimitry Andric 
11020b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
11030b57cec5SDimitry Andric     m_arguments.push_back(arg);
11040b57cec5SDimitry Andric   }
11050b57cec5SDimitry Andric 
11060b57cec5SDimitry Andric   ~CommandObjectThreadSelect() override = default;
11070b57cec5SDimitry Andric 
1108af732203SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1109af732203SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
1110af732203SDimitry Andric                            OptionElementVector &opt_element_vector) override {
1111af732203SDimitry Andric     if (request.GetCursorIndex())
1112af732203SDimitry Andric       return;
1113af732203SDimitry Andric 
1114af732203SDimitry Andric     CommandCompletions::InvokeCommonCompletionCallbacks(
1115af732203SDimitry Andric         GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion,
1116af732203SDimitry Andric         request, nullptr);
1117af732203SDimitry Andric   }
1118af732203SDimitry Andric 
11190b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)11200b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
11210b57cec5SDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
11220b57cec5SDimitry Andric     if (process == nullptr) {
11230b57cec5SDimitry Andric       result.AppendError("no process");
11240b57cec5SDimitry Andric       return false;
11250b57cec5SDimitry Andric     } else if (command.GetArgumentCount() != 1) {
11260b57cec5SDimitry Andric       result.AppendErrorWithFormat(
11270b57cec5SDimitry Andric           "'%s' takes exactly one thread index argument:\nUsage: %s\n",
11280b57cec5SDimitry Andric           m_cmd_name.c_str(), m_cmd_syntax.c_str());
11290b57cec5SDimitry Andric       return false;
11300b57cec5SDimitry Andric     }
11310b57cec5SDimitry Andric 
11325ffd83dbSDimitry Andric     uint32_t index_id;
11335ffd83dbSDimitry Andric     if (!llvm::to_integer(command.GetArgumentAtIndex(0), index_id)) {
11345ffd83dbSDimitry Andric       result.AppendErrorWithFormat("Invalid thread index '%s'",
11355ffd83dbSDimitry Andric                                    command.GetArgumentAtIndex(0));
11365ffd83dbSDimitry Andric       return false;
11375ffd83dbSDimitry Andric     }
11380b57cec5SDimitry Andric 
11390b57cec5SDimitry Andric     Thread *new_thread =
11400b57cec5SDimitry Andric         process->GetThreadList().FindThreadByIndexID(index_id).get();
11410b57cec5SDimitry Andric     if (new_thread == nullptr) {
11420b57cec5SDimitry Andric       result.AppendErrorWithFormat("invalid thread #%s.\n",
11430b57cec5SDimitry Andric                                    command.GetArgumentAtIndex(0));
11440b57cec5SDimitry Andric       return false;
11450b57cec5SDimitry Andric     }
11460b57cec5SDimitry Andric 
11470b57cec5SDimitry Andric     process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true);
11480b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric     return result.Succeeded();
11510b57cec5SDimitry Andric   }
11520b57cec5SDimitry Andric };
11530b57cec5SDimitry Andric 
11540b57cec5SDimitry Andric // CommandObjectThreadList
11550b57cec5SDimitry Andric 
11560b57cec5SDimitry Andric class CommandObjectThreadList : public CommandObjectParsed {
11570b57cec5SDimitry Andric public:
CommandObjectThreadList(CommandInterpreter & interpreter)11580b57cec5SDimitry Andric   CommandObjectThreadList(CommandInterpreter &interpreter)
11590b57cec5SDimitry Andric       : CommandObjectParsed(
11600b57cec5SDimitry Andric             interpreter, "thread list",
11610b57cec5SDimitry Andric             "Show a summary of each thread in the current target process.  "
11620b57cec5SDimitry Andric             "Use 'settings set thread-format' to customize the individual "
11630b57cec5SDimitry Andric             "thread listings.",
11640b57cec5SDimitry Andric             "thread list",
11650b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
11660b57cec5SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
11670b57cec5SDimitry Andric 
11680b57cec5SDimitry Andric   ~CommandObjectThreadList() override = default;
11690b57cec5SDimitry Andric 
11700b57cec5SDimitry Andric protected:
DoExecute(Args & command,CommandReturnObject & result)11710b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
11720b57cec5SDimitry Andric     Stream &strm = result.GetOutputStream();
11730b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
11740b57cec5SDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
11750b57cec5SDimitry Andric     const bool only_threads_with_stop_reason = false;
11760b57cec5SDimitry Andric     const uint32_t start_frame = 0;
11770b57cec5SDimitry Andric     const uint32_t num_frames = 0;
11780b57cec5SDimitry Andric     const uint32_t num_frames_with_source = 0;
11790b57cec5SDimitry Andric     process->GetStatus(strm);
11800b57cec5SDimitry Andric     process->GetThreadStatus(strm, only_threads_with_stop_reason, start_frame,
11810b57cec5SDimitry Andric                              num_frames, num_frames_with_source, false);
11820b57cec5SDimitry Andric     return result.Succeeded();
11830b57cec5SDimitry Andric   }
11840b57cec5SDimitry Andric };
11850b57cec5SDimitry Andric 
11860b57cec5SDimitry Andric // CommandObjectThreadInfo
11870b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_info
11880b57cec5SDimitry Andric #include "CommandOptions.inc"
11890b57cec5SDimitry Andric 
11900b57cec5SDimitry Andric class CommandObjectThreadInfo : public CommandObjectIterateOverThreads {
11910b57cec5SDimitry Andric public:
11920b57cec5SDimitry Andric   class CommandOptions : public Options {
11930b57cec5SDimitry Andric   public:
CommandOptions()11940b57cec5SDimitry Andric     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
11950b57cec5SDimitry Andric 
11960b57cec5SDimitry Andric     ~CommandOptions() override = default;
11970b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)11980b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
11990b57cec5SDimitry Andric       m_json_thread = false;
12000b57cec5SDimitry Andric       m_json_stopinfo = false;
12010b57cec5SDimitry Andric     }
12020b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)12030b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
12040b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
12050b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
12060b57cec5SDimitry Andric       Status error;
12070b57cec5SDimitry Andric 
12080b57cec5SDimitry Andric       switch (short_option) {
12090b57cec5SDimitry Andric       case 'j':
12100b57cec5SDimitry Andric         m_json_thread = true;
12110b57cec5SDimitry Andric         break;
12120b57cec5SDimitry Andric 
12130b57cec5SDimitry Andric       case 's':
12140b57cec5SDimitry Andric         m_json_stopinfo = true;
12150b57cec5SDimitry Andric         break;
12160b57cec5SDimitry Andric 
12170b57cec5SDimitry Andric       default:
12189dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
12190b57cec5SDimitry Andric       }
12200b57cec5SDimitry Andric       return error;
12210b57cec5SDimitry Andric     }
12220b57cec5SDimitry Andric 
GetDefinitions()12230b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
12240b57cec5SDimitry Andric       return llvm::makeArrayRef(g_thread_info_options);
12250b57cec5SDimitry Andric     }
12260b57cec5SDimitry Andric 
12270b57cec5SDimitry Andric     bool m_json_thread;
12280b57cec5SDimitry Andric     bool m_json_stopinfo;
12290b57cec5SDimitry Andric   };
12300b57cec5SDimitry Andric 
CommandObjectThreadInfo(CommandInterpreter & interpreter)12310b57cec5SDimitry Andric   CommandObjectThreadInfo(CommandInterpreter &interpreter)
12320b57cec5SDimitry Andric       : CommandObjectIterateOverThreads(
1233480093f4SDimitry Andric             interpreter, "thread info",
1234480093f4SDimitry Andric             "Show an extended summary of one or "
12350b57cec5SDimitry Andric             "more threads.  Defaults to the "
12360b57cec5SDimitry Andric             "current thread.",
12370b57cec5SDimitry Andric             "thread info",
12380b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
12390b57cec5SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
12400b57cec5SDimitry Andric         m_options() {
12410b57cec5SDimitry Andric     m_add_return = false;
12420b57cec5SDimitry Andric   }
12430b57cec5SDimitry Andric 
12440b57cec5SDimitry Andric   ~CommandObjectThreadInfo() override = default;
12450b57cec5SDimitry Andric 
1246af732203SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1247af732203SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
1248af732203SDimitry Andric                            OptionElementVector &opt_element_vector) override {
1249af732203SDimitry Andric     CommandCompletions::InvokeCommonCompletionCallbacks(
1250af732203SDimitry Andric         GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion,
1251af732203SDimitry Andric         request, nullptr);
1252af732203SDimitry Andric   }
1253af732203SDimitry Andric 
GetOptions()12540b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
12550b57cec5SDimitry Andric 
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)12560b57cec5SDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
12570b57cec5SDimitry Andric     ThreadSP thread_sp =
12580b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
12590b57cec5SDimitry Andric     if (!thread_sp) {
12600b57cec5SDimitry Andric       result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
12610b57cec5SDimitry Andric                                    tid);
12620b57cec5SDimitry Andric       return false;
12630b57cec5SDimitry Andric     }
12640b57cec5SDimitry Andric 
12650b57cec5SDimitry Andric     Thread *thread = thread_sp.get();
12660b57cec5SDimitry Andric 
12670b57cec5SDimitry Andric     Stream &strm = result.GetOutputStream();
12680b57cec5SDimitry Andric     if (!thread->GetDescription(strm, eDescriptionLevelFull,
12690b57cec5SDimitry Andric                                 m_options.m_json_thread,
12700b57cec5SDimitry Andric                                 m_options.m_json_stopinfo)) {
12710b57cec5SDimitry Andric       result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n",
12720b57cec5SDimitry Andric                                    thread->GetIndexID());
12730b57cec5SDimitry Andric       return false;
12740b57cec5SDimitry Andric     }
12750b57cec5SDimitry Andric     return true;
12760b57cec5SDimitry Andric   }
12770b57cec5SDimitry Andric 
12780b57cec5SDimitry Andric   CommandOptions m_options;
12790b57cec5SDimitry Andric };
12800b57cec5SDimitry Andric 
12810b57cec5SDimitry Andric // CommandObjectThreadException
12820b57cec5SDimitry Andric 
12830b57cec5SDimitry Andric class CommandObjectThreadException : public CommandObjectIterateOverThreads {
12840b57cec5SDimitry Andric public:
CommandObjectThreadException(CommandInterpreter & interpreter)12850b57cec5SDimitry Andric   CommandObjectThreadException(CommandInterpreter &interpreter)
12860b57cec5SDimitry Andric       : CommandObjectIterateOverThreads(
12870b57cec5SDimitry Andric             interpreter, "thread exception",
12880b57cec5SDimitry Andric             "Display the current exception object for a thread. Defaults to "
12890b57cec5SDimitry Andric             "the current thread.",
12900b57cec5SDimitry Andric             "thread exception",
12910b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
12920b57cec5SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
12930b57cec5SDimitry Andric 
12940b57cec5SDimitry Andric   ~CommandObjectThreadException() override = default;
12950b57cec5SDimitry Andric 
1296af732203SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1297af732203SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
1298af732203SDimitry Andric                            OptionElementVector &opt_element_vector) override {
1299af732203SDimitry Andric     CommandCompletions::InvokeCommonCompletionCallbacks(
1300af732203SDimitry Andric         GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion,
1301af732203SDimitry Andric         request, nullptr);
1302af732203SDimitry Andric   }
1303af732203SDimitry Andric 
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)13040b57cec5SDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
13050b57cec5SDimitry Andric     ThreadSP thread_sp =
13060b57cec5SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
13070b57cec5SDimitry Andric     if (!thread_sp) {
13080b57cec5SDimitry Andric       result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",
13090b57cec5SDimitry Andric                                    tid);
13100b57cec5SDimitry Andric       return false;
13110b57cec5SDimitry Andric     }
13120b57cec5SDimitry Andric 
13130b57cec5SDimitry Andric     Stream &strm = result.GetOutputStream();
13140b57cec5SDimitry Andric     ValueObjectSP exception_object_sp = thread_sp->GetCurrentException();
13150b57cec5SDimitry Andric     if (exception_object_sp) {
13160b57cec5SDimitry Andric       exception_object_sp->Dump(strm);
13170b57cec5SDimitry Andric     }
13180b57cec5SDimitry Andric 
13190b57cec5SDimitry Andric     ThreadSP exception_thread_sp = thread_sp->GetCurrentExceptionBacktrace();
13200b57cec5SDimitry Andric     if (exception_thread_sp && exception_thread_sp->IsValid()) {
13210b57cec5SDimitry Andric       const uint32_t num_frames_with_source = 0;
13220b57cec5SDimitry Andric       const bool stop_format = false;
13230b57cec5SDimitry Andric       exception_thread_sp->GetStatus(strm, 0, UINT32_MAX,
13240b57cec5SDimitry Andric                                      num_frames_with_source, stop_format);
13250b57cec5SDimitry Andric     }
13260b57cec5SDimitry Andric 
13270b57cec5SDimitry Andric     return true;
13280b57cec5SDimitry Andric   }
13290b57cec5SDimitry Andric };
13300b57cec5SDimitry Andric 
13310b57cec5SDimitry Andric // CommandObjectThreadReturn
13320b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_return
13330b57cec5SDimitry Andric #include "CommandOptions.inc"
13340b57cec5SDimitry Andric 
13350b57cec5SDimitry Andric class CommandObjectThreadReturn : public CommandObjectRaw {
13360b57cec5SDimitry Andric public:
13370b57cec5SDimitry Andric   class CommandOptions : public Options {
13380b57cec5SDimitry Andric   public:
CommandOptions()1339*5f7ddb14SDimitry Andric     CommandOptions() : Options() {
13400b57cec5SDimitry Andric       // Keep default values of all options in one place: OptionParsingStarting
13410b57cec5SDimitry Andric       // ()
13420b57cec5SDimitry Andric       OptionParsingStarting(nullptr);
13430b57cec5SDimitry Andric     }
13440b57cec5SDimitry Andric 
13450b57cec5SDimitry Andric     ~CommandOptions() override = default;
13460b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)13470b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
13480b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
13490b57cec5SDimitry Andric       Status error;
13500b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
13510b57cec5SDimitry Andric 
13520b57cec5SDimitry Andric       switch (short_option) {
13530b57cec5SDimitry Andric       case 'x': {
13540b57cec5SDimitry Andric         bool success;
13550b57cec5SDimitry Andric         bool tmp_value =
13560b57cec5SDimitry Andric             OptionArgParser::ToBoolean(option_arg, false, &success);
13570b57cec5SDimitry Andric         if (success)
13580b57cec5SDimitry Andric           m_from_expression = tmp_value;
13590b57cec5SDimitry Andric         else {
13600b57cec5SDimitry Andric           error.SetErrorStringWithFormat(
13610b57cec5SDimitry Andric               "invalid boolean value '%s' for 'x' option",
13620b57cec5SDimitry Andric               option_arg.str().c_str());
13630b57cec5SDimitry Andric         }
13640b57cec5SDimitry Andric       } break;
13650b57cec5SDimitry Andric       default:
13669dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
13670b57cec5SDimitry Andric       }
13680b57cec5SDimitry Andric       return error;
13690b57cec5SDimitry Andric     }
13700b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)13710b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
13720b57cec5SDimitry Andric       m_from_expression = false;
13730b57cec5SDimitry Andric     }
13740b57cec5SDimitry Andric 
GetDefinitions()13750b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
13760b57cec5SDimitry Andric       return llvm::makeArrayRef(g_thread_return_options);
13770b57cec5SDimitry Andric     }
13780b57cec5SDimitry Andric 
1379*5f7ddb14SDimitry Andric     bool m_from_expression = false;
13800b57cec5SDimitry Andric 
13810b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
13820b57cec5SDimitry Andric   };
13830b57cec5SDimitry Andric 
CommandObjectThreadReturn(CommandInterpreter & interpreter)13840b57cec5SDimitry Andric   CommandObjectThreadReturn(CommandInterpreter &interpreter)
13850b57cec5SDimitry Andric       : CommandObjectRaw(interpreter, "thread return",
13860b57cec5SDimitry Andric                          "Prematurely return from a stack frame, "
13870b57cec5SDimitry Andric                          "short-circuiting execution of newer frames "
13880b57cec5SDimitry Andric                          "and optionally yielding a specified value.  Defaults "
13890b57cec5SDimitry Andric                          "to the exiting the current stack "
13900b57cec5SDimitry Andric                          "frame.",
13910b57cec5SDimitry Andric                          "thread return",
13920b57cec5SDimitry Andric                          eCommandRequiresFrame | eCommandTryTargetAPILock |
13930b57cec5SDimitry Andric                              eCommandProcessMustBeLaunched |
13940b57cec5SDimitry Andric                              eCommandProcessMustBePaused),
13950b57cec5SDimitry Andric         m_options() {
13960b57cec5SDimitry Andric     CommandArgumentEntry arg;
13970b57cec5SDimitry Andric     CommandArgumentData expression_arg;
13980b57cec5SDimitry Andric 
13990b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
14000b57cec5SDimitry Andric     expression_arg.arg_type = eArgTypeExpression;
14010b57cec5SDimitry Andric     expression_arg.arg_repetition = eArgRepeatOptional;
14020b57cec5SDimitry Andric 
14030b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
14040b57cec5SDimitry Andric     // argument entry.
14050b57cec5SDimitry Andric     arg.push_back(expression_arg);
14060b57cec5SDimitry Andric 
14070b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
14080b57cec5SDimitry Andric     m_arguments.push_back(arg);
14090b57cec5SDimitry Andric   }
14100b57cec5SDimitry Andric 
14110b57cec5SDimitry Andric   ~CommandObjectThreadReturn() override = default;
14120b57cec5SDimitry Andric 
GetOptions()14130b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
14140b57cec5SDimitry Andric 
14150b57cec5SDimitry Andric protected:
DoExecute(llvm::StringRef command,CommandReturnObject & result)14160b57cec5SDimitry Andric   bool DoExecute(llvm::StringRef command,
14170b57cec5SDimitry Andric                  CommandReturnObject &result) override {
14180b57cec5SDimitry Andric     // I am going to handle this by hand, because I don't want you to have to
14190b57cec5SDimitry Andric     // say:
14200b57cec5SDimitry Andric     // "thread return -- -5".
14210b57cec5SDimitry Andric     if (command.startswith("-x")) {
14220b57cec5SDimitry Andric       if (command.size() != 2U)
14230b57cec5SDimitry Andric         result.AppendWarning("Return values ignored when returning from user "
14240b57cec5SDimitry Andric                              "called expressions");
14250b57cec5SDimitry Andric 
14260b57cec5SDimitry Andric       Thread *thread = m_exe_ctx.GetThreadPtr();
14270b57cec5SDimitry Andric       Status error;
14280b57cec5SDimitry Andric       error = thread->UnwindInnermostExpression();
14290b57cec5SDimitry Andric       if (!error.Success()) {
14300b57cec5SDimitry Andric         result.AppendErrorWithFormat("Unwinding expression failed - %s.",
14310b57cec5SDimitry Andric                                      error.AsCString());
14320b57cec5SDimitry Andric       } else {
14330b57cec5SDimitry Andric         bool success =
14340b57cec5SDimitry Andric             thread->SetSelectedFrameByIndexNoisily(0, result.GetOutputStream());
14350b57cec5SDimitry Andric         if (success) {
14360b57cec5SDimitry Andric           m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
14370b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
14380b57cec5SDimitry Andric         } else {
14390b57cec5SDimitry Andric           result.AppendErrorWithFormat(
14400b57cec5SDimitry Andric               "Could not select 0th frame after unwinding expression.");
14410b57cec5SDimitry Andric         }
14420b57cec5SDimitry Andric       }
14430b57cec5SDimitry Andric       return result.Succeeded();
14440b57cec5SDimitry Andric     }
14450b57cec5SDimitry Andric 
14460b57cec5SDimitry Andric     ValueObjectSP return_valobj_sp;
14470b57cec5SDimitry Andric 
14480b57cec5SDimitry Andric     StackFrameSP frame_sp = m_exe_ctx.GetFrameSP();
14490b57cec5SDimitry Andric     uint32_t frame_idx = frame_sp->GetFrameIndex();
14500b57cec5SDimitry Andric 
14510b57cec5SDimitry Andric     if (frame_sp->IsInlined()) {
14520b57cec5SDimitry Andric       result.AppendError("Don't know how to return from inlined frames.");
14530b57cec5SDimitry Andric       return false;
14540b57cec5SDimitry Andric     }
14550b57cec5SDimitry Andric 
14560b57cec5SDimitry Andric     if (!command.empty()) {
14570b57cec5SDimitry Andric       Target *target = m_exe_ctx.GetTargetPtr();
14580b57cec5SDimitry Andric       EvaluateExpressionOptions options;
14590b57cec5SDimitry Andric 
14600b57cec5SDimitry Andric       options.SetUnwindOnError(true);
14610b57cec5SDimitry Andric       options.SetUseDynamic(eNoDynamicValues);
14620b57cec5SDimitry Andric 
14630b57cec5SDimitry Andric       ExpressionResults exe_results = eExpressionSetupError;
14640b57cec5SDimitry Andric       exe_results = target->EvaluateExpression(command, frame_sp.get(),
14650b57cec5SDimitry Andric                                                return_valobj_sp, options);
14660b57cec5SDimitry Andric       if (exe_results != eExpressionCompleted) {
14670b57cec5SDimitry Andric         if (return_valobj_sp)
14680b57cec5SDimitry Andric           result.AppendErrorWithFormat(
14690b57cec5SDimitry Andric               "Error evaluating result expression: %s",
14700b57cec5SDimitry Andric               return_valobj_sp->GetError().AsCString());
14710b57cec5SDimitry Andric         else
14720b57cec5SDimitry Andric           result.AppendErrorWithFormat(
14730b57cec5SDimitry Andric               "Unknown error evaluating result expression.");
14740b57cec5SDimitry Andric         return false;
14750b57cec5SDimitry Andric       }
14760b57cec5SDimitry Andric     }
14770b57cec5SDimitry Andric 
14780b57cec5SDimitry Andric     Status error;
14790b57cec5SDimitry Andric     ThreadSP thread_sp = m_exe_ctx.GetThreadSP();
14800b57cec5SDimitry Andric     const bool broadcast = true;
14810b57cec5SDimitry Andric     error = thread_sp->ReturnFromFrame(frame_sp, return_valobj_sp, broadcast);
14820b57cec5SDimitry Andric     if (!error.Success()) {
14830b57cec5SDimitry Andric       result.AppendErrorWithFormat(
14840b57cec5SDimitry Andric           "Error returning from frame %d of thread %d: %s.", frame_idx,
14850b57cec5SDimitry Andric           thread_sp->GetIndexID(), error.AsCString());
14860b57cec5SDimitry Andric       return false;
14870b57cec5SDimitry Andric     }
14880b57cec5SDimitry Andric 
14890b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
14900b57cec5SDimitry Andric     return true;
14910b57cec5SDimitry Andric   }
14920b57cec5SDimitry Andric 
14930b57cec5SDimitry Andric   CommandOptions m_options;
14940b57cec5SDimitry Andric };
14950b57cec5SDimitry Andric 
14960b57cec5SDimitry Andric // CommandObjectThreadJump
14970b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_jump
14980b57cec5SDimitry Andric #include "CommandOptions.inc"
14990b57cec5SDimitry Andric 
15000b57cec5SDimitry Andric class CommandObjectThreadJump : public CommandObjectParsed {
15010b57cec5SDimitry Andric public:
15020b57cec5SDimitry Andric   class CommandOptions : public Options {
15030b57cec5SDimitry Andric   public:
CommandOptions()15040b57cec5SDimitry Andric     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
15050b57cec5SDimitry Andric 
15060b57cec5SDimitry Andric     ~CommandOptions() override = default;
15070b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)15080b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
15090b57cec5SDimitry Andric       m_filenames.Clear();
15100b57cec5SDimitry Andric       m_line_num = 0;
15110b57cec5SDimitry Andric       m_line_offset = 0;
15120b57cec5SDimitry Andric       m_load_addr = LLDB_INVALID_ADDRESS;
15130b57cec5SDimitry Andric       m_force = false;
15140b57cec5SDimitry Andric     }
15150b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)15160b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
15170b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
15180b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
15190b57cec5SDimitry Andric       Status error;
15200b57cec5SDimitry Andric 
15210b57cec5SDimitry Andric       switch (short_option) {
15220b57cec5SDimitry Andric       case 'f':
15230b57cec5SDimitry Andric         m_filenames.AppendIfUnique(FileSpec(option_arg));
15240b57cec5SDimitry Andric         if (m_filenames.GetSize() > 1)
15250b57cec5SDimitry Andric           return Status("only one source file expected.");
15260b57cec5SDimitry Andric         break;
15270b57cec5SDimitry Andric       case 'l':
15280b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_line_num))
15290b57cec5SDimitry Andric           return Status("invalid line number: '%s'.", option_arg.str().c_str());
15300b57cec5SDimitry Andric         break;
15310b57cec5SDimitry Andric       case 'b':
15320b57cec5SDimitry Andric         if (option_arg.getAsInteger(0, m_line_offset))
15330b57cec5SDimitry Andric           return Status("invalid line offset: '%s'.", option_arg.str().c_str());
15340b57cec5SDimitry Andric         break;
15350b57cec5SDimitry Andric       case 'a':
15360b57cec5SDimitry Andric         m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg,
15370b57cec5SDimitry Andric                                                  LLDB_INVALID_ADDRESS, &error);
15380b57cec5SDimitry Andric         break;
15390b57cec5SDimitry Andric       case 'r':
15400b57cec5SDimitry Andric         m_force = true;
15410b57cec5SDimitry Andric         break;
15420b57cec5SDimitry Andric       default:
15439dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
15440b57cec5SDimitry Andric       }
15450b57cec5SDimitry Andric       return error;
15460b57cec5SDimitry Andric     }
15470b57cec5SDimitry Andric 
GetDefinitions()15480b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
15490b57cec5SDimitry Andric       return llvm::makeArrayRef(g_thread_jump_options);
15500b57cec5SDimitry Andric     }
15510b57cec5SDimitry Andric 
15520b57cec5SDimitry Andric     FileSpecList m_filenames;
15530b57cec5SDimitry Andric     uint32_t m_line_num;
15540b57cec5SDimitry Andric     int32_t m_line_offset;
15550b57cec5SDimitry Andric     lldb::addr_t m_load_addr;
15560b57cec5SDimitry Andric     bool m_force;
15570b57cec5SDimitry Andric   };
15580b57cec5SDimitry Andric 
CommandObjectThreadJump(CommandInterpreter & interpreter)15590b57cec5SDimitry Andric   CommandObjectThreadJump(CommandInterpreter &interpreter)
15600b57cec5SDimitry Andric       : CommandObjectParsed(
15610b57cec5SDimitry Andric             interpreter, "thread jump",
15620b57cec5SDimitry Andric             "Sets the program counter to a new address.", "thread jump",
15630b57cec5SDimitry Andric             eCommandRequiresFrame | eCommandTryTargetAPILock |
15640b57cec5SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
15650b57cec5SDimitry Andric         m_options() {}
15660b57cec5SDimitry Andric 
15670b57cec5SDimitry Andric   ~CommandObjectThreadJump() override = default;
15680b57cec5SDimitry Andric 
GetOptions()15690b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
15700b57cec5SDimitry Andric 
15710b57cec5SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)15720b57cec5SDimitry Andric   bool DoExecute(Args &args, CommandReturnObject &result) override {
15730b57cec5SDimitry Andric     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
15740b57cec5SDimitry Andric     StackFrame *frame = m_exe_ctx.GetFramePtr();
15750b57cec5SDimitry Andric     Thread *thread = m_exe_ctx.GetThreadPtr();
15760b57cec5SDimitry Andric     Target *target = m_exe_ctx.GetTargetPtr();
15770b57cec5SDimitry Andric     const SymbolContext &sym_ctx =
15780b57cec5SDimitry Andric         frame->GetSymbolContext(eSymbolContextLineEntry);
15790b57cec5SDimitry Andric 
15800b57cec5SDimitry Andric     if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) {
15810b57cec5SDimitry Andric       // Use this address directly.
15820b57cec5SDimitry Andric       Address dest = Address(m_options.m_load_addr);
15830b57cec5SDimitry Andric 
15840b57cec5SDimitry Andric       lldb::addr_t callAddr = dest.GetCallableLoadAddress(target);
15850b57cec5SDimitry Andric       if (callAddr == LLDB_INVALID_ADDRESS) {
15860b57cec5SDimitry Andric         result.AppendErrorWithFormat("Invalid destination address.");
15870b57cec5SDimitry Andric         return false;
15880b57cec5SDimitry Andric       }
15890b57cec5SDimitry Andric 
15900b57cec5SDimitry Andric       if (!reg_ctx->SetPC(callAddr)) {
15910b57cec5SDimitry Andric         result.AppendErrorWithFormat("Error changing PC value for thread %d.",
15920b57cec5SDimitry Andric                                      thread->GetIndexID());
15930b57cec5SDimitry Andric         return false;
15940b57cec5SDimitry Andric       }
15950b57cec5SDimitry Andric     } else {
15960b57cec5SDimitry Andric       // Pick either the absolute line, or work out a relative one.
15970b57cec5SDimitry Andric       int32_t line = (int32_t)m_options.m_line_num;
15980b57cec5SDimitry Andric       if (line == 0)
15990b57cec5SDimitry Andric         line = sym_ctx.line_entry.line + m_options.m_line_offset;
16000b57cec5SDimitry Andric 
16010b57cec5SDimitry Andric       // Try the current file, but override if asked.
16020b57cec5SDimitry Andric       FileSpec file = sym_ctx.line_entry.file;
16030b57cec5SDimitry Andric       if (m_options.m_filenames.GetSize() == 1)
16040b57cec5SDimitry Andric         file = m_options.m_filenames.GetFileSpecAtIndex(0);
16050b57cec5SDimitry Andric 
16060b57cec5SDimitry Andric       if (!file) {
16070b57cec5SDimitry Andric         result.AppendErrorWithFormat(
16080b57cec5SDimitry Andric             "No source file available for the current location.");
16090b57cec5SDimitry Andric         return false;
16100b57cec5SDimitry Andric       }
16110b57cec5SDimitry Andric 
16120b57cec5SDimitry Andric       std::string warnings;
16130b57cec5SDimitry Andric       Status err = thread->JumpToLine(file, line, m_options.m_force, &warnings);
16140b57cec5SDimitry Andric 
16150b57cec5SDimitry Andric       if (err.Fail()) {
16160b57cec5SDimitry Andric         result.SetError(err);
16170b57cec5SDimitry Andric         return false;
16180b57cec5SDimitry Andric       }
16190b57cec5SDimitry Andric 
16200b57cec5SDimitry Andric       if (!warnings.empty())
16210b57cec5SDimitry Andric         result.AppendWarning(warnings.c_str());
16220b57cec5SDimitry Andric     }
16230b57cec5SDimitry Andric 
16240b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
16250b57cec5SDimitry Andric     return true;
16260b57cec5SDimitry Andric   }
16270b57cec5SDimitry Andric 
16280b57cec5SDimitry Andric   CommandOptions m_options;
16290b57cec5SDimitry Andric };
16300b57cec5SDimitry Andric 
16310b57cec5SDimitry Andric // Next are the subcommands of CommandObjectMultiwordThreadPlan
16320b57cec5SDimitry Andric 
16330b57cec5SDimitry Andric // CommandObjectThreadPlanList
16340b57cec5SDimitry Andric #define LLDB_OPTIONS_thread_plan_list
16350b57cec5SDimitry Andric #include "CommandOptions.inc"
16360b57cec5SDimitry Andric 
16370b57cec5SDimitry Andric class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads {
16380b57cec5SDimitry Andric public:
16390b57cec5SDimitry Andric   class CommandOptions : public Options {
16400b57cec5SDimitry Andric   public:
CommandOptions()16410b57cec5SDimitry Andric     CommandOptions() : Options() {
16420b57cec5SDimitry Andric       // Keep default values of all options in one place: OptionParsingStarting
16430b57cec5SDimitry Andric       // ()
16440b57cec5SDimitry Andric       OptionParsingStarting(nullptr);
16450b57cec5SDimitry Andric     }
16460b57cec5SDimitry Andric 
16470b57cec5SDimitry Andric     ~CommandOptions() override = default;
16480b57cec5SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)16490b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
16500b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
16510b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
16520b57cec5SDimitry Andric 
16530b57cec5SDimitry Andric       switch (short_option) {
16540b57cec5SDimitry Andric       case 'i':
16550b57cec5SDimitry Andric         m_internal = true;
16560b57cec5SDimitry Andric         break;
16575ffd83dbSDimitry Andric       case 't':
16585ffd83dbSDimitry Andric         lldb::tid_t tid;
16595ffd83dbSDimitry Andric         if (option_arg.getAsInteger(0, tid))
16605ffd83dbSDimitry Andric           return Status("invalid tid: '%s'.", option_arg.str().c_str());
16615ffd83dbSDimitry Andric         m_tids.push_back(tid);
16625ffd83dbSDimitry Andric         break;
16635ffd83dbSDimitry Andric       case 'u':
16645ffd83dbSDimitry Andric         m_unreported = false;
16655ffd83dbSDimitry Andric         break;
16660b57cec5SDimitry Andric       case 'v':
16670b57cec5SDimitry Andric         m_verbose = true;
16680b57cec5SDimitry Andric         break;
16690b57cec5SDimitry Andric       default:
16709dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
16710b57cec5SDimitry Andric       }
16725ffd83dbSDimitry Andric       return {};
16730b57cec5SDimitry Andric     }
16740b57cec5SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)16750b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
16760b57cec5SDimitry Andric       m_verbose = false;
16770b57cec5SDimitry Andric       m_internal = false;
16785ffd83dbSDimitry Andric       m_unreported = true; // The variable is "skip unreported" and we want to
16795ffd83dbSDimitry Andric                            // skip unreported by default.
16805ffd83dbSDimitry Andric       m_tids.clear();
16810b57cec5SDimitry Andric     }
16820b57cec5SDimitry Andric 
GetDefinitions()16830b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
16840b57cec5SDimitry Andric       return llvm::makeArrayRef(g_thread_plan_list_options);
16850b57cec5SDimitry Andric     }
16860b57cec5SDimitry Andric 
16870b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
16880b57cec5SDimitry Andric     bool m_verbose;
16890b57cec5SDimitry Andric     bool m_internal;
16905ffd83dbSDimitry Andric     bool m_unreported;
16915ffd83dbSDimitry Andric     std::vector<lldb::tid_t> m_tids;
16920b57cec5SDimitry Andric   };
16930b57cec5SDimitry Andric 
CommandObjectThreadPlanList(CommandInterpreter & interpreter)16940b57cec5SDimitry Andric   CommandObjectThreadPlanList(CommandInterpreter &interpreter)
16950b57cec5SDimitry Andric       : CommandObjectIterateOverThreads(
16960b57cec5SDimitry Andric             interpreter, "thread plan list",
16970b57cec5SDimitry Andric             "Show thread plans for one or more threads.  If no threads are "
16980b57cec5SDimitry Andric             "specified, show the "
16990b57cec5SDimitry Andric             "current thread.  Use the thread-index \"all\" to see all threads.",
17000b57cec5SDimitry Andric             nullptr,
17010b57cec5SDimitry Andric             eCommandRequiresProcess | eCommandRequiresThread |
17020b57cec5SDimitry Andric                 eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |
17030b57cec5SDimitry Andric                 eCommandProcessMustBePaused),
17040b57cec5SDimitry Andric         m_options() {}
17050b57cec5SDimitry Andric 
17060b57cec5SDimitry Andric   ~CommandObjectThreadPlanList() override = default;
17070b57cec5SDimitry Andric 
GetOptions()17080b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
17090b57cec5SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)17105ffd83dbSDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
17115ffd83dbSDimitry Andric     // If we are reporting all threads, dispatch to the Process to do that:
17125ffd83dbSDimitry Andric     if (command.GetArgumentCount() == 0 && m_options.m_tids.empty()) {
17135ffd83dbSDimitry Andric       Stream &strm = result.GetOutputStream();
17145ffd83dbSDimitry Andric       DescriptionLevel desc_level = m_options.m_verbose
17155ffd83dbSDimitry Andric                                         ? eDescriptionLevelVerbose
17165ffd83dbSDimitry Andric                                         : eDescriptionLevelFull;
17175ffd83dbSDimitry Andric       m_exe_ctx.GetProcessPtr()->DumpThreadPlans(
17185ffd83dbSDimitry Andric           strm, desc_level, m_options.m_internal, true, m_options.m_unreported);
17195ffd83dbSDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
17205ffd83dbSDimitry Andric       return true;
17215ffd83dbSDimitry Andric     } else {
17225ffd83dbSDimitry Andric       // Do any TID's that the user may have specified as TID, then do any
17235ffd83dbSDimitry Andric       // Thread Indexes...
17245ffd83dbSDimitry Andric       if (!m_options.m_tids.empty()) {
17255ffd83dbSDimitry Andric         Process *process = m_exe_ctx.GetProcessPtr();
17265ffd83dbSDimitry Andric         StreamString tmp_strm;
17275ffd83dbSDimitry Andric         for (lldb::tid_t tid : m_options.m_tids) {
17285ffd83dbSDimitry Andric           bool success = process->DumpThreadPlansForTID(
17295ffd83dbSDimitry Andric               tmp_strm, tid, eDescriptionLevelFull, m_options.m_internal,
17305ffd83dbSDimitry Andric               true /* condense_trivial */, m_options.m_unreported);
17315ffd83dbSDimitry Andric           // If we didn't find a TID, stop here and return an error.
17325ffd83dbSDimitry Andric           if (!success) {
1733*5f7ddb14SDimitry Andric             result.AppendError("Error dumping plans:");
17345ffd83dbSDimitry Andric             result.AppendError(tmp_strm.GetString());
17350b57cec5SDimitry Andric             return false;
17360b57cec5SDimitry Andric           }
17375ffd83dbSDimitry Andric           // Otherwise, add our data to the output:
17385ffd83dbSDimitry Andric           result.GetOutputStream() << tmp_strm.GetString();
17395ffd83dbSDimitry Andric         }
17405ffd83dbSDimitry Andric       }
17415ffd83dbSDimitry Andric       return CommandObjectIterateOverThreads::DoExecute(command, result);
17425ffd83dbSDimitry Andric     }
17435ffd83dbSDimitry Andric   }
17440b57cec5SDimitry Andric 
17455ffd83dbSDimitry Andric protected:
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)17465ffd83dbSDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
17475ffd83dbSDimitry Andric     // If we have already handled this from a -t option, skip it here.
1748af732203SDimitry Andric     if (llvm::is_contained(m_options.m_tids, tid))
17495ffd83dbSDimitry Andric       return true;
17505ffd83dbSDimitry Andric 
17515ffd83dbSDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
17520b57cec5SDimitry Andric 
17530b57cec5SDimitry Andric     Stream &strm = result.GetOutputStream();
17540b57cec5SDimitry Andric     DescriptionLevel desc_level = eDescriptionLevelFull;
17550b57cec5SDimitry Andric     if (m_options.m_verbose)
17560b57cec5SDimitry Andric       desc_level = eDescriptionLevelVerbose;
17570b57cec5SDimitry Andric 
17585ffd83dbSDimitry Andric     process->DumpThreadPlansForTID(strm, tid, desc_level, m_options.m_internal,
17595ffd83dbSDimitry Andric                                    true /* condense_trivial */,
17605ffd83dbSDimitry Andric                                    m_options.m_unreported);
17610b57cec5SDimitry Andric     return true;
17620b57cec5SDimitry Andric   }
17630b57cec5SDimitry Andric 
17640b57cec5SDimitry Andric   CommandOptions m_options;
17650b57cec5SDimitry Andric };
17660b57cec5SDimitry Andric 
17670b57cec5SDimitry Andric class CommandObjectThreadPlanDiscard : public CommandObjectParsed {
17680b57cec5SDimitry Andric public:
CommandObjectThreadPlanDiscard(CommandInterpreter & interpreter)17690b57cec5SDimitry Andric   CommandObjectThreadPlanDiscard(CommandInterpreter &interpreter)
17700b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "thread plan discard",
17710b57cec5SDimitry Andric                             "Discards thread plans up to and including the "
17720b57cec5SDimitry Andric                             "specified index (see 'thread plan list'.)  "
17730b57cec5SDimitry Andric                             "Only user visible plans can be discarded.",
17740b57cec5SDimitry Andric                             nullptr,
17750b57cec5SDimitry Andric                             eCommandRequiresProcess | eCommandRequiresThread |
17760b57cec5SDimitry Andric                                 eCommandTryTargetAPILock |
17770b57cec5SDimitry Andric                                 eCommandProcessMustBeLaunched |
17780b57cec5SDimitry Andric                                 eCommandProcessMustBePaused) {
17790b57cec5SDimitry Andric     CommandArgumentEntry arg;
17800b57cec5SDimitry Andric     CommandArgumentData plan_index_arg;
17810b57cec5SDimitry Andric 
17820b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
17830b57cec5SDimitry Andric     plan_index_arg.arg_type = eArgTypeUnsignedInteger;
17840b57cec5SDimitry Andric     plan_index_arg.arg_repetition = eArgRepeatPlain;
17850b57cec5SDimitry Andric 
17860b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
17870b57cec5SDimitry Andric     // argument entry.
17880b57cec5SDimitry Andric     arg.push_back(plan_index_arg);
17890b57cec5SDimitry Andric 
17900b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
17910b57cec5SDimitry Andric     m_arguments.push_back(arg);
17920b57cec5SDimitry Andric   }
17930b57cec5SDimitry Andric 
17940b57cec5SDimitry Andric   ~CommandObjectThreadPlanDiscard() override = default;
17950b57cec5SDimitry Andric 
1796af732203SDimitry Andric   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1797af732203SDimitry Andric   HandleArgumentCompletion(CompletionRequest &request,
1798af732203SDimitry Andric                            OptionElementVector &opt_element_vector) override {
1799af732203SDimitry Andric     if (!m_exe_ctx.HasThreadScope() || request.GetCursorIndex())
1800af732203SDimitry Andric       return;
1801af732203SDimitry Andric 
1802af732203SDimitry Andric     m_exe_ctx.GetThreadPtr()->AutoCompleteThreadPlans(request);
1803af732203SDimitry Andric   }
1804af732203SDimitry Andric 
DoExecute(Args & args,CommandReturnObject & result)18050b57cec5SDimitry Andric   bool DoExecute(Args &args, CommandReturnObject &result) override {
18060b57cec5SDimitry Andric     Thread *thread = m_exe_ctx.GetThreadPtr();
18070b57cec5SDimitry Andric     if (args.GetArgumentCount() != 1) {
18080b57cec5SDimitry Andric       result.AppendErrorWithFormat("Too many arguments, expected one - the "
18090b57cec5SDimitry Andric                                    "thread plan index - but got %zu.",
18100b57cec5SDimitry Andric                                    args.GetArgumentCount());
18110b57cec5SDimitry Andric       return false;
18120b57cec5SDimitry Andric     }
18130b57cec5SDimitry Andric 
18145ffd83dbSDimitry Andric     uint32_t thread_plan_idx;
18155ffd83dbSDimitry Andric     if (!llvm::to_integer(args.GetArgumentAtIndex(0), thread_plan_idx)) {
18160b57cec5SDimitry Andric       result.AppendErrorWithFormat(
18170b57cec5SDimitry Andric           "Invalid thread index: \"%s\" - should be unsigned int.",
18180b57cec5SDimitry Andric           args.GetArgumentAtIndex(0));
18190b57cec5SDimitry Andric       return false;
18200b57cec5SDimitry Andric     }
18210b57cec5SDimitry Andric 
18220b57cec5SDimitry Andric     if (thread_plan_idx == 0) {
18230b57cec5SDimitry Andric       result.AppendErrorWithFormat(
18240b57cec5SDimitry Andric           "You wouldn't really want me to discard the base thread plan.");
18250b57cec5SDimitry Andric       return false;
18260b57cec5SDimitry Andric     }
18270b57cec5SDimitry Andric 
18280b57cec5SDimitry Andric     if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) {
18290b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
18300b57cec5SDimitry Andric       return true;
18310b57cec5SDimitry Andric     } else {
18320b57cec5SDimitry Andric       result.AppendErrorWithFormat(
18330b57cec5SDimitry Andric           "Could not find User thread plan with index %s.",
18340b57cec5SDimitry Andric           args.GetArgumentAtIndex(0));
18350b57cec5SDimitry Andric       return false;
18360b57cec5SDimitry Andric     }
18370b57cec5SDimitry Andric   }
18380b57cec5SDimitry Andric };
18390b57cec5SDimitry Andric 
18405ffd83dbSDimitry Andric class CommandObjectThreadPlanPrune : public CommandObjectParsed {
18415ffd83dbSDimitry Andric public:
CommandObjectThreadPlanPrune(CommandInterpreter & interpreter)18425ffd83dbSDimitry Andric   CommandObjectThreadPlanPrune(CommandInterpreter &interpreter)
18435ffd83dbSDimitry Andric       : CommandObjectParsed(interpreter, "thread plan prune",
18445ffd83dbSDimitry Andric                             "Removes any thread plans associated with "
18455ffd83dbSDimitry Andric                             "currently unreported threads.  "
18465ffd83dbSDimitry Andric                             "Specify one or more TID's to remove, or if no "
18475ffd83dbSDimitry Andric                             "TID's are provides, remove threads for all "
18485ffd83dbSDimitry Andric                             "unreported threads",
18495ffd83dbSDimitry Andric                             nullptr,
18505ffd83dbSDimitry Andric                             eCommandRequiresProcess |
18515ffd83dbSDimitry Andric                                 eCommandTryTargetAPILock |
18525ffd83dbSDimitry Andric                                 eCommandProcessMustBeLaunched |
18535ffd83dbSDimitry Andric                                 eCommandProcessMustBePaused) {
18545ffd83dbSDimitry Andric     CommandArgumentEntry arg;
18555ffd83dbSDimitry Andric     CommandArgumentData tid_arg;
18565ffd83dbSDimitry Andric 
18575ffd83dbSDimitry Andric     // Define the first (and only) variant of this arg.
18585ffd83dbSDimitry Andric     tid_arg.arg_type = eArgTypeThreadID;
18595ffd83dbSDimitry Andric     tid_arg.arg_repetition = eArgRepeatStar;
18605ffd83dbSDimitry Andric 
18615ffd83dbSDimitry Andric     // There is only one variant this argument could be; put it into the
18625ffd83dbSDimitry Andric     // argument entry.
18635ffd83dbSDimitry Andric     arg.push_back(tid_arg);
18645ffd83dbSDimitry Andric 
18655ffd83dbSDimitry Andric     // Push the data for the first argument into the m_arguments vector.
18665ffd83dbSDimitry Andric     m_arguments.push_back(arg);
18675ffd83dbSDimitry Andric   }
18685ffd83dbSDimitry Andric 
18695ffd83dbSDimitry Andric   ~CommandObjectThreadPlanPrune() override = default;
18705ffd83dbSDimitry Andric 
DoExecute(Args & args,CommandReturnObject & result)18715ffd83dbSDimitry Andric   bool DoExecute(Args &args, CommandReturnObject &result) override {
18725ffd83dbSDimitry Andric     Process *process = m_exe_ctx.GetProcessPtr();
18735ffd83dbSDimitry Andric 
18745ffd83dbSDimitry Andric     if (args.GetArgumentCount() == 0) {
18755ffd83dbSDimitry Andric       process->PruneThreadPlans();
18765ffd83dbSDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
18775ffd83dbSDimitry Andric       return true;
18785ffd83dbSDimitry Andric     }
18795ffd83dbSDimitry Andric 
18805ffd83dbSDimitry Andric     const size_t num_args = args.GetArgumentCount();
18815ffd83dbSDimitry Andric 
18825ffd83dbSDimitry Andric     std::lock_guard<std::recursive_mutex> guard(
18835ffd83dbSDimitry Andric         process->GetThreadList().GetMutex());
18845ffd83dbSDimitry Andric 
18855ffd83dbSDimitry Andric     for (size_t i = 0; i < num_args; i++) {
18865ffd83dbSDimitry Andric       lldb::tid_t tid;
18875ffd83dbSDimitry Andric       if (!llvm::to_integer(args.GetArgumentAtIndex(i), tid)) {
18885ffd83dbSDimitry Andric         result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",
18895ffd83dbSDimitry Andric                                      args.GetArgumentAtIndex(i));
18905ffd83dbSDimitry Andric         return false;
18915ffd83dbSDimitry Andric       }
18925ffd83dbSDimitry Andric       if (!process->PruneThreadPlansForTID(tid)) {
18935ffd83dbSDimitry Andric         result.AppendErrorWithFormat("Could not find unreported tid: \"%s\"\n",
18945ffd83dbSDimitry Andric                                      args.GetArgumentAtIndex(i));
18955ffd83dbSDimitry Andric         return false;
18965ffd83dbSDimitry Andric       }
18975ffd83dbSDimitry Andric     }
18985ffd83dbSDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
18995ffd83dbSDimitry Andric     return true;
19005ffd83dbSDimitry Andric   }
19015ffd83dbSDimitry Andric };
19025ffd83dbSDimitry Andric 
19030b57cec5SDimitry Andric // CommandObjectMultiwordThreadPlan
19040b57cec5SDimitry Andric 
19050b57cec5SDimitry Andric class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword {
19060b57cec5SDimitry Andric public:
CommandObjectMultiwordThreadPlan(CommandInterpreter & interpreter)19070b57cec5SDimitry Andric   CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter)
19080b57cec5SDimitry Andric       : CommandObjectMultiword(
19090b57cec5SDimitry Andric             interpreter, "plan",
19100b57cec5SDimitry Andric             "Commands for managing thread plans that control execution.",
19110b57cec5SDimitry Andric             "thread plan <subcommand> [<subcommand objects]") {
19120b57cec5SDimitry Andric     LoadSubCommand(
19130b57cec5SDimitry Andric         "list", CommandObjectSP(new CommandObjectThreadPlanList(interpreter)));
19140b57cec5SDimitry Andric     LoadSubCommand(
19150b57cec5SDimitry Andric         "discard",
19160b57cec5SDimitry Andric         CommandObjectSP(new CommandObjectThreadPlanDiscard(interpreter)));
19175ffd83dbSDimitry Andric     LoadSubCommand(
19185ffd83dbSDimitry Andric         "prune",
19195ffd83dbSDimitry Andric         CommandObjectSP(new CommandObjectThreadPlanPrune(interpreter)));
19200b57cec5SDimitry Andric   }
19210b57cec5SDimitry Andric 
19220b57cec5SDimitry Andric   ~CommandObjectMultiwordThreadPlan() override = default;
19230b57cec5SDimitry Andric };
19240b57cec5SDimitry Andric 
1925af732203SDimitry Andric // Next are the subcommands of CommandObjectMultiwordTrace
1926af732203SDimitry Andric 
1927*5f7ddb14SDimitry Andric // CommandObjectTraceExport
1928*5f7ddb14SDimitry Andric 
1929*5f7ddb14SDimitry Andric class CommandObjectTraceExport : public CommandObjectMultiword {
1930*5f7ddb14SDimitry Andric public:
CommandObjectTraceExport(CommandInterpreter & interpreter)1931*5f7ddb14SDimitry Andric   CommandObjectTraceExport(CommandInterpreter &interpreter)
1932*5f7ddb14SDimitry Andric       : CommandObjectMultiword(
1933*5f7ddb14SDimitry Andric             interpreter, "trace thread export",
1934*5f7ddb14SDimitry Andric             "Commands for exporting traces of the threads in the current "
1935*5f7ddb14SDimitry Andric             "process to different formats.",
1936*5f7ddb14SDimitry Andric             "thread trace export <export-plugin> [<subcommand objects>]") {
1937*5f7ddb14SDimitry Andric 
1938*5f7ddb14SDimitry Andric     for (uint32_t i = 0; true; i++) {
1939*5f7ddb14SDimitry Andric       if (const char *plugin_name =
1940*5f7ddb14SDimitry Andric               PluginManager::GetTraceExporterPluginNameAtIndex(i)) {
1941*5f7ddb14SDimitry Andric         if (ThreadTraceExportCommandCreator command_creator =
1942*5f7ddb14SDimitry Andric                 PluginManager::GetThreadTraceExportCommandCreatorAtIndex(i)) {
1943*5f7ddb14SDimitry Andric           LoadSubCommand(plugin_name, command_creator(interpreter));
1944*5f7ddb14SDimitry Andric         }
1945*5f7ddb14SDimitry Andric       } else {
1946*5f7ddb14SDimitry Andric         break;
1947*5f7ddb14SDimitry Andric       }
1948*5f7ddb14SDimitry Andric     }
1949*5f7ddb14SDimitry Andric   }
1950*5f7ddb14SDimitry Andric };
1951*5f7ddb14SDimitry Andric 
1952af732203SDimitry Andric // CommandObjectTraceStart
1953af732203SDimitry Andric 
1954*5f7ddb14SDimitry Andric class CommandObjectTraceStart : public CommandObjectTraceProxy {
1955af732203SDimitry Andric public:
CommandObjectTraceStart(CommandInterpreter & interpreter)1956af732203SDimitry Andric   CommandObjectTraceStart(CommandInterpreter &interpreter)
1957*5f7ddb14SDimitry Andric       : CommandObjectTraceProxy(
1958*5f7ddb14SDimitry Andric             /*live_debug_session_only=*/true, interpreter, "thread trace start",
1959af732203SDimitry Andric             "Start tracing threads with the corresponding trace "
1960af732203SDimitry Andric             "plug-in for the current process.",
1961af732203SDimitry Andric             "thread trace start [<trace-options>]") {}
1962af732203SDimitry Andric 
1963af732203SDimitry Andric protected:
GetDelegateCommand(Trace & trace)1964*5f7ddb14SDimitry Andric   lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override {
1965*5f7ddb14SDimitry Andric     return trace.GetThreadTraceStartCommand(m_interpreter);
1966af732203SDimitry Andric   }
1967af732203SDimitry Andric };
1968af732203SDimitry Andric 
1969af732203SDimitry Andric // CommandObjectTraceStop
1970af732203SDimitry Andric 
1971*5f7ddb14SDimitry Andric class CommandObjectTraceStop : public CommandObjectMultipleThreads {
1972af732203SDimitry Andric public:
CommandObjectTraceStop(CommandInterpreter & interpreter)1973af732203SDimitry Andric   CommandObjectTraceStop(CommandInterpreter &interpreter)
1974*5f7ddb14SDimitry Andric       : CommandObjectMultipleThreads(
1975af732203SDimitry Andric             interpreter, "thread trace stop",
1976*5f7ddb14SDimitry Andric             "Stop tracing threads, including the ones traced with the "
1977*5f7ddb14SDimitry Andric             "\"process trace start\" command."
1978af732203SDimitry Andric             "Defaults to the current thread. Thread indices can be "
1979*5f7ddb14SDimitry Andric             "specified as arguments.\n Use the thread-index \"all\" to stop "
1980*5f7ddb14SDimitry Andric             "tracing "
1981*5f7ddb14SDimitry Andric             "for all existing threads.",
1982af732203SDimitry Andric             "thread trace stop [<thread-index> <thread-index> ...]",
1983af732203SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
1984af732203SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
1985af732203SDimitry Andric                 eCommandProcessMustBeTraced) {}
1986af732203SDimitry Andric 
1987af732203SDimitry Andric   ~CommandObjectTraceStop() override = default;
1988af732203SDimitry Andric 
DoExecuteOnThreads(Args & command,CommandReturnObject & result,llvm::ArrayRef<lldb::tid_t> tids)1989*5f7ddb14SDimitry Andric   bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,
1990*5f7ddb14SDimitry Andric                           llvm::ArrayRef<lldb::tid_t> tids) override {
1991*5f7ddb14SDimitry Andric     ProcessSP process_sp = m_exe_ctx.GetProcessSP();
1992af732203SDimitry Andric 
1993*5f7ddb14SDimitry Andric     TraceSP trace_sp = process_sp->GetTarget().GetTrace();
1994af732203SDimitry Andric 
1995*5f7ddb14SDimitry Andric     if (llvm::Error err = trace_sp->Stop(tids))
1996*5f7ddb14SDimitry Andric       result.AppendError(toString(std::move(err)));
1997*5f7ddb14SDimitry Andric     else
1998*5f7ddb14SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
1999*5f7ddb14SDimitry Andric 
2000*5f7ddb14SDimitry Andric     return result.Succeeded();
2001af732203SDimitry Andric   }
2002af732203SDimitry Andric };
2003af732203SDimitry Andric 
2004af732203SDimitry Andric // CommandObjectTraceDumpInstructions
2005af732203SDimitry Andric #define LLDB_OPTIONS_thread_trace_dump_instructions
2006af732203SDimitry Andric #include "CommandOptions.inc"
2007af732203SDimitry Andric 
2008af732203SDimitry Andric class CommandObjectTraceDumpInstructions
2009af732203SDimitry Andric     : public CommandObjectIterateOverThreads {
2010af732203SDimitry Andric public:
2011af732203SDimitry Andric   class CommandOptions : public Options {
2012af732203SDimitry Andric   public:
CommandOptions()2013af732203SDimitry Andric     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
2014af732203SDimitry Andric 
2015af732203SDimitry Andric     ~CommandOptions() override = default;
2016af732203SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2017af732203SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2018af732203SDimitry Andric                           ExecutionContext *execution_context) override {
2019af732203SDimitry Andric       Status error;
2020af732203SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
2021af732203SDimitry Andric 
2022af732203SDimitry Andric       switch (short_option) {
2023af732203SDimitry Andric       case 'c': {
2024af732203SDimitry Andric         int32_t count;
2025af732203SDimitry Andric         if (option_arg.empty() || option_arg.getAsInteger(0, count) ||
2026af732203SDimitry Andric             count < 0)
2027af732203SDimitry Andric           error.SetErrorStringWithFormat(
2028af732203SDimitry Andric               "invalid integer value for option '%s'",
2029af732203SDimitry Andric               option_arg.str().c_str());
2030af732203SDimitry Andric         else
2031af732203SDimitry Andric           m_count = count;
2032af732203SDimitry Andric         break;
2033af732203SDimitry Andric       }
2034*5f7ddb14SDimitry Andric       case 's': {
2035*5f7ddb14SDimitry Andric         int32_t skip;
2036*5f7ddb14SDimitry Andric         if (option_arg.empty() || option_arg.getAsInteger(0, skip) || skip < 0)
2037af732203SDimitry Andric           error.SetErrorStringWithFormat(
2038af732203SDimitry Andric               "invalid integer value for option '%s'",
2039af732203SDimitry Andric               option_arg.str().c_str());
2040af732203SDimitry Andric         else
2041*5f7ddb14SDimitry Andric           m_skip = skip;
2042af732203SDimitry Andric         break;
2043af732203SDimitry Andric       }
2044af732203SDimitry Andric       case 'r': {
2045af732203SDimitry Andric         m_raw = true;
2046af732203SDimitry Andric         break;
2047af732203SDimitry Andric       }
2048*5f7ddb14SDimitry Andric       case 'f': {
2049*5f7ddb14SDimitry Andric         m_forwards = true;
2050*5f7ddb14SDimitry Andric         break;
2051*5f7ddb14SDimitry Andric       }
2052*5f7ddb14SDimitry Andric       case 't': {
2053*5f7ddb14SDimitry Andric         m_show_tsc = true;
2054*5f7ddb14SDimitry Andric         break;
2055*5f7ddb14SDimitry Andric       }
2056af732203SDimitry Andric       default:
2057af732203SDimitry Andric         llvm_unreachable("Unimplemented option");
2058af732203SDimitry Andric       }
2059af732203SDimitry Andric       return error;
2060af732203SDimitry Andric     }
2061af732203SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)2062af732203SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
2063af732203SDimitry Andric       m_count = kDefaultCount;
2064*5f7ddb14SDimitry Andric       m_skip = 0;
2065af732203SDimitry Andric       m_raw = false;
2066*5f7ddb14SDimitry Andric       m_forwards = false;
2067*5f7ddb14SDimitry Andric       m_show_tsc = false;
2068af732203SDimitry Andric     }
2069af732203SDimitry Andric 
GetDefinitions()2070af732203SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2071af732203SDimitry Andric       return llvm::makeArrayRef(g_thread_trace_dump_instructions_options);
2072af732203SDimitry Andric     }
2073af732203SDimitry Andric 
2074af732203SDimitry Andric     static const size_t kDefaultCount = 20;
2075af732203SDimitry Andric 
2076af732203SDimitry Andric     // Instance variables to hold the values for command options.
2077af732203SDimitry Andric     size_t m_count;
2078*5f7ddb14SDimitry Andric     size_t m_skip;
2079af732203SDimitry Andric     bool m_raw;
2080*5f7ddb14SDimitry Andric     bool m_forwards;
2081*5f7ddb14SDimitry Andric     bool m_show_tsc;
2082af732203SDimitry Andric   };
2083af732203SDimitry Andric 
CommandObjectTraceDumpInstructions(CommandInterpreter & interpreter)2084af732203SDimitry Andric   CommandObjectTraceDumpInstructions(CommandInterpreter &interpreter)
2085af732203SDimitry Andric       : CommandObjectIterateOverThreads(
2086af732203SDimitry Andric             interpreter, "thread trace dump instructions",
2087af732203SDimitry Andric             "Dump the traced instructions for one or more threads. If no "
2088af732203SDimitry Andric             "threads are specified, show the current thread.  Use the "
2089af732203SDimitry Andric             "thread-index \"all\" to see all threads.",
2090af732203SDimitry Andric             nullptr,
2091af732203SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
2092af732203SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
2093af732203SDimitry Andric                 eCommandProcessMustBeTraced),
2094af732203SDimitry Andric         m_options(), m_create_repeat_command_just_invoked(false) {}
2095af732203SDimitry Andric 
2096af732203SDimitry Andric   ~CommandObjectTraceDumpInstructions() override = default;
2097af732203SDimitry Andric 
GetOptions()2098af732203SDimitry Andric   Options *GetOptions() override { return &m_options; }
2099af732203SDimitry Andric 
GetRepeatCommand(Args & current_command_args,uint32_t index)2100af732203SDimitry Andric   const char *GetRepeatCommand(Args &current_command_args,
2101af732203SDimitry Andric                                uint32_t index) override {
2102af732203SDimitry Andric     current_command_args.GetCommandString(m_repeat_command);
2103af732203SDimitry Andric     m_create_repeat_command_just_invoked = true;
2104af732203SDimitry Andric     return m_repeat_command.c_str();
2105af732203SDimitry Andric   }
2106af732203SDimitry Andric 
2107af732203SDimitry Andric protected:
DoExecute(Args & args,CommandReturnObject & result)2108af732203SDimitry Andric   bool DoExecute(Args &args, CommandReturnObject &result) override {
2109*5f7ddb14SDimitry Andric     if (!IsRepeatCommand())
2110*5f7ddb14SDimitry Andric       m_dumpers.clear();
2111*5f7ddb14SDimitry Andric 
2112af732203SDimitry Andric     bool status = CommandObjectIterateOverThreads::DoExecute(args, result);
2113af732203SDimitry Andric 
2114af732203SDimitry Andric     m_create_repeat_command_just_invoked = false;
2115af732203SDimitry Andric     return status;
2116af732203SDimitry Andric   }
2117af732203SDimitry Andric 
IsRepeatCommand()2118af732203SDimitry Andric   bool IsRepeatCommand() {
2119af732203SDimitry Andric     return !m_repeat_command.empty() && !m_create_repeat_command_just_invoked;
2120af732203SDimitry Andric   }
2121af732203SDimitry Andric 
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)2122af732203SDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
2123*5f7ddb14SDimitry Andric     Stream &s = result.GetOutputStream();
2124*5f7ddb14SDimitry Andric 
2125af732203SDimitry Andric     const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace();
2126af732203SDimitry Andric     ThreadSP thread_sp =
2127af732203SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
2128af732203SDimitry Andric 
2129*5f7ddb14SDimitry Andric     if (!m_dumpers.count(thread_sp->GetID())) {
2130*5f7ddb14SDimitry Andric       lldb::TraceCursorUP cursor_up = trace_sp->GetCursor(*thread_sp);
2131*5f7ddb14SDimitry Andric       // Set up the cursor and return the presentation index of the first
2132*5f7ddb14SDimitry Andric       // instruction to dump after skipping instructions.
2133*5f7ddb14SDimitry Andric       auto setUpCursor = [&]() {
2134*5f7ddb14SDimitry Andric         cursor_up->SetForwards(m_options.m_forwards);
2135*5f7ddb14SDimitry Andric         if (m_options.m_forwards)
2136*5f7ddb14SDimitry Andric           return cursor_up->Seek(m_options.m_skip, TraceCursor::SeekType::Set);
2137*5f7ddb14SDimitry Andric         return -cursor_up->Seek(-m_options.m_skip, TraceCursor::SeekType::End);
2138*5f7ddb14SDimitry Andric       };
2139*5f7ddb14SDimitry Andric 
2140*5f7ddb14SDimitry Andric       int initial_index = setUpCursor();
2141*5f7ddb14SDimitry Andric 
2142*5f7ddb14SDimitry Andric       auto dumper = std::make_unique<TraceInstructionDumper>(
2143*5f7ddb14SDimitry Andric           std::move(cursor_up), initial_index, m_options.m_raw,
2144*5f7ddb14SDimitry Andric           m_options.m_show_tsc);
2145*5f7ddb14SDimitry Andric 
2146*5f7ddb14SDimitry Andric       // This happens when the seek value was more than the number of available
2147*5f7ddb14SDimitry Andric       // instructions.
2148*5f7ddb14SDimitry Andric       if (std::abs(initial_index) < (int)m_options.m_skip)
2149*5f7ddb14SDimitry Andric         dumper->SetNoMoreData();
2150*5f7ddb14SDimitry Andric 
2151*5f7ddb14SDimitry Andric       m_dumpers[thread_sp->GetID()] = std::move(dumper);
2152*5f7ddb14SDimitry Andric     }
2153*5f7ddb14SDimitry Andric 
2154*5f7ddb14SDimitry Andric     m_dumpers[thread_sp->GetID()]->DumpInstructions(s, m_options.m_count);
2155af732203SDimitry Andric     return true;
2156af732203SDimitry Andric   }
2157af732203SDimitry Andric 
2158af732203SDimitry Andric   CommandOptions m_options;
2159af732203SDimitry Andric 
2160af732203SDimitry Andric   // Repeat command helpers
2161af732203SDimitry Andric   std::string m_repeat_command;
2162af732203SDimitry Andric   bool m_create_repeat_command_just_invoked;
2163*5f7ddb14SDimitry Andric   std::map<lldb::tid_t, std::unique_ptr<TraceInstructionDumper>> m_dumpers;
2164*5f7ddb14SDimitry Andric };
2165*5f7ddb14SDimitry Andric 
2166*5f7ddb14SDimitry Andric // CommandObjectTraceDumpInfo
2167*5f7ddb14SDimitry Andric #define LLDB_OPTIONS_thread_trace_dump_info
2168*5f7ddb14SDimitry Andric #include "CommandOptions.inc"
2169*5f7ddb14SDimitry Andric 
2170*5f7ddb14SDimitry Andric class CommandObjectTraceDumpInfo : public CommandObjectIterateOverThreads {
2171*5f7ddb14SDimitry Andric public:
2172*5f7ddb14SDimitry Andric   class CommandOptions : public Options {
2173*5f7ddb14SDimitry Andric   public:
CommandOptions()2174*5f7ddb14SDimitry Andric     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
2175*5f7ddb14SDimitry Andric 
2176*5f7ddb14SDimitry Andric     ~CommandOptions() override = default;
2177*5f7ddb14SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2178*5f7ddb14SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2179*5f7ddb14SDimitry Andric                           ExecutionContext *execution_context) override {
2180*5f7ddb14SDimitry Andric       Status error;
2181*5f7ddb14SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
2182*5f7ddb14SDimitry Andric 
2183*5f7ddb14SDimitry Andric       switch (short_option) {
2184*5f7ddb14SDimitry Andric       case 'v': {
2185*5f7ddb14SDimitry Andric         m_verbose = true;
2186*5f7ddb14SDimitry Andric         break;
2187*5f7ddb14SDimitry Andric       }
2188*5f7ddb14SDimitry Andric       default:
2189*5f7ddb14SDimitry Andric         llvm_unreachable("Unimplemented option");
2190*5f7ddb14SDimitry Andric       }
2191*5f7ddb14SDimitry Andric       return error;
2192*5f7ddb14SDimitry Andric     }
2193*5f7ddb14SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)2194*5f7ddb14SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
2195*5f7ddb14SDimitry Andric       m_verbose = false;
2196*5f7ddb14SDimitry Andric     }
2197*5f7ddb14SDimitry Andric 
GetDefinitions()2198*5f7ddb14SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2199*5f7ddb14SDimitry Andric       return llvm::makeArrayRef(g_thread_trace_dump_info_options);
2200*5f7ddb14SDimitry Andric     }
2201*5f7ddb14SDimitry Andric 
2202*5f7ddb14SDimitry Andric     // Instance variables to hold the values for command options.
2203*5f7ddb14SDimitry Andric     bool m_verbose;
2204*5f7ddb14SDimitry Andric   };
2205*5f7ddb14SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)2206*5f7ddb14SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
2207*5f7ddb14SDimitry Andric     Target &target = m_exe_ctx.GetTargetRef();
2208*5f7ddb14SDimitry Andric     result.GetOutputStream().Printf(
2209*5f7ddb14SDimitry Andric         "Trace technology: %s\n",
2210*5f7ddb14SDimitry Andric         target.GetTrace()->GetPluginName().AsCString());
2211*5f7ddb14SDimitry Andric     return CommandObjectIterateOverThreads::DoExecute(command, result);
2212*5f7ddb14SDimitry Andric   }
2213*5f7ddb14SDimitry Andric 
CommandObjectTraceDumpInfo(CommandInterpreter & interpreter)2214*5f7ddb14SDimitry Andric   CommandObjectTraceDumpInfo(CommandInterpreter &interpreter)
2215*5f7ddb14SDimitry Andric       : CommandObjectIterateOverThreads(
2216*5f7ddb14SDimitry Andric             interpreter, "thread trace dump info",
2217*5f7ddb14SDimitry Andric             "Dump the traced information for one or more threads.  If no "
2218*5f7ddb14SDimitry Andric             "threads are specified, show the current thread.  Use the "
2219*5f7ddb14SDimitry Andric             "thread-index \"all\" to see all threads.",
2220*5f7ddb14SDimitry Andric             nullptr,
2221*5f7ddb14SDimitry Andric             eCommandRequiresProcess | eCommandTryTargetAPILock |
2222*5f7ddb14SDimitry Andric                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
2223*5f7ddb14SDimitry Andric                 eCommandProcessMustBeTraced),
2224*5f7ddb14SDimitry Andric         m_options() {}
2225*5f7ddb14SDimitry Andric 
2226*5f7ddb14SDimitry Andric   ~CommandObjectTraceDumpInfo() override = default;
2227*5f7ddb14SDimitry Andric 
GetOptions()2228*5f7ddb14SDimitry Andric   Options *GetOptions() override { return &m_options; }
2229*5f7ddb14SDimitry Andric 
2230*5f7ddb14SDimitry Andric protected:
HandleOneThread(lldb::tid_t tid,CommandReturnObject & result)2231*5f7ddb14SDimitry Andric   bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {
2232*5f7ddb14SDimitry Andric     const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace();
2233*5f7ddb14SDimitry Andric     ThreadSP thread_sp =
2234*5f7ddb14SDimitry Andric         m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
2235*5f7ddb14SDimitry Andric     trace_sp->DumpTraceInfo(*thread_sp, result.GetOutputStream(),
2236*5f7ddb14SDimitry Andric                             m_options.m_verbose);
2237*5f7ddb14SDimitry Andric     return true;
2238*5f7ddb14SDimitry Andric   }
2239*5f7ddb14SDimitry Andric 
2240*5f7ddb14SDimitry Andric   CommandOptions m_options;
2241af732203SDimitry Andric };
2242af732203SDimitry Andric 
2243af732203SDimitry Andric // CommandObjectMultiwordTraceDump
2244af732203SDimitry Andric class CommandObjectMultiwordTraceDump : public CommandObjectMultiword {
2245af732203SDimitry Andric public:
CommandObjectMultiwordTraceDump(CommandInterpreter & interpreter)2246af732203SDimitry Andric   CommandObjectMultiwordTraceDump(CommandInterpreter &interpreter)
2247af732203SDimitry Andric       : CommandObjectMultiword(
2248af732203SDimitry Andric             interpreter, "dump",
2249af732203SDimitry Andric             "Commands for displaying trace information of the threads "
2250af732203SDimitry Andric             "in the current process.",
2251af732203SDimitry Andric             "thread trace dump <subcommand> [<subcommand objects>]") {
2252af732203SDimitry Andric     LoadSubCommand(
2253af732203SDimitry Andric         "instructions",
2254af732203SDimitry Andric         CommandObjectSP(new CommandObjectTraceDumpInstructions(interpreter)));
2255*5f7ddb14SDimitry Andric     LoadSubCommand(
2256*5f7ddb14SDimitry Andric         "info", CommandObjectSP(new CommandObjectTraceDumpInfo(interpreter)));
2257af732203SDimitry Andric   }
2258af732203SDimitry Andric   ~CommandObjectMultiwordTraceDump() override = default;
2259af732203SDimitry Andric };
2260af732203SDimitry Andric 
2261af732203SDimitry Andric // CommandObjectMultiwordTrace
2262af732203SDimitry Andric class CommandObjectMultiwordTrace : public CommandObjectMultiword {
2263af732203SDimitry Andric public:
CommandObjectMultiwordTrace(CommandInterpreter & interpreter)2264af732203SDimitry Andric   CommandObjectMultiwordTrace(CommandInterpreter &interpreter)
2265af732203SDimitry Andric       : CommandObjectMultiword(
2266af732203SDimitry Andric             interpreter, "trace",
2267af732203SDimitry Andric             "Commands for operating on traces of the threads in the current "
2268af732203SDimitry Andric             "process.",
2269af732203SDimitry Andric             "thread trace <subcommand> [<subcommand objects>]") {
2270af732203SDimitry Andric     LoadSubCommand("dump", CommandObjectSP(new CommandObjectMultiwordTraceDump(
2271af732203SDimitry Andric                                interpreter)));
2272af732203SDimitry Andric     LoadSubCommand("start",
2273af732203SDimitry Andric                    CommandObjectSP(new CommandObjectTraceStart(interpreter)));
2274af732203SDimitry Andric     LoadSubCommand("stop",
2275af732203SDimitry Andric                    CommandObjectSP(new CommandObjectTraceStop(interpreter)));
2276*5f7ddb14SDimitry Andric     LoadSubCommand("export",
2277*5f7ddb14SDimitry Andric                    CommandObjectSP(new CommandObjectTraceExport(interpreter)));
2278af732203SDimitry Andric   }
2279af732203SDimitry Andric 
2280af732203SDimitry Andric   ~CommandObjectMultiwordTrace() override = default;
2281af732203SDimitry Andric };
2282af732203SDimitry Andric 
22830b57cec5SDimitry Andric // CommandObjectMultiwordThread
22840b57cec5SDimitry Andric 
CommandObjectMultiwordThread(CommandInterpreter & interpreter)22850b57cec5SDimitry Andric CommandObjectMultiwordThread::CommandObjectMultiwordThread(
22860b57cec5SDimitry Andric     CommandInterpreter &interpreter)
2287480093f4SDimitry Andric     : CommandObjectMultiword(interpreter, "thread",
2288480093f4SDimitry Andric                              "Commands for operating on "
22890b57cec5SDimitry Andric                              "one or more threads in "
22900b57cec5SDimitry Andric                              "the current process.",
22910b57cec5SDimitry Andric                              "thread <subcommand> [<subcommand-options>]") {
22920b57cec5SDimitry Andric   LoadSubCommand("backtrace", CommandObjectSP(new CommandObjectThreadBacktrace(
22930b57cec5SDimitry Andric                                   interpreter)));
22940b57cec5SDimitry Andric   LoadSubCommand("continue",
22950b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadContinue(interpreter)));
22960b57cec5SDimitry Andric   LoadSubCommand("list",
22970b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadList(interpreter)));
22980b57cec5SDimitry Andric   LoadSubCommand("return",
22990b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadReturn(interpreter)));
23000b57cec5SDimitry Andric   LoadSubCommand("jump",
23010b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadJump(interpreter)));
23020b57cec5SDimitry Andric   LoadSubCommand("select",
23030b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadSelect(interpreter)));
23040b57cec5SDimitry Andric   LoadSubCommand("until",
23050b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadUntil(interpreter)));
23060b57cec5SDimitry Andric   LoadSubCommand("info",
23070b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadInfo(interpreter)));
2308480093f4SDimitry Andric   LoadSubCommand("exception", CommandObjectSP(new CommandObjectThreadException(
2309480093f4SDimitry Andric                                   interpreter)));
23100b57cec5SDimitry Andric   LoadSubCommand("step-in",
23110b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
23120b57cec5SDimitry Andric                      interpreter, "thread step-in",
23130b57cec5SDimitry Andric                      "Source level single step, stepping into calls.  Defaults "
23140b57cec5SDimitry Andric                      "to current thread unless specified.",
23150b57cec5SDimitry Andric                      nullptr, eStepTypeInto, eStepScopeSource)));
23160b57cec5SDimitry Andric 
23170b57cec5SDimitry Andric   LoadSubCommand("step-out",
23180b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
23190b57cec5SDimitry Andric                      interpreter, "thread step-out",
23200b57cec5SDimitry Andric                      "Finish executing the current stack frame and stop after "
23210b57cec5SDimitry Andric                      "returning.  Defaults to current thread unless specified.",
23220b57cec5SDimitry Andric                      nullptr, eStepTypeOut, eStepScopeSource)));
23230b57cec5SDimitry Andric 
23240b57cec5SDimitry Andric   LoadSubCommand("step-over",
23250b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
23260b57cec5SDimitry Andric                      interpreter, "thread step-over",
23270b57cec5SDimitry Andric                      "Source level single step, stepping over calls.  Defaults "
23280b57cec5SDimitry Andric                      "to current thread unless specified.",
23290b57cec5SDimitry Andric                      nullptr, eStepTypeOver, eStepScopeSource)));
23300b57cec5SDimitry Andric 
23310b57cec5SDimitry Andric   LoadSubCommand("step-inst",
23320b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
23330b57cec5SDimitry Andric                      interpreter, "thread step-inst",
23340b57cec5SDimitry Andric                      "Instruction level single step, stepping into calls.  "
23350b57cec5SDimitry Andric                      "Defaults to current thread unless specified.",
23360b57cec5SDimitry Andric                      nullptr, eStepTypeTrace, eStepScopeInstruction)));
23370b57cec5SDimitry Andric 
23380b57cec5SDimitry Andric   LoadSubCommand("step-inst-over",
23390b57cec5SDimitry Andric                  CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
23400b57cec5SDimitry Andric                      interpreter, "thread step-inst-over",
23410b57cec5SDimitry Andric                      "Instruction level single step, stepping over calls.  "
23420b57cec5SDimitry Andric                      "Defaults to current thread unless specified.",
23430b57cec5SDimitry Andric                      nullptr, eStepTypeTraceOver, eStepScopeInstruction)));
23440b57cec5SDimitry Andric 
23450b57cec5SDimitry Andric   LoadSubCommand(
23460b57cec5SDimitry Andric       "step-scripted",
23470b57cec5SDimitry Andric       CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(
23480b57cec5SDimitry Andric           interpreter, "thread step-scripted",
23499dba64beSDimitry Andric           "Step as instructed by the script class passed in the -C option.  "
23509dba64beSDimitry Andric           "You can also specify a dictionary of key (-k) and value (-v) pairs "
23519dba64beSDimitry Andric           "that will be used to populate an SBStructuredData Dictionary, which "
23529dba64beSDimitry Andric           "will be passed to the constructor of the class implementing the "
23539dba64beSDimitry Andric           "scripted step.  See the Python Reference for more details.",
23540b57cec5SDimitry Andric           nullptr, eStepTypeScripted, eStepScopeSource)));
23550b57cec5SDimitry Andric 
23560b57cec5SDimitry Andric   LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan(
23570b57cec5SDimitry Andric                              interpreter)));
2358af732203SDimitry Andric   LoadSubCommand("trace",
2359af732203SDimitry Andric                  CommandObjectSP(new CommandObjectMultiwordTrace(interpreter)));
23600b57cec5SDimitry Andric }
23610b57cec5SDimitry Andric 
23620b57cec5SDimitry Andric CommandObjectMultiwordThread::~CommandObjectMultiwordThread() = default;
2363