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 ¤t_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