1ac7ddfbfSEd Maste //===-- CommandObjectThread.cpp ---------------------------------*- C++ -*-===// 2ac7ddfbfSEd Maste // 3ac7ddfbfSEd Maste // The LLVM Compiler Infrastructure 4ac7ddfbfSEd Maste // 5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source 6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details. 7ac7ddfbfSEd Maste // 8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===// 9ac7ddfbfSEd Maste 10ac7ddfbfSEd Maste #include "CommandObjectThread.h" 11ac7ddfbfSEd Maste 12ac7ddfbfSEd Maste // C Includes 13ac7ddfbfSEd Maste // C++ Includes 14ac7ddfbfSEd Maste // Other libraries and framework includes 15ac7ddfbfSEd Maste // Project includes 16ac7ddfbfSEd Maste #include "lldb/Core/SourceManager.h" 17435933ddSDimitry Andric #include "lldb/Core/State.h" 181c3bbb01SEd Maste #include "lldb/Core/ValueObject.h" 19ac7ddfbfSEd Maste #include "lldb/Host/Host.h" 201c3bbb01SEd Maste #include "lldb/Host/StringConvert.h" 21ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandInterpreter.h" 22ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandReturnObject.h" 23ac7ddfbfSEd Maste #include "lldb/Interpreter/Options.h" 24ac7ddfbfSEd Maste #include "lldb/Symbol/CompileUnit.h" 25ac7ddfbfSEd Maste #include "lldb/Symbol/Function.h" 26ac7ddfbfSEd Maste #include "lldb/Symbol/LineEntry.h" 27435933ddSDimitry Andric #include "lldb/Symbol/LineTable.h" 28ac7ddfbfSEd Maste #include "lldb/Target/Process.h" 29ac7ddfbfSEd Maste #include "lldb/Target/RegisterContext.h" 30b952cd58SEd Maste #include "lldb/Target/SystemRuntime.h" 31ac7ddfbfSEd Maste #include "lldb/Target/Target.h" 32ac7ddfbfSEd Maste #include "lldb/Target/Thread.h" 33ac7ddfbfSEd Maste #include "lldb/Target/ThreadPlan.h" 34435933ddSDimitry Andric #include "lldb/Target/ThreadPlanStepInRange.h" 35ac7ddfbfSEd Maste #include "lldb/Target/ThreadPlanStepInstruction.h" 36ac7ddfbfSEd Maste #include "lldb/Target/ThreadPlanStepOut.h" 37ac7ddfbfSEd Maste #include "lldb/Target/ThreadPlanStepRange.h" 38435933ddSDimitry Andric #include "lldb/lldb-private.h" 39ac7ddfbfSEd Maste 40ac7ddfbfSEd Maste using namespace lldb; 41ac7ddfbfSEd Maste using namespace lldb_private; 42ac7ddfbfSEd Maste 43ac7ddfbfSEd Maste //------------------------------------------------------------------------- 44ac7ddfbfSEd Maste // CommandObjectThreadBacktrace 45ac7ddfbfSEd Maste //------------------------------------------------------------------------- 46ac7ddfbfSEd Maste 47435933ddSDimitry Andric class CommandObjectIterateOverThreads : public CommandObjectParsed { 487aa51b79SEd Maste public: 497aa51b79SEd Maste CommandObjectIterateOverThreads(CommandInterpreter &interpreter, 50435933ddSDimitry Andric const char *name, const char *help, 51435933ddSDimitry Andric const char *syntax, uint32_t flags) 52435933ddSDimitry Andric : CommandObjectParsed(interpreter, name, help, syntax, flags) {} 537aa51b79SEd Maste 544bb0738eSEd Maste ~CommandObjectIterateOverThreads() override = default; 559f2f44ceSEd Maste 56435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 577aa51b79SEd Maste result.SetStatus(m_success_return); 587aa51b79SEd Maste 59435933ddSDimitry Andric if (command.GetArgumentCount() == 0) { 607aa51b79SEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 614bb0738eSEd Maste if (!HandleOneThread(thread->GetID(), result)) 627aa51b79SEd Maste return false; 634bb0738eSEd Maste return result.Succeeded(); 647aa51b79SEd Maste } 654bb0738eSEd Maste 66435933ddSDimitry Andric // Use tids instead of ThreadSPs to prevent deadlocking problems which 67435933ddSDimitry Andric // result from JIT-ing 684bb0738eSEd Maste // code while iterating over the (locked) ThreadSP list. 694bb0738eSEd Maste std::vector<lldb::tid_t> tids; 704bb0738eSEd Maste 71435933ddSDimitry Andric if (command.GetArgumentCount() == 1 && 72435933ddSDimitry Andric ::strcmp(command.GetArgumentAtIndex(0), "all") == 0) { 737aa51b79SEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 747aa51b79SEd Maste 754bb0738eSEd Maste for (ThreadSP thread_sp : process->Threads()) 764bb0738eSEd Maste tids.push_back(thread_sp->GetID()); 77435933ddSDimitry Andric } else { 787aa51b79SEd Maste const size_t num_args = command.GetArgumentCount(); 797aa51b79SEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 804bb0738eSEd Maste 81435933ddSDimitry Andric std::lock_guard<std::recursive_mutex> guard( 82435933ddSDimitry Andric process->GetThreadList().GetMutex()); 837aa51b79SEd Maste 84435933ddSDimitry Andric for (size_t i = 0; i < num_args; i++) { 857aa51b79SEd Maste bool success; 867aa51b79SEd Maste 87435933ddSDimitry Andric uint32_t thread_idx = StringConvert::ToUInt32( 88435933ddSDimitry Andric command.GetArgumentAtIndex(i), 0, 0, &success); 89435933ddSDimitry Andric if (!success) { 90435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", 91435933ddSDimitry Andric command.GetArgumentAtIndex(i)); 927aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 937aa51b79SEd Maste return false; 947aa51b79SEd Maste } 957aa51b79SEd Maste 96435933ddSDimitry Andric ThreadSP thread = 97435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(thread_idx); 987aa51b79SEd Maste 99435933ddSDimitry Andric if (!thread) { 100435933ddSDimitry Andric result.AppendErrorWithFormat("no thread with index: \"%s\"\n", 101435933ddSDimitry Andric command.GetArgumentAtIndex(i)); 1027aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 1037aa51b79SEd Maste return false; 1047aa51b79SEd Maste } 1057aa51b79SEd Maste 1064bb0738eSEd Maste tids.push_back(thread->GetID()); 1074bb0738eSEd Maste } 1087aa51b79SEd Maste } 1097aa51b79SEd Maste 1104bb0738eSEd Maste uint32_t idx = 0; 111435933ddSDimitry Andric for (const lldb::tid_t &tid : tids) { 1124bb0738eSEd Maste if (idx != 0 && m_add_return) 1134bb0738eSEd Maste result.AppendMessage(""); 1144bb0738eSEd Maste 1154bb0738eSEd Maste if (!HandleOneThread(tid, result)) 1167aa51b79SEd Maste return false; 1177aa51b79SEd Maste 1184bb0738eSEd Maste ++idx; 1197aa51b79SEd Maste } 1207aa51b79SEd Maste return result.Succeeded(); 1217aa51b79SEd Maste } 1227aa51b79SEd Maste 1237aa51b79SEd Maste protected: 1247aa51b79SEd Maste // Override this to do whatever you need to do for one thread. 1257aa51b79SEd Maste // 1267aa51b79SEd Maste // If you return false, the iteration will stop, otherwise it will proceed. 127435933ddSDimitry Andric // The result is set to m_success_return (defaults to 128435933ddSDimitry Andric // eReturnStatusSuccessFinishResult) before the iteration, 129435933ddSDimitry Andric // so you only need to set the return status in HandleOneThread if you want to 130435933ddSDimitry Andric // indicate an error. 131435933ddSDimitry Andric // If m_add_return is true, a blank line will be inserted between each of the 132435933ddSDimitry Andric // listings (except the last one.) 1337aa51b79SEd Maste 134435933ddSDimitry Andric virtual bool HandleOneThread(lldb::tid_t, CommandReturnObject &result) = 0; 1357aa51b79SEd Maste 1367aa51b79SEd Maste ReturnStatus m_success_return = eReturnStatusSuccessFinishResult; 1377aa51b79SEd Maste bool m_add_return = true; 1387aa51b79SEd Maste }; 1397aa51b79SEd Maste 1407aa51b79SEd Maste //------------------------------------------------------------------------- 1417aa51b79SEd Maste // CommandObjectThreadBacktrace 1427aa51b79SEd Maste //------------------------------------------------------------------------- 1437aa51b79SEd Maste 144435933ddSDimitry Andric static OptionDefinition g_thread_backtrace_options[] = { 145435933ddSDimitry Andric // clang-format off 146435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "How many frames to display (-1 for all)" }, 147435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "start", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFrameIndex, "Frame in which to start the backtrace" }, 148435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "extended", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Show the extended backtrace, if available" } 149435933ddSDimitry Andric // clang-format on 150435933ddSDimitry Andric }; 151435933ddSDimitry Andric 152435933ddSDimitry Andric class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads { 153ac7ddfbfSEd Maste public: 154435933ddSDimitry Andric class CommandOptions : public Options { 155ac7ddfbfSEd Maste public: 156435933ddSDimitry Andric CommandOptions() : Options() { 157435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 158435933ddSDimitry Andric // () 159435933ddSDimitry Andric OptionParsingStarting(nullptr); 160ac7ddfbfSEd Maste } 161ac7ddfbfSEd Maste 1624bb0738eSEd Maste ~CommandOptions() override = default; 163ac7ddfbfSEd Maste 164435933ddSDimitry Andric Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 165435933ddSDimitry Andric ExecutionContext *execution_context) override { 166ac7ddfbfSEd Maste Error error; 167ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 168ac7ddfbfSEd Maste 169435933ddSDimitry Andric switch (short_option) { 170435933ddSDimitry Andric case 'c': { 171435933ddSDimitry Andric int32_t input_count = 0; 172435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_count)) { 173ac7ddfbfSEd Maste m_count = UINT32_MAX; 174435933ddSDimitry Andric error.SetErrorStringWithFormat( 175435933ddSDimitry Andric "invalid integer value for option '%c'", short_option); 176435933ddSDimitry Andric } else if (input_count < 0) 177435933ddSDimitry Andric m_count = UINT32_MAX; 178435933ddSDimitry Andric } break; 179ac7ddfbfSEd Maste case 's': 180435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_start)) 181435933ddSDimitry Andric error.SetErrorStringWithFormat( 182435933ddSDimitry Andric "invalid integer value for option '%c'", short_option); 1834bb0738eSEd Maste break; 184435933ddSDimitry Andric case 'e': { 185b952cd58SEd Maste bool success; 186435933ddSDimitry Andric m_extended_backtrace = 187435933ddSDimitry Andric Args::StringToBoolean(option_arg, false, &success); 188b952cd58SEd Maste if (!success) 189435933ddSDimitry Andric error.SetErrorStringWithFormat( 190435933ddSDimitry Andric "invalid boolean value for option '%c'", short_option); 191435933ddSDimitry Andric } break; 192ac7ddfbfSEd Maste default: 193435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 194435933ddSDimitry Andric short_option); 195ac7ddfbfSEd Maste break; 196ac7ddfbfSEd Maste } 197ac7ddfbfSEd Maste return error; 198ac7ddfbfSEd Maste } 199ac7ddfbfSEd Maste 200435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 201ac7ddfbfSEd Maste m_count = UINT32_MAX; 202ac7ddfbfSEd Maste m_start = 0; 203b952cd58SEd Maste m_extended_backtrace = false; 204ac7ddfbfSEd Maste } 205ac7ddfbfSEd Maste 206435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 207435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_backtrace_options); 208ac7ddfbfSEd Maste } 209ac7ddfbfSEd Maste 210ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 211ac7ddfbfSEd Maste uint32_t m_count; 212ac7ddfbfSEd Maste uint32_t m_start; 213b952cd58SEd Maste bool m_extended_backtrace; 214ac7ddfbfSEd Maste }; 215ac7ddfbfSEd Maste 2164bb0738eSEd Maste CommandObjectThreadBacktrace(CommandInterpreter &interpreter) 2174bb0738eSEd Maste : CommandObjectIterateOverThreads( 218435933ddSDimitry Andric interpreter, "thread backtrace", 219435933ddSDimitry Andric "Show thread call stacks. Defaults to the current thread, thread " 220435933ddSDimitry Andric "indexes can be specified as arguments. Use the thread-index " 221435933ddSDimitry Andric "\"all\" " 2224bb0738eSEd Maste "to see all threads.", 223435933ddSDimitry Andric nullptr, 224435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 225435933ddSDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 226435933ddSDimitry Andric eCommandProcessMustBePaused), 227435933ddSDimitry Andric m_options() {} 228ac7ddfbfSEd Maste 2294bb0738eSEd Maste ~CommandObjectThreadBacktrace() override = default; 230ac7ddfbfSEd Maste 231435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 232ac7ddfbfSEd Maste 233ac7ddfbfSEd Maste protected: 234435933ddSDimitry Andric void DoExtendedBacktrace(Thread *thread, CommandReturnObject &result) { 235b952cd58SEd Maste SystemRuntime *runtime = thread->GetProcess()->GetSystemRuntime(); 236435933ddSDimitry Andric if (runtime) { 237b952cd58SEd Maste Stream &strm = result.GetOutputStream(); 238435933ddSDimitry Andric const std::vector<ConstString> &types = 239435933ddSDimitry Andric runtime->GetExtendedBacktraceTypes(); 240435933ddSDimitry Andric for (auto type : types) { 241435933ddSDimitry Andric ThreadSP ext_thread_sp = runtime->GetExtendedBacktraceThread( 242435933ddSDimitry Andric thread->shared_from_this(), type); 243435933ddSDimitry Andric if (ext_thread_sp && ext_thread_sp->IsValid()) { 244b952cd58SEd Maste const uint32_t num_frames_with_source = 0; 245435933ddSDimitry Andric const bool stop_format = false; 246435933ddSDimitry Andric if (ext_thread_sp->GetStatus(strm, m_options.m_start, 247b952cd58SEd Maste m_options.m_count, 248435933ddSDimitry Andric num_frames_with_source, 249435933ddSDimitry Andric stop_format)) { 250b952cd58SEd Maste DoExtendedBacktrace(ext_thread_sp.get(), result); 251b952cd58SEd Maste } 252b952cd58SEd Maste } 253b952cd58SEd Maste } 254b952cd58SEd Maste } 255b952cd58SEd Maste } 256b952cd58SEd Maste 257435933ddSDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 258435933ddSDimitry Andric ThreadSP thread_sp = 259435933ddSDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 260435933ddSDimitry Andric if (!thread_sp) { 261435933ddSDimitry Andric result.AppendErrorWithFormat( 262435933ddSDimitry Andric "thread disappeared while computing backtraces: 0x%" PRIx64 "\n", 263435933ddSDimitry Andric tid); 2644bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 2654bb0738eSEd Maste return false; 2664bb0738eSEd Maste } 2674bb0738eSEd Maste 2684bb0738eSEd Maste Thread *thread = thread_sp.get(); 2694bb0738eSEd Maste 270ac7ddfbfSEd Maste Stream &strm = result.GetOutputStream(); 271ac7ddfbfSEd Maste 272ac7ddfbfSEd Maste // Don't show source context when doing backtraces. 273ac7ddfbfSEd Maste const uint32_t num_frames_with_source = 0; 274435933ddSDimitry Andric const bool stop_format = true; 275435933ddSDimitry Andric if (!thread->GetStatus(strm, m_options.m_start, m_options.m_count, 276435933ddSDimitry Andric num_frames_with_source, stop_format)) { 277435933ddSDimitry Andric result.AppendErrorWithFormat( 278435933ddSDimitry Andric "error displaying backtrace for thread: \"0x%4.4x\"\n", 279435933ddSDimitry Andric thread->GetIndexID()); 280ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 281ac7ddfbfSEd Maste return false; 282ac7ddfbfSEd Maste } 283435933ddSDimitry Andric if (m_options.m_extended_backtrace) { 2844bb0738eSEd Maste DoExtendedBacktrace(thread, result); 285b952cd58SEd Maste } 286ac7ddfbfSEd Maste 2877aa51b79SEd Maste return true; 288ac7ddfbfSEd Maste } 289ac7ddfbfSEd Maste 290ac7ddfbfSEd Maste CommandOptions m_options; 291ac7ddfbfSEd Maste }; 292ac7ddfbfSEd Maste 293435933ddSDimitry Andric enum StepScope { eStepScopeSource, eStepScopeInstruction }; 294435933ddSDimitry Andric 295435933ddSDimitry Andric static OptionEnumValueElement g_tri_running_mode[] = { 296435933ddSDimitry Andric {eOnlyThisThread, "this-thread", "Run only this thread"}, 297435933ddSDimitry Andric {eAllThreads, "all-threads", "Run all threads"}, 298435933ddSDimitry Andric {eOnlyDuringStepping, "while-stepping", 299435933ddSDimitry Andric "Run only this thread while stepping"}, 300435933ddSDimitry Andric {0, nullptr, nullptr}}; 301435933ddSDimitry Andric 302435933ddSDimitry Andric static OptionEnumValueElement g_duo_running_mode[] = { 303435933ddSDimitry Andric {eOnlyThisThread, "this-thread", "Run only this thread"}, 304435933ddSDimitry Andric {eAllThreads, "all-threads", "Run all threads"}, 305435933ddSDimitry Andric {0, nullptr, nullptr}}; 306435933ddSDimitry Andric 307435933ddSDimitry Andric static OptionDefinition g_thread_step_scope_options[] = { 308435933ddSDimitry Andric // clang-format off 309435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "step-in-avoids-no-debug", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "A boolean value that sets whether stepping into functions will step over functions with no debug information." }, 310435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "step-out-avoids-no-debug", 'A', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "A boolean value, if true stepping out of functions will continue to step out till it hits a function with debug information." }, 311435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst." }, 312435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "end-linenumber", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 1, eArgTypeLineNum, "The line at which to stop stepping - defaults to the next line and only supported for step-in and step-over. You can also pass the string 'block' to step to the end of the current block. This is particularly useful in conjunction with --step-target to step through a complex calling sequence." }, 313435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, nullptr, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread." }, 314435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "step-over-regexp", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in." }, 315435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into." }, 316435933ddSDimitry Andric { LLDB_OPT_SET_2, false, "python-class", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonClass, "The name of the class that will manage this step - only supported for Scripted Step." } 317435933ddSDimitry Andric // clang-format on 318ac7ddfbfSEd Maste }; 319ac7ddfbfSEd Maste 320435933ddSDimitry Andric class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed { 321ac7ddfbfSEd Maste public: 322435933ddSDimitry Andric class CommandOptions : public Options { 323ac7ddfbfSEd Maste public: 324435933ddSDimitry Andric CommandOptions() : Options() { 325435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 326435933ddSDimitry Andric // () 327435933ddSDimitry Andric OptionParsingStarting(nullptr); 328ac7ddfbfSEd Maste } 329ac7ddfbfSEd Maste 3304bb0738eSEd Maste ~CommandOptions() override = default; 331ac7ddfbfSEd Maste 332435933ddSDimitry Andric Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 333435933ddSDimitry Andric ExecutionContext *execution_context) override { 334ac7ddfbfSEd Maste Error error; 335ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 336ac7ddfbfSEd Maste 337435933ddSDimitry Andric switch (short_option) { 338435933ddSDimitry Andric case 'a': { 339ac7ddfbfSEd Maste bool success; 3400127ef0fSEd Maste bool avoid_no_debug = Args::StringToBoolean(option_arg, true, &success); 341ac7ddfbfSEd Maste if (!success) 342435933ddSDimitry Andric error.SetErrorStringWithFormat( 343435933ddSDimitry Andric "invalid boolean value for option '%c'", short_option); 344435933ddSDimitry Andric else { 345435933ddSDimitry Andric m_step_in_avoid_no_debug = 346435933ddSDimitry Andric avoid_no_debug ? eLazyBoolYes : eLazyBoolNo; 3470127ef0fSEd Maste } 348435933ddSDimitry Andric } break; 349ac7ddfbfSEd Maste 350435933ddSDimitry Andric case 'A': { 3510127ef0fSEd Maste bool success; 3520127ef0fSEd Maste bool avoid_no_debug = Args::StringToBoolean(option_arg, true, &success); 3530127ef0fSEd Maste if (!success) 354435933ddSDimitry Andric error.SetErrorStringWithFormat( 355435933ddSDimitry Andric "invalid boolean value for option '%c'", short_option); 356435933ddSDimitry Andric else { 357435933ddSDimitry Andric m_step_out_avoid_no_debug = 358435933ddSDimitry Andric avoid_no_debug ? eLazyBoolYes : eLazyBoolNo; 3590127ef0fSEd Maste } 360435933ddSDimitry Andric } break; 3610127ef0fSEd Maste 3620127ef0fSEd Maste case 'c': 363435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_step_count)) 364435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid step count '%s'", 365435933ddSDimitry Andric option_arg.str().c_str()); 3660127ef0fSEd Maste break; 3674bb0738eSEd Maste 3687aa51b79SEd Maste case 'C': 3697aa51b79SEd Maste m_class_name.clear(); 3707aa51b79SEd Maste m_class_name.assign(option_arg); 3717aa51b79SEd Maste break; 3724bb0738eSEd Maste 373435933ddSDimitry Andric case 'm': { 374435933ddSDimitry Andric OptionEnumValueElement *enum_values = 375435933ddSDimitry Andric GetDefinitions()[option_idx].enum_values; 376435933ddSDimitry Andric m_run_mode = (lldb::RunMode)Args::StringToOptionEnum( 377435933ddSDimitry Andric option_arg, enum_values, eOnlyDuringStepping, error); 378435933ddSDimitry Andric } break; 379ac7ddfbfSEd Maste 3804bb0738eSEd Maste case 'e': 381435933ddSDimitry Andric if (option_arg == "block") { 3824bb0738eSEd Maste m_end_line_is_block_end = 1; 3834bb0738eSEd Maste break; 3844bb0738eSEd Maste } 385435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_end_line)) 386435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid end line number '%s'", 387435933ddSDimitry Andric option_arg.str().c_str()); 3884bb0738eSEd Maste break; 3894bb0738eSEd Maste 3904bb0738eSEd Maste case 'r': 391ac7ddfbfSEd Maste m_avoid_regexp.clear(); 392ac7ddfbfSEd Maste m_avoid_regexp.assign(option_arg); 393ac7ddfbfSEd Maste break; 394ac7ddfbfSEd Maste 395ac7ddfbfSEd Maste case 't': 396ac7ddfbfSEd Maste m_step_in_target.clear(); 397ac7ddfbfSEd Maste m_step_in_target.assign(option_arg); 398ac7ddfbfSEd Maste break; 3994bb0738eSEd Maste 400ac7ddfbfSEd Maste default: 401435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 402435933ddSDimitry Andric short_option); 403ac7ddfbfSEd Maste break; 404ac7ddfbfSEd Maste } 405ac7ddfbfSEd Maste return error; 406ac7ddfbfSEd Maste } 407ac7ddfbfSEd Maste 408435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 4090127ef0fSEd Maste m_step_in_avoid_no_debug = eLazyBoolCalculate; 4100127ef0fSEd Maste m_step_out_avoid_no_debug = eLazyBoolCalculate; 411ac7ddfbfSEd Maste m_run_mode = eOnlyDuringStepping; 4121c3bbb01SEd Maste 4131c3bbb01SEd Maste // Check if we are in Non-Stop mode 414435933ddSDimitry Andric TargetSP target_sp = 415435933ddSDimitry Andric execution_context ? execution_context->GetTargetSP() : TargetSP(); 4164bb0738eSEd Maste if (target_sp && target_sp->GetNonStopModeEnabled()) 4171c3bbb01SEd Maste m_run_mode = eOnlyThisThread; 4181c3bbb01SEd Maste 419ac7ddfbfSEd Maste m_avoid_regexp.clear(); 420ac7ddfbfSEd Maste m_step_in_target.clear(); 4217aa51b79SEd Maste m_class_name.clear(); 4220127ef0fSEd Maste m_step_count = 1; 4234bb0738eSEd Maste m_end_line = LLDB_INVALID_LINE_NUMBER; 4244bb0738eSEd Maste m_end_line_is_block_end = false; 425ac7ddfbfSEd Maste } 426ac7ddfbfSEd Maste 427435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 428435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_step_scope_options); 429ac7ddfbfSEd Maste } 430ac7ddfbfSEd Maste 431ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 4320127ef0fSEd Maste LazyBool m_step_in_avoid_no_debug; 4330127ef0fSEd Maste LazyBool m_step_out_avoid_no_debug; 434ac7ddfbfSEd Maste RunMode m_run_mode; 435ac7ddfbfSEd Maste std::string m_avoid_regexp; 436ac7ddfbfSEd Maste std::string m_step_in_target; 4377aa51b79SEd Maste std::string m_class_name; 4387aa51b79SEd Maste uint32_t m_step_count; 4394bb0738eSEd Maste uint32_t m_end_line; 4404bb0738eSEd Maste bool m_end_line_is_block_end; 441ac7ddfbfSEd Maste }; 442ac7ddfbfSEd Maste 443ac7ddfbfSEd Maste CommandObjectThreadStepWithTypeAndScope(CommandInterpreter &interpreter, 444435933ddSDimitry Andric const char *name, const char *help, 445ac7ddfbfSEd Maste const char *syntax, 446ac7ddfbfSEd Maste StepType step_type, 447435933ddSDimitry Andric StepScope step_scope) 448435933ddSDimitry Andric : CommandObjectParsed(interpreter, name, help, syntax, 449435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 4501c3bbb01SEd Maste eCommandTryTargetAPILock | 4511c3bbb01SEd Maste eCommandProcessMustBeLaunched | 4521c3bbb01SEd Maste eCommandProcessMustBePaused), 453435933ddSDimitry Andric m_step_type(step_type), m_step_scope(step_scope), m_options() { 454ac7ddfbfSEd Maste CommandArgumentEntry arg; 455ac7ddfbfSEd Maste CommandArgumentData thread_id_arg; 456ac7ddfbfSEd Maste 457ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 458ac7ddfbfSEd Maste thread_id_arg.arg_type = eArgTypeThreadID; 459ac7ddfbfSEd Maste thread_id_arg.arg_repetition = eArgRepeatOptional; 460ac7ddfbfSEd Maste 461435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 462435933ddSDimitry Andric // argument entry. 463ac7ddfbfSEd Maste arg.push_back(thread_id_arg); 464ac7ddfbfSEd Maste 465ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 466ac7ddfbfSEd Maste m_arguments.push_back(arg); 467ac7ddfbfSEd Maste } 468ac7ddfbfSEd Maste 4694bb0738eSEd Maste ~CommandObjectThreadStepWithTypeAndScope() override = default; 470ac7ddfbfSEd Maste 471435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 472ac7ddfbfSEd Maste 473ac7ddfbfSEd Maste protected: 474435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 475ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 476ac7ddfbfSEd Maste bool synchronous_execution = m_interpreter.GetSynchronous(); 477ac7ddfbfSEd Maste 478ac7ddfbfSEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 4794bb0738eSEd Maste Thread *thread = nullptr; 480ac7ddfbfSEd Maste 481435933ddSDimitry Andric if (command.GetArgumentCount() == 0) { 4824bb0738eSEd Maste thread = GetDefaultThread(); 4834bb0738eSEd Maste 484435933ddSDimitry Andric if (thread == nullptr) { 485ac7ddfbfSEd Maste result.AppendError("no selected thread in process"); 486ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 487ac7ddfbfSEd Maste return false; 488ac7ddfbfSEd Maste } 489435933ddSDimitry Andric } else { 490ac7ddfbfSEd Maste const char *thread_idx_cstr = command.GetArgumentAtIndex(0); 491435933ddSDimitry Andric uint32_t step_thread_idx = 492435933ddSDimitry Andric StringConvert::ToUInt32(thread_idx_cstr, LLDB_INVALID_INDEX32); 493435933ddSDimitry Andric if (step_thread_idx == LLDB_INVALID_INDEX32) { 494435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread index '%s'.\n", 495435933ddSDimitry Andric thread_idx_cstr); 496ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 497ac7ddfbfSEd Maste return false; 498ac7ddfbfSEd Maste } 499435933ddSDimitry Andric thread = 500435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(step_thread_idx).get(); 501435933ddSDimitry Andric if (thread == nullptr) { 502435933ddSDimitry Andric result.AppendErrorWithFormat( 503435933ddSDimitry Andric "Thread index %u is out of range (valid values are 0 - %u).\n", 504ac7ddfbfSEd Maste step_thread_idx, num_threads); 505ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 506ac7ddfbfSEd Maste return false; 507ac7ddfbfSEd Maste } 508ac7ddfbfSEd Maste } 509ac7ddfbfSEd Maste 510435933ddSDimitry Andric if (m_step_type == eStepTypeScripted) { 511435933ddSDimitry Andric if (m_options.m_class_name.empty()) { 5127aa51b79SEd Maste result.AppendErrorWithFormat("empty class name for scripted step."); 5137aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 5147aa51b79SEd Maste return false; 515435933ddSDimitry Andric } else if (!m_interpreter.GetScriptInterpreter()->CheckObjectExists( 516435933ddSDimitry Andric m_options.m_class_name.c_str())) { 517435933ddSDimitry Andric result.AppendErrorWithFormat( 518435933ddSDimitry Andric "class for scripted step: \"%s\" does not exist.", 519435933ddSDimitry Andric m_options.m_class_name.c_str()); 5207aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 5217aa51b79SEd Maste return false; 5227aa51b79SEd Maste } 5237aa51b79SEd Maste } 5247aa51b79SEd Maste 525435933ddSDimitry Andric if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER && 526435933ddSDimitry Andric m_step_type != eStepTypeInto) { 527435933ddSDimitry Andric result.AppendErrorWithFormat( 528435933ddSDimitry Andric "end line option is only valid for step into"); 5294bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 5304bb0738eSEd Maste return false; 5314bb0738eSEd Maste } 5324bb0738eSEd Maste 533ac7ddfbfSEd Maste const bool abort_other_plans = false; 534ac7ddfbfSEd Maste const lldb::RunMode stop_other_threads = m_options.m_run_mode; 535ac7ddfbfSEd Maste 536435933ddSDimitry Andric // This is a bit unfortunate, but not all the commands in this command 537435933ddSDimitry Andric // object support 538ac7ddfbfSEd Maste // only while stepping, so I use the bool for them. 539ac7ddfbfSEd Maste bool bool_stop_other_threads; 540ac7ddfbfSEd Maste if (m_options.m_run_mode == eAllThreads) 541ac7ddfbfSEd Maste bool_stop_other_threads = false; 542ac7ddfbfSEd Maste else if (m_options.m_run_mode == eOnlyDuringStepping) 543435933ddSDimitry Andric bool_stop_other_threads = 544435933ddSDimitry Andric (m_step_type != eStepTypeOut && m_step_type != eStepTypeScripted); 545ac7ddfbfSEd Maste else 546ac7ddfbfSEd Maste bool_stop_other_threads = true; 547ac7ddfbfSEd Maste 548ac7ddfbfSEd Maste ThreadPlanSP new_plan_sp; 549ac7ddfbfSEd Maste 550435933ddSDimitry Andric if (m_step_type == eStepTypeInto) { 551ac7ddfbfSEd Maste StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); 5521c3bbb01SEd Maste assert(frame != nullptr); 553ac7ddfbfSEd Maste 554435933ddSDimitry Andric if (frame->HasDebugInformation()) { 5554bb0738eSEd Maste AddressRange range; 5564bb0738eSEd Maste SymbolContext sc = frame->GetSymbolContext(eSymbolContextEverything); 557435933ddSDimitry Andric if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER) { 5584bb0738eSEd Maste Error error; 559435933ddSDimitry Andric if (!sc.GetAddressRangeFromHereToEndLine(m_options.m_end_line, range, 560435933ddSDimitry Andric error)) { 561435933ddSDimitry Andric result.AppendErrorWithFormat("invalid end-line option: %s.", 562435933ddSDimitry Andric error.AsCString()); 5634bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 5644bb0738eSEd Maste return false; 5654bb0738eSEd Maste } 566435933ddSDimitry Andric } else if (m_options.m_end_line_is_block_end) { 5674bb0738eSEd Maste Error error; 5684bb0738eSEd Maste Block *block = frame->GetSymbolContext(eSymbolContextBlock).block; 569435933ddSDimitry Andric if (!block) { 5704bb0738eSEd Maste result.AppendErrorWithFormat("Could not find the current block."); 5714bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 5724bb0738eSEd Maste return false; 5734bb0738eSEd Maste } 5744bb0738eSEd Maste 5754bb0738eSEd Maste AddressRange block_range; 5764bb0738eSEd Maste Address pc_address = frame->GetFrameCodeAddress(); 5774bb0738eSEd Maste block->GetRangeContainingAddress(pc_address, block_range); 578435933ddSDimitry Andric if (!block_range.GetBaseAddress().IsValid()) { 579435933ddSDimitry Andric result.AppendErrorWithFormat( 580435933ddSDimitry Andric "Could not find the current block address."); 5814bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 5824bb0738eSEd Maste return false; 5834bb0738eSEd Maste } 584435933ddSDimitry Andric lldb::addr_t pc_offset_in_block = 585435933ddSDimitry Andric pc_address.GetFileAddress() - 586435933ddSDimitry Andric block_range.GetBaseAddress().GetFileAddress(); 587435933ddSDimitry Andric lldb::addr_t range_length = 588435933ddSDimitry Andric block_range.GetByteSize() - pc_offset_in_block; 5894bb0738eSEd Maste range = AddressRange(pc_address, range_length); 590435933ddSDimitry Andric } else { 5914bb0738eSEd Maste range = sc.line_entry.range; 5924bb0738eSEd Maste } 5934bb0738eSEd Maste 594435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepInRange( 595435933ddSDimitry Andric abort_other_plans, range, 596ac7ddfbfSEd Maste frame->GetSymbolContext(eSymbolContextEverything), 597435933ddSDimitry Andric m_options.m_step_in_target.c_str(), stop_other_threads, 5980127ef0fSEd Maste m_options.m_step_in_avoid_no_debug, 5990127ef0fSEd Maste m_options.m_step_out_avoid_no_debug); 6000127ef0fSEd Maste 601435933ddSDimitry Andric if (new_plan_sp && !m_options.m_avoid_regexp.empty()) { 602435933ddSDimitry Andric ThreadPlanStepInRange *step_in_range_plan = 603435933ddSDimitry Andric static_cast<ThreadPlanStepInRange *>(new_plan_sp.get()); 604ac7ddfbfSEd Maste step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str()); 605ac7ddfbfSEd Maste } 606435933ddSDimitry Andric } else 607435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 608435933ddSDimitry Andric false, abort_other_plans, bool_stop_other_threads); 609435933ddSDimitry Andric } else if (m_step_type == eStepTypeOver) { 610ac7ddfbfSEd Maste StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); 611ac7ddfbfSEd Maste 612ac7ddfbfSEd Maste if (frame->HasDebugInformation()) 613435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepOverRange( 614435933ddSDimitry Andric abort_other_plans, 6159f2f44ceSEd Maste frame->GetSymbolContext(eSymbolContextEverything).line_entry, 616ac7ddfbfSEd Maste frame->GetSymbolContext(eSymbolContextEverything), 617435933ddSDimitry Andric stop_other_threads, m_options.m_step_out_avoid_no_debug); 618ac7ddfbfSEd Maste else 619435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 620435933ddSDimitry Andric true, abort_other_plans, bool_stop_other_threads); 621435933ddSDimitry Andric } else if (m_step_type == eStepTypeTrace) { 622435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 623435933ddSDimitry Andric false, abort_other_plans, bool_stop_other_threads); 624435933ddSDimitry Andric } else if (m_step_type == eStepTypeTraceOver) { 625435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 626435933ddSDimitry Andric true, abort_other_plans, bool_stop_other_threads); 627435933ddSDimitry Andric } else if (m_step_type == eStepTypeOut) { 628435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepOut( 629435933ddSDimitry Andric abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes, 630435933ddSDimitry Andric eVoteNoOpinion, thread->GetSelectedFrameIndex(), 6310127ef0fSEd Maste m_options.m_step_out_avoid_no_debug); 632435933ddSDimitry Andric } else if (m_step_type == eStepTypeScripted) { 633435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepScripted( 634435933ddSDimitry Andric abort_other_plans, m_options.m_class_name.c_str(), 6357aa51b79SEd Maste bool_stop_other_threads); 636435933ddSDimitry Andric } else { 637ac7ddfbfSEd Maste result.AppendError("step type is not supported"); 638ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 639ac7ddfbfSEd Maste return false; 640ac7ddfbfSEd Maste } 641ac7ddfbfSEd Maste 642435933ddSDimitry Andric // If we got a new plan, then set it to be a master plan (User level Plans 643435933ddSDimitry Andric // should be master plans 644ac7ddfbfSEd Maste // so that they can be interruptible). Then resume the process. 645ac7ddfbfSEd Maste 646435933ddSDimitry Andric if (new_plan_sp) { 647ac7ddfbfSEd Maste new_plan_sp->SetIsMasterPlan(true); 648ac7ddfbfSEd Maste new_plan_sp->SetOkayToDiscard(false); 649ac7ddfbfSEd Maste 650435933ddSDimitry Andric if (m_options.m_step_count > 1) { 651435933ddSDimitry Andric if (new_plan_sp->SetIterationCount(m_options.m_step_count)) { 652435933ddSDimitry Andric result.AppendWarning( 653435933ddSDimitry Andric "step operation does not support iteration count."); 6540127ef0fSEd Maste } 6550127ef0fSEd Maste } 6560127ef0fSEd Maste 657ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(thread->GetID()); 6587aa51b79SEd Maste 6591c3bbb01SEd Maste const uint32_t iohandler_id = process->GetIOHandlerID(); 6601c3bbb01SEd Maste 6617aa51b79SEd Maste StreamString stream; 6627aa51b79SEd Maste Error error; 6637aa51b79SEd Maste if (synchronous_execution) 6647aa51b79SEd Maste error = process->ResumeSynchronous(&stream); 6657aa51b79SEd Maste else 6667aa51b79SEd Maste error = process->Resume(); 667ac7ddfbfSEd Maste 668435933ddSDimitry Andric // There is a race condition where this thread will return up the call 669435933ddSDimitry Andric // stack to the main command handler 670435933ddSDimitry Andric // and show an (lldb) prompt before HandlePrivateEvent (from 671435933ddSDimitry Andric // PrivateStateThread) has 6720127ef0fSEd Maste // a chance to call PushProcessIOHandler(). 6731c3bbb01SEd Maste process->SyncIOHandler(iohandler_id, 2000); 674ac7ddfbfSEd Maste 675435933ddSDimitry Andric if (synchronous_execution) { 676435933ddSDimitry Andric // If any state changed events had anything to say, add that to the 677435933ddSDimitry Andric // result 678435933ddSDimitry Andric if (stream.GetSize() > 0) 679435933ddSDimitry Andric result.AppendMessage(stream.GetString()); 680ac7ddfbfSEd Maste 681ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(thread->GetID()); 682ac7ddfbfSEd Maste result.SetDidChangeProcessState(true); 683ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 684435933ddSDimitry Andric } else { 685ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessContinuingNoResult); 686ac7ddfbfSEd Maste } 687435933ddSDimitry Andric } else { 688ac7ddfbfSEd Maste result.AppendError("Couldn't find thread plan to implement step type."); 689ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 690ac7ddfbfSEd Maste } 691ac7ddfbfSEd Maste return result.Succeeded(); 692ac7ddfbfSEd Maste } 693ac7ddfbfSEd Maste 694ac7ddfbfSEd Maste protected: 695ac7ddfbfSEd Maste StepType m_step_type; 696ac7ddfbfSEd Maste StepScope m_step_scope; 697ac7ddfbfSEd Maste CommandOptions m_options; 698ac7ddfbfSEd Maste }; 699ac7ddfbfSEd Maste 700ac7ddfbfSEd Maste //------------------------------------------------------------------------- 701ac7ddfbfSEd Maste // CommandObjectThreadContinue 702ac7ddfbfSEd Maste //------------------------------------------------------------------------- 703ac7ddfbfSEd Maste 704435933ddSDimitry Andric class CommandObjectThreadContinue : public CommandObjectParsed { 705ac7ddfbfSEd Maste public: 7064bb0738eSEd Maste CommandObjectThreadContinue(CommandInterpreter &interpreter) 707435933ddSDimitry Andric : CommandObjectParsed( 708435933ddSDimitry Andric interpreter, "thread continue", 709435933ddSDimitry Andric "Continue execution of the current target process. One " 7104bb0738eSEd Maste "or more threads may be specified, by default all " 7114bb0738eSEd Maste "threads continue.", 712435933ddSDimitry Andric nullptr, 713435933ddSDimitry Andric eCommandRequiresThread | eCommandTryTargetAPILock | 714435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { 715ac7ddfbfSEd Maste CommandArgumentEntry arg; 716ac7ddfbfSEd Maste CommandArgumentData thread_idx_arg; 717ac7ddfbfSEd Maste 718ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 719ac7ddfbfSEd Maste thread_idx_arg.arg_type = eArgTypeThreadIndex; 720ac7ddfbfSEd Maste thread_idx_arg.arg_repetition = eArgRepeatPlus; 721ac7ddfbfSEd Maste 722435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 723435933ddSDimitry Andric // argument entry. 724ac7ddfbfSEd Maste arg.push_back(thread_idx_arg); 725ac7ddfbfSEd Maste 726ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 727ac7ddfbfSEd Maste m_arguments.push_back(arg); 728ac7ddfbfSEd Maste } 729ac7ddfbfSEd Maste 7304bb0738eSEd Maste ~CommandObjectThreadContinue() override = default; 731ac7ddfbfSEd Maste 732435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 733ac7ddfbfSEd Maste bool synchronous_execution = m_interpreter.GetSynchronous(); 734ac7ddfbfSEd Maste 735435933ddSDimitry Andric if (!m_interpreter.GetDebugger().GetSelectedTarget()) { 736435933ddSDimitry Andric result.AppendError("invalid target, create a debug target using the " 737435933ddSDimitry Andric "'target create' command"); 738ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 739ac7ddfbfSEd Maste return false; 740ac7ddfbfSEd Maste } 741ac7ddfbfSEd Maste 742ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 743435933ddSDimitry Andric if (process == nullptr) { 744ac7ddfbfSEd Maste result.AppendError("no process exists. Cannot continue"); 745ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 746ac7ddfbfSEd Maste return false; 747ac7ddfbfSEd Maste } 748ac7ddfbfSEd Maste 749ac7ddfbfSEd Maste StateType state = process->GetState(); 750435933ddSDimitry Andric if ((state == eStateCrashed) || (state == eStateStopped) || 751435933ddSDimitry Andric (state == eStateSuspended)) { 752ac7ddfbfSEd Maste const size_t argc = command.GetArgumentCount(); 753435933ddSDimitry Andric if (argc > 0) { 75435617911SEd Maste // These two lines appear at the beginning of both blocks in 75535617911SEd Maste // this if..else, but that is because we need to release the 75635617911SEd Maste // lock before calling process->Resume below. 757435933ddSDimitry Andric std::lock_guard<std::recursive_mutex> guard( 758435933ddSDimitry Andric process->GetThreadList().GetMutex()); 75935617911SEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 760ac7ddfbfSEd Maste std::vector<Thread *> resume_threads; 761435933ddSDimitry Andric for (auto &entry : command.entries()) { 762435933ddSDimitry Andric uint32_t thread_idx; 763435933ddSDimitry Andric if (entry.ref.getAsInteger(0, thread_idx)) { 764435933ddSDimitry Andric result.AppendErrorWithFormat( 765435933ddSDimitry Andric "invalid thread index argument: \"%s\".\n", entry.c_str()); 766435933ddSDimitry Andric result.SetStatus(eReturnStatusFailed); 767435933ddSDimitry Andric return false; 768435933ddSDimitry Andric } 769435933ddSDimitry Andric Thread *thread = 770435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(thread_idx).get(); 771ac7ddfbfSEd Maste 772435933ddSDimitry Andric if (thread) { 773ac7ddfbfSEd Maste resume_threads.push_back(thread); 774435933ddSDimitry Andric } else { 775435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread index %u.\n", 776435933ddSDimitry Andric thread_idx); 777ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 778ac7ddfbfSEd Maste return false; 779ac7ddfbfSEd Maste } 780ac7ddfbfSEd Maste } 781ac7ddfbfSEd Maste 782435933ddSDimitry Andric if (resume_threads.empty()) { 783ac7ddfbfSEd Maste result.AppendError("no valid thread indexes were specified"); 784ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 785ac7ddfbfSEd Maste return false; 786435933ddSDimitry Andric } else { 787ac7ddfbfSEd Maste if (resume_threads.size() == 1) 788ac7ddfbfSEd Maste result.AppendMessageWithFormat("Resuming thread: "); 789ac7ddfbfSEd Maste else 790ac7ddfbfSEd Maste result.AppendMessageWithFormat("Resuming threads: "); 791ac7ddfbfSEd Maste 792435933ddSDimitry Andric for (uint32_t idx = 0; idx < num_threads; ++idx) { 793435933ddSDimitry Andric Thread *thread = 794435933ddSDimitry Andric process->GetThreadList().GetThreadAtIndex(idx).get(); 795435933ddSDimitry Andric std::vector<Thread *>::iterator this_thread_pos = 796435933ddSDimitry Andric find(resume_threads.begin(), resume_threads.end(), thread); 797ac7ddfbfSEd Maste 798435933ddSDimitry Andric if (this_thread_pos != resume_threads.end()) { 799ac7ddfbfSEd Maste resume_threads.erase(this_thread_pos); 8004bb0738eSEd Maste if (!resume_threads.empty()) 801ac7ddfbfSEd Maste result.AppendMessageWithFormat("%u, ", thread->GetIndexID()); 802ac7ddfbfSEd Maste else 803ac7ddfbfSEd Maste result.AppendMessageWithFormat("%u ", thread->GetIndexID()); 804ac7ddfbfSEd Maste 8050127ef0fSEd Maste const bool override_suspend = true; 8060127ef0fSEd Maste thread->SetResumeState(eStateRunning, override_suspend); 807435933ddSDimitry Andric } else { 808ac7ddfbfSEd Maste thread->SetResumeState(eStateSuspended); 809ac7ddfbfSEd Maste } 810ac7ddfbfSEd Maste } 811435933ddSDimitry Andric result.AppendMessageWithFormat("in process %" PRIu64 "\n", 812435933ddSDimitry Andric process->GetID()); 813ac7ddfbfSEd Maste } 814435933ddSDimitry Andric } else { 81535617911SEd Maste // These two lines appear at the beginning of both blocks in 81635617911SEd Maste // this if..else, but that is because we need to release the 81735617911SEd Maste // lock before calling process->Resume below. 818435933ddSDimitry Andric std::lock_guard<std::recursive_mutex> guard( 819435933ddSDimitry Andric process->GetThreadList().GetMutex()); 82035617911SEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 8214bb0738eSEd Maste Thread *current_thread = GetDefaultThread(); 822435933ddSDimitry Andric if (current_thread == nullptr) { 823ac7ddfbfSEd Maste result.AppendError("the process doesn't have a current thread"); 824ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 825ac7ddfbfSEd Maste return false; 826ac7ddfbfSEd Maste } 827ac7ddfbfSEd Maste // Set the actions that the threads should each take when resuming 828435933ddSDimitry Andric for (uint32_t idx = 0; idx < num_threads; ++idx) { 829ac7ddfbfSEd Maste Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get(); 830435933ddSDimitry Andric if (thread == current_thread) { 831435933ddSDimitry Andric result.AppendMessageWithFormat("Resuming thread 0x%4.4" PRIx64 832435933ddSDimitry Andric " in process %" PRIu64 "\n", 833435933ddSDimitry Andric thread->GetID(), process->GetID()); 8340127ef0fSEd Maste const bool override_suspend = true; 8350127ef0fSEd Maste thread->SetResumeState(eStateRunning, override_suspend); 836435933ddSDimitry Andric } else { 837ac7ddfbfSEd Maste thread->SetResumeState(eStateSuspended); 838ac7ddfbfSEd Maste } 839ac7ddfbfSEd Maste } 840ac7ddfbfSEd Maste } 841ac7ddfbfSEd Maste 8427aa51b79SEd Maste StreamString stream; 8437aa51b79SEd Maste Error error; 8447aa51b79SEd Maste if (synchronous_execution) 8457aa51b79SEd Maste error = process->ResumeSynchronous(&stream); 8467aa51b79SEd Maste else 8477aa51b79SEd Maste error = process->Resume(); 8487aa51b79SEd Maste 84935617911SEd Maste // We should not be holding the thread list lock when we do this. 850435933ddSDimitry Andric if (error.Success()) { 851435933ddSDimitry Andric result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n", 852435933ddSDimitry Andric process->GetID()); 853435933ddSDimitry Andric if (synchronous_execution) { 854435933ddSDimitry Andric // If any state changed events had anything to say, add that to the 855435933ddSDimitry Andric // result 856435933ddSDimitry Andric if (stream.GetSize() > 0) 857435933ddSDimitry Andric result.AppendMessage(stream.GetString()); 858ac7ddfbfSEd Maste 859ac7ddfbfSEd Maste result.SetDidChangeProcessState(true); 860ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 861435933ddSDimitry Andric } else { 862ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessContinuingNoResult); 863ac7ddfbfSEd Maste } 864435933ddSDimitry Andric } else { 865435933ddSDimitry Andric result.AppendErrorWithFormat("Failed to resume process: %s\n", 866435933ddSDimitry Andric error.AsCString()); 867ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 868ac7ddfbfSEd Maste } 869435933ddSDimitry Andric } else { 870435933ddSDimitry Andric result.AppendErrorWithFormat( 871435933ddSDimitry Andric "Process cannot be continued from its current state (%s).\n", 872ac7ddfbfSEd Maste StateAsCString(state)); 873ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 874ac7ddfbfSEd Maste } 875ac7ddfbfSEd Maste 876ac7ddfbfSEd Maste return result.Succeeded(); 877ac7ddfbfSEd Maste } 878ac7ddfbfSEd Maste }; 879ac7ddfbfSEd Maste 880ac7ddfbfSEd Maste //------------------------------------------------------------------------- 881ac7ddfbfSEd Maste // CommandObjectThreadUntil 882ac7ddfbfSEd Maste //------------------------------------------------------------------------- 883ac7ddfbfSEd Maste 884435933ddSDimitry Andric static OptionDefinition g_thread_until_options[] = { 885435933ddSDimitry Andric // clang-format off 886435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "frame", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFrameIndex, "Frame index for until operation - defaults to 0" }, 887435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "thread", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadIndex, "Thread index for the thread for until operation" }, 888435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "run-mode",'m', OptionParser::eRequiredArgument, nullptr, g_duo_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping this one" }, 889435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddressOrExpression, "Run until we reach the specified address, or leave the function - can be specified multiple times." } 890435933ddSDimitry Andric // clang-format on 891435933ddSDimitry Andric }; 892435933ddSDimitry Andric 893435933ddSDimitry Andric class CommandObjectThreadUntil : public CommandObjectParsed { 894ac7ddfbfSEd Maste public: 895435933ddSDimitry Andric class CommandOptions : public Options { 896ac7ddfbfSEd Maste public: 897ac7ddfbfSEd Maste uint32_t m_thread_idx; 898ac7ddfbfSEd Maste uint32_t m_frame_idx; 899ac7ddfbfSEd Maste 900435933ddSDimitry Andric CommandOptions() 901435933ddSDimitry Andric : Options(), m_thread_idx(LLDB_INVALID_THREAD_ID), 902435933ddSDimitry Andric m_frame_idx(LLDB_INVALID_FRAME_ID) { 903435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 904435933ddSDimitry Andric // () 905435933ddSDimitry Andric OptionParsingStarting(nullptr); 906ac7ddfbfSEd Maste } 907ac7ddfbfSEd Maste 9084bb0738eSEd Maste ~CommandOptions() override = default; 909ac7ddfbfSEd Maste 910435933ddSDimitry Andric Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 911435933ddSDimitry Andric ExecutionContext *execution_context) override { 912ac7ddfbfSEd Maste Error error; 913ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 914ac7ddfbfSEd Maste 915435933ddSDimitry Andric switch (short_option) { 916435933ddSDimitry Andric case 'a': { 917435933ddSDimitry Andric lldb::addr_t tmp_addr = Args::StringToAddress( 918435933ddSDimitry Andric execution_context, option_arg, LLDB_INVALID_ADDRESS, &error); 9191c3bbb01SEd Maste if (error.Success()) 9201c3bbb01SEd Maste m_until_addrs.push_back(tmp_addr); 921435933ddSDimitry Andric } break; 922ac7ddfbfSEd Maste case 't': 923435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_thread_idx)) { 924435933ddSDimitry Andric m_thread_idx = LLDB_INVALID_INDEX32; 925435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid thread index '%s'", 926435933ddSDimitry Andric option_arg.str().c_str()); 927ac7ddfbfSEd Maste } 928ac7ddfbfSEd Maste break; 929ac7ddfbfSEd Maste case 'f': 930435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_frame_idx)) { 931435933ddSDimitry Andric m_frame_idx = LLDB_INVALID_FRAME_ID; 932435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid frame index '%s'", 933435933ddSDimitry Andric option_arg.str().c_str()); 934ac7ddfbfSEd Maste } 935ac7ddfbfSEd Maste break; 936435933ddSDimitry Andric case 'm': { 937435933ddSDimitry Andric OptionEnumValueElement *enum_values = 938435933ddSDimitry Andric GetDefinitions()[option_idx].enum_values; 939435933ddSDimitry Andric lldb::RunMode run_mode = (lldb::RunMode)Args::StringToOptionEnum( 940435933ddSDimitry Andric option_arg, enum_values, eOnlyDuringStepping, error); 941ac7ddfbfSEd Maste 942435933ddSDimitry Andric if (error.Success()) { 943ac7ddfbfSEd Maste if (run_mode == eAllThreads) 944ac7ddfbfSEd Maste m_stop_others = false; 945ac7ddfbfSEd Maste else 946ac7ddfbfSEd Maste m_stop_others = true; 947ac7ddfbfSEd Maste } 948435933ddSDimitry Andric } break; 949ac7ddfbfSEd Maste default: 950435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 951435933ddSDimitry Andric short_option); 952ac7ddfbfSEd Maste break; 953ac7ddfbfSEd Maste } 954ac7ddfbfSEd Maste return error; 955ac7ddfbfSEd Maste } 956ac7ddfbfSEd Maste 957435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 958ac7ddfbfSEd Maste m_thread_idx = LLDB_INVALID_THREAD_ID; 959ac7ddfbfSEd Maste m_frame_idx = 0; 960ac7ddfbfSEd Maste m_stop_others = false; 9611c3bbb01SEd Maste m_until_addrs.clear(); 962ac7ddfbfSEd Maste } 963ac7ddfbfSEd Maste 964435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 965435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_until_options); 966ac7ddfbfSEd Maste } 967ac7ddfbfSEd Maste 968ac7ddfbfSEd Maste uint32_t m_step_thread_idx; 969ac7ddfbfSEd Maste bool m_stop_others; 9701c3bbb01SEd Maste std::vector<lldb::addr_t> m_until_addrs; 971ac7ddfbfSEd Maste 972ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 973ac7ddfbfSEd Maste }; 974ac7ddfbfSEd Maste 9754bb0738eSEd Maste CommandObjectThreadUntil(CommandInterpreter &interpreter) 976435933ddSDimitry Andric : CommandObjectParsed( 977435933ddSDimitry Andric interpreter, "thread until", 978435933ddSDimitry Andric "Continue until a line number or address is reached by the " 9794bb0738eSEd Maste "current or specified thread. Stops when returning from " 980435933ddSDimitry Andric "the current function as a safety measure. " 981435933ddSDimitry Andric "The target line number(s) are given as arguments, and if more than one" 982435933ddSDimitry Andric " is provided, stepping will stop when the first one is hit.", 983435933ddSDimitry Andric nullptr, 984435933ddSDimitry Andric eCommandRequiresThread | eCommandTryTargetAPILock | 9854bb0738eSEd Maste eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 986435933ddSDimitry Andric m_options() { 987ac7ddfbfSEd Maste CommandArgumentEntry arg; 988ac7ddfbfSEd Maste CommandArgumentData line_num_arg; 989ac7ddfbfSEd Maste 990ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 991ac7ddfbfSEd Maste line_num_arg.arg_type = eArgTypeLineNum; 992ac7ddfbfSEd Maste line_num_arg.arg_repetition = eArgRepeatPlain; 993ac7ddfbfSEd Maste 994435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 995435933ddSDimitry Andric // argument entry. 996ac7ddfbfSEd Maste arg.push_back(line_num_arg); 997ac7ddfbfSEd Maste 998ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 999ac7ddfbfSEd Maste m_arguments.push_back(arg); 1000ac7ddfbfSEd Maste } 1001ac7ddfbfSEd Maste 10024bb0738eSEd Maste ~CommandObjectThreadUntil() override = default; 1003ac7ddfbfSEd Maste 1004435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 1005ac7ddfbfSEd Maste 1006ac7ddfbfSEd Maste protected: 1007435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 1008ac7ddfbfSEd Maste bool synchronous_execution = m_interpreter.GetSynchronous(); 1009ac7ddfbfSEd Maste 1010ac7ddfbfSEd Maste Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 1011435933ddSDimitry Andric if (target == nullptr) { 1012435933ddSDimitry Andric result.AppendError("invalid target, create a debug target using the " 1013435933ddSDimitry Andric "'target create' command"); 1014ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1015ac7ddfbfSEd Maste return false; 1016ac7ddfbfSEd Maste } 1017ac7ddfbfSEd Maste 1018ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 1019435933ddSDimitry Andric if (process == nullptr) { 1020ac7ddfbfSEd Maste result.AppendError("need a valid process to step"); 1021ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1022435933ddSDimitry Andric } else { 10234bb0738eSEd Maste Thread *thread = nullptr; 10241c3bbb01SEd Maste std::vector<uint32_t> line_numbers; 1025ac7ddfbfSEd Maste 1026435933ddSDimitry Andric if (command.GetArgumentCount() >= 1) { 10271c3bbb01SEd Maste size_t num_args = command.GetArgumentCount(); 1028435933ddSDimitry Andric for (size_t i = 0; i < num_args; i++) { 10291c3bbb01SEd Maste uint32_t line_number; 1030435933ddSDimitry Andric line_number = StringConvert::ToUInt32(command.GetArgumentAtIndex(i), 1031435933ddSDimitry Andric UINT32_MAX); 1032435933ddSDimitry Andric if (line_number == UINT32_MAX) { 1033435933ddSDimitry Andric result.AppendErrorWithFormat("invalid line number: '%s'.\n", 1034435933ddSDimitry Andric command.GetArgumentAtIndex(i)); 1035ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1036ac7ddfbfSEd Maste return false; 1037435933ddSDimitry Andric } else 10381c3bbb01SEd Maste line_numbers.push_back(line_number); 10391c3bbb01SEd Maste } 1040435933ddSDimitry Andric } else if (m_options.m_until_addrs.empty()) { 1041435933ddSDimitry Andric result.AppendErrorWithFormat("No line number or address provided:\n%s", 1042435933ddSDimitry Andric GetSyntax().str().c_str()); 10431c3bbb01SEd Maste result.SetStatus(eReturnStatusFailed); 10441c3bbb01SEd Maste return false; 10451c3bbb01SEd Maste } 10461c3bbb01SEd Maste 1047435933ddSDimitry Andric if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) { 10484bb0738eSEd Maste thread = GetDefaultThread(); 1049435933ddSDimitry Andric } else { 1050435933ddSDimitry Andric thread = process->GetThreadList() 1051435933ddSDimitry Andric .FindThreadByIndexID(m_options.m_thread_idx) 1052435933ddSDimitry Andric .get(); 1053ac7ddfbfSEd Maste } 1054ac7ddfbfSEd Maste 1055435933ddSDimitry Andric if (thread == nullptr) { 1056ac7ddfbfSEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 1057435933ddSDimitry Andric result.AppendErrorWithFormat( 1058435933ddSDimitry Andric "Thread index %u is out of range (valid values are 0 - %u).\n", 1059435933ddSDimitry Andric m_options.m_thread_idx, num_threads); 1060ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1061ac7ddfbfSEd Maste return false; 1062ac7ddfbfSEd Maste } 1063ac7ddfbfSEd Maste 1064ac7ddfbfSEd Maste const bool abort_other_plans = false; 1065ac7ddfbfSEd Maste 1066435933ddSDimitry Andric StackFrame *frame = 1067435933ddSDimitry Andric thread->GetStackFrameAtIndex(m_options.m_frame_idx).get(); 1068435933ddSDimitry Andric if (frame == nullptr) { 1069435933ddSDimitry Andric result.AppendErrorWithFormat( 1070435933ddSDimitry Andric "Frame index %u is out of range for thread %u.\n", 1071435933ddSDimitry Andric m_options.m_frame_idx, m_options.m_thread_idx); 1072ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1073ac7ddfbfSEd Maste return false; 1074ac7ddfbfSEd Maste } 1075ac7ddfbfSEd Maste 1076ac7ddfbfSEd Maste ThreadPlanSP new_plan_sp; 1077ac7ddfbfSEd Maste 1078435933ddSDimitry Andric if (frame->HasDebugInformation()) { 1079435933ddSDimitry Andric // Finally we got here... Translate the given line number to a bunch of 1080435933ddSDimitry Andric // addresses: 1081ac7ddfbfSEd Maste SymbolContext sc(frame->GetSymbolContext(eSymbolContextCompUnit)); 10824bb0738eSEd Maste LineTable *line_table = nullptr; 1083ac7ddfbfSEd Maste if (sc.comp_unit) 1084ac7ddfbfSEd Maste line_table = sc.comp_unit->GetLineTable(); 1085ac7ddfbfSEd Maste 1086435933ddSDimitry Andric if (line_table == nullptr) { 1087435933ddSDimitry Andric result.AppendErrorWithFormat("Failed to resolve the line table for " 1088435933ddSDimitry Andric "frame %u of thread index %u.\n", 1089435933ddSDimitry Andric m_options.m_frame_idx, 1090435933ddSDimitry Andric m_options.m_thread_idx); 1091ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1092ac7ddfbfSEd Maste return false; 1093ac7ddfbfSEd Maste } 1094ac7ddfbfSEd Maste 1095ac7ddfbfSEd Maste LineEntry function_start; 1096ac7ddfbfSEd Maste uint32_t index_ptr = 0, end_ptr; 1097ac7ddfbfSEd Maste std::vector<addr_t> address_list; 1098ac7ddfbfSEd Maste 1099ac7ddfbfSEd Maste // Find the beginning & end index of the 1100ac7ddfbfSEd Maste AddressRange fun_addr_range = sc.function->GetAddressRange(); 1101ac7ddfbfSEd Maste Address fun_start_addr = fun_addr_range.GetBaseAddress(); 1102435933ddSDimitry Andric line_table->FindLineEntryByAddress(fun_start_addr, function_start, 1103435933ddSDimitry Andric &index_ptr); 1104ac7ddfbfSEd Maste 1105ac7ddfbfSEd Maste Address fun_end_addr(fun_start_addr.GetSection(), 1106435933ddSDimitry Andric fun_start_addr.GetOffset() + 1107435933ddSDimitry Andric fun_addr_range.GetByteSize()); 1108ac7ddfbfSEd Maste 1109ac7ddfbfSEd Maste bool all_in_function = true; 1110ac7ddfbfSEd Maste 1111435933ddSDimitry Andric line_table->FindLineEntryByAddress(fun_end_addr, function_start, 1112435933ddSDimitry Andric &end_ptr); 11131c3bbb01SEd Maste 1114435933ddSDimitry Andric for (uint32_t line_number : line_numbers) { 11151c3bbb01SEd Maste uint32_t start_idx_ptr = index_ptr; 1116435933ddSDimitry Andric while (start_idx_ptr <= end_ptr) { 1117ac7ddfbfSEd Maste LineEntry line_entry; 1118ac7ddfbfSEd Maste const bool exact = false; 1119435933ddSDimitry Andric start_idx_ptr = sc.comp_unit->FindLineEntry( 1120435933ddSDimitry Andric start_idx_ptr, line_number, sc.comp_unit, exact, &line_entry); 11211c3bbb01SEd Maste if (start_idx_ptr == UINT32_MAX) 1122ac7ddfbfSEd Maste break; 1123ac7ddfbfSEd Maste 1124435933ddSDimitry Andric addr_t address = 1125435933ddSDimitry Andric line_entry.range.GetBaseAddress().GetLoadAddress(target); 1126435933ddSDimitry Andric if (address != LLDB_INVALID_ADDRESS) { 1127ac7ddfbfSEd Maste if (fun_addr_range.ContainsLoadAddress(address, target)) 1128ac7ddfbfSEd Maste address_list.push_back(address); 1129ac7ddfbfSEd Maste else 1130ac7ddfbfSEd Maste all_in_function = false; 1131ac7ddfbfSEd Maste } 11321c3bbb01SEd Maste start_idx_ptr++; 11331c3bbb01SEd Maste } 11341c3bbb01SEd Maste } 11351c3bbb01SEd Maste 1136435933ddSDimitry Andric for (lldb::addr_t address : m_options.m_until_addrs) { 11371c3bbb01SEd Maste if (fun_addr_range.ContainsLoadAddress(address, target)) 11381c3bbb01SEd Maste address_list.push_back(address); 11391c3bbb01SEd Maste else 11401c3bbb01SEd Maste all_in_function = false; 1141ac7ddfbfSEd Maste } 1142ac7ddfbfSEd Maste 1143435933ddSDimitry Andric if (address_list.empty()) { 1144ac7ddfbfSEd Maste if (all_in_function) 1145435933ddSDimitry Andric result.AppendErrorWithFormat( 1146435933ddSDimitry Andric "No line entries matching until target.\n"); 1147ac7ddfbfSEd Maste else 1148435933ddSDimitry Andric result.AppendErrorWithFormat( 1149435933ddSDimitry Andric "Until target outside of the current function.\n"); 1150ac7ddfbfSEd Maste 1151ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1152ac7ddfbfSEd Maste return false; 1153ac7ddfbfSEd Maste } 1154ac7ddfbfSEd Maste 1155435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepUntil( 1156435933ddSDimitry Andric abort_other_plans, &address_list.front(), address_list.size(), 1157435933ddSDimitry Andric m_options.m_stop_others, m_options.m_frame_idx); 1158435933ddSDimitry Andric // User level plans should be master plans so they can be interrupted 1159435933ddSDimitry Andric // (e.g. by hitting a breakpoint) 1160435933ddSDimitry Andric // and other plans executed by the user (stepping around the breakpoint) 1161435933ddSDimitry Andric // and then a "continue" 1162ac7ddfbfSEd Maste // will resume the original plan. 1163ac7ddfbfSEd Maste new_plan_sp->SetIsMasterPlan(true); 1164ac7ddfbfSEd Maste new_plan_sp->SetOkayToDiscard(false); 1165435933ddSDimitry Andric } else { 1166435933ddSDimitry Andric result.AppendErrorWithFormat( 1167435933ddSDimitry Andric "Frame index %u of thread %u has no debug information.\n", 1168435933ddSDimitry Andric m_options.m_frame_idx, m_options.m_thread_idx); 1169ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1170ac7ddfbfSEd Maste return false; 1171ac7ddfbfSEd Maste } 1172ac7ddfbfSEd Maste 1173ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(m_options.m_thread_idx); 11747aa51b79SEd Maste 11757aa51b79SEd Maste StreamString stream; 11767aa51b79SEd Maste Error error; 11777aa51b79SEd Maste if (synchronous_execution) 11787aa51b79SEd Maste error = process->ResumeSynchronous(&stream); 11797aa51b79SEd Maste else 11807aa51b79SEd Maste error = process->Resume(); 11817aa51b79SEd Maste 1182435933ddSDimitry Andric if (error.Success()) { 1183435933ddSDimitry Andric result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n", 1184435933ddSDimitry Andric process->GetID()); 1185435933ddSDimitry Andric if (synchronous_execution) { 1186435933ddSDimitry Andric // If any state changed events had anything to say, add that to the 1187435933ddSDimitry Andric // result 1188435933ddSDimitry Andric if (stream.GetSize() > 0) 1189435933ddSDimitry Andric result.AppendMessage(stream.GetString()); 1190ac7ddfbfSEd Maste 1191ac7ddfbfSEd Maste result.SetDidChangeProcessState(true); 1192ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 1193435933ddSDimitry Andric } else { 1194ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessContinuingNoResult); 1195ac7ddfbfSEd Maste } 1196435933ddSDimitry Andric } else { 1197435933ddSDimitry Andric result.AppendErrorWithFormat("Failed to resume process: %s.\n", 1198435933ddSDimitry Andric error.AsCString()); 1199ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1200ac7ddfbfSEd Maste } 1201ac7ddfbfSEd Maste } 1202ac7ddfbfSEd Maste return result.Succeeded(); 1203ac7ddfbfSEd Maste } 1204ac7ddfbfSEd Maste 1205ac7ddfbfSEd Maste CommandOptions m_options; 1206ac7ddfbfSEd Maste }; 1207ac7ddfbfSEd Maste 1208ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1209ac7ddfbfSEd Maste // CommandObjectThreadSelect 1210ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1211ac7ddfbfSEd Maste 1212435933ddSDimitry Andric class CommandObjectThreadSelect : public CommandObjectParsed { 1213ac7ddfbfSEd Maste public: 12144bb0738eSEd Maste CommandObjectThreadSelect(CommandInterpreter &interpreter) 1215435933ddSDimitry Andric : CommandObjectParsed(interpreter, "thread select", 1216435933ddSDimitry Andric "Change the currently selected thread.", nullptr, 1217435933ddSDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 1218435933ddSDimitry Andric eCommandProcessMustBeLaunched | 1219435933ddSDimitry Andric eCommandProcessMustBePaused) { 1220ac7ddfbfSEd Maste CommandArgumentEntry arg; 1221ac7ddfbfSEd Maste CommandArgumentData thread_idx_arg; 1222ac7ddfbfSEd Maste 1223ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 1224ac7ddfbfSEd Maste thread_idx_arg.arg_type = eArgTypeThreadIndex; 1225ac7ddfbfSEd Maste thread_idx_arg.arg_repetition = eArgRepeatPlain; 1226ac7ddfbfSEd Maste 1227435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 1228435933ddSDimitry Andric // argument entry. 1229ac7ddfbfSEd Maste arg.push_back(thread_idx_arg); 1230ac7ddfbfSEd Maste 1231ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 1232ac7ddfbfSEd Maste m_arguments.push_back(arg); 1233ac7ddfbfSEd Maste } 1234ac7ddfbfSEd Maste 12354bb0738eSEd Maste ~CommandObjectThreadSelect() override = default; 1236ac7ddfbfSEd Maste 1237ac7ddfbfSEd Maste protected: 1238435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 1239ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 1240435933ddSDimitry Andric if (process == nullptr) { 1241ac7ddfbfSEd Maste result.AppendError("no process"); 1242ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1243ac7ddfbfSEd Maste return false; 1244435933ddSDimitry Andric } else if (command.GetArgumentCount() != 1) { 1245435933ddSDimitry Andric result.AppendErrorWithFormat( 1246435933ddSDimitry Andric "'%s' takes exactly one thread index argument:\nUsage: %s\n", 1247435933ddSDimitry Andric m_cmd_name.c_str(), m_cmd_syntax.c_str()); 1248ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1249ac7ddfbfSEd Maste return false; 1250ac7ddfbfSEd Maste } 1251ac7ddfbfSEd Maste 1252435933ddSDimitry Andric uint32_t index_id = 1253435933ddSDimitry Andric StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 1254ac7ddfbfSEd Maste 1255435933ddSDimitry Andric Thread *new_thread = 1256435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(index_id).get(); 1257435933ddSDimitry Andric if (new_thread == nullptr) { 1258435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread #%s.\n", 1259435933ddSDimitry Andric command.GetArgumentAtIndex(0)); 1260ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1261ac7ddfbfSEd Maste return false; 1262ac7ddfbfSEd Maste } 1263ac7ddfbfSEd Maste 1264ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true); 1265ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 1266ac7ddfbfSEd Maste 1267ac7ddfbfSEd Maste return result.Succeeded(); 1268ac7ddfbfSEd Maste } 1269ac7ddfbfSEd Maste }; 1270ac7ddfbfSEd Maste 1271ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1272ac7ddfbfSEd Maste // CommandObjectThreadList 1273ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1274ac7ddfbfSEd Maste 1275435933ddSDimitry Andric class CommandObjectThreadList : public CommandObjectParsed { 1276ac7ddfbfSEd Maste public: 12774bb0738eSEd Maste CommandObjectThreadList(CommandInterpreter &interpreter) 1278435933ddSDimitry Andric : CommandObjectParsed( 1279435933ddSDimitry Andric interpreter, "thread list", 1280435933ddSDimitry Andric "Show a summary of each thread in the current target process.", 1281435933ddSDimitry Andric "thread list", 1282435933ddSDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 1283435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 1284ac7ddfbfSEd Maste 12854bb0738eSEd Maste ~CommandObjectThreadList() override = default; 1286ac7ddfbfSEd Maste 1287ac7ddfbfSEd Maste protected: 1288435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 1289ac7ddfbfSEd Maste Stream &strm = result.GetOutputStream(); 1290ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 1291ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 1292ac7ddfbfSEd Maste const bool only_threads_with_stop_reason = false; 1293ac7ddfbfSEd Maste const uint32_t start_frame = 0; 1294ac7ddfbfSEd Maste const uint32_t num_frames = 0; 1295ac7ddfbfSEd Maste const uint32_t num_frames_with_source = 0; 1296ac7ddfbfSEd Maste process->GetStatus(strm); 1297435933ddSDimitry Andric process->GetThreadStatus(strm, only_threads_with_stop_reason, start_frame, 1298435933ddSDimitry Andric num_frames, num_frames_with_source, false); 1299ac7ddfbfSEd Maste return result.Succeeded(); 1300ac7ddfbfSEd Maste } 1301ac7ddfbfSEd Maste }; 1302ac7ddfbfSEd Maste 1303ac7ddfbfSEd Maste //------------------------------------------------------------------------- 13040127ef0fSEd Maste // CommandObjectThreadInfo 13050127ef0fSEd Maste //------------------------------------------------------------------------- 13060127ef0fSEd Maste 1307435933ddSDimitry Andric static OptionDefinition g_thread_info_options[] = { 1308435933ddSDimitry Andric // clang-format off 1309435933ddSDimitry Andric { LLDB_OPT_SET_ALL, false, "json", 'j', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display the thread info in JSON format." }, 1310435933ddSDimitry Andric { LLDB_OPT_SET_ALL, false, "stop-info", 's', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display the extended stop info in JSON format." } 1311435933ddSDimitry Andric // clang-format on 1312435933ddSDimitry Andric }; 1313435933ddSDimitry Andric 1314435933ddSDimitry Andric class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { 13150127ef0fSEd Maste public: 1316435933ddSDimitry Andric class CommandOptions : public Options { 13170127ef0fSEd Maste public: 1318435933ddSDimitry Andric CommandOptions() : Options() { OptionParsingStarting(nullptr); } 13190127ef0fSEd Maste 13204bb0738eSEd Maste ~CommandOptions() override = default; 13214bb0738eSEd Maste 1322435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 13237aa51b79SEd Maste m_json_thread = false; 13247aa51b79SEd Maste m_json_stopinfo = false; 13250127ef0fSEd Maste } 13260127ef0fSEd Maste 1327435933ddSDimitry Andric Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1328435933ddSDimitry Andric ExecutionContext *execution_context) override { 13290127ef0fSEd Maste const int short_option = m_getopt_table[option_idx].val; 13300127ef0fSEd Maste Error error; 13310127ef0fSEd Maste 1332435933ddSDimitry Andric switch (short_option) { 13330127ef0fSEd Maste case 'j': 13347aa51b79SEd Maste m_json_thread = true; 13357aa51b79SEd Maste break; 13367aa51b79SEd Maste 13377aa51b79SEd Maste case 's': 13387aa51b79SEd Maste m_json_stopinfo = true; 13390127ef0fSEd Maste break; 13400127ef0fSEd Maste 13410127ef0fSEd Maste default: 13420127ef0fSEd Maste return Error("invalid short option character '%c'", short_option); 13430127ef0fSEd Maste } 13440127ef0fSEd Maste return error; 13450127ef0fSEd Maste } 13460127ef0fSEd Maste 1347435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1348435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_info_options); 13490127ef0fSEd Maste } 13500127ef0fSEd Maste 13517aa51b79SEd Maste bool m_json_thread; 13527aa51b79SEd Maste bool m_json_stopinfo; 13530127ef0fSEd Maste }; 13540127ef0fSEd Maste 13554bb0738eSEd Maste CommandObjectThreadInfo(CommandInterpreter &interpreter) 13564bb0738eSEd Maste : CommandObjectIterateOverThreads( 1357435933ddSDimitry Andric interpreter, "thread info", "Show an extended summary of one or " 1358435933ddSDimitry Andric "more threads. Defaults to the " 1359435933ddSDimitry Andric "current thread.", 1360435933ddSDimitry Andric "thread info", 1361435933ddSDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 1362435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 1363435933ddSDimitry Andric m_options() { 13644bb0738eSEd Maste m_add_return = false; 13654bb0738eSEd Maste } 13664bb0738eSEd Maste 13674bb0738eSEd Maste ~CommandObjectThreadInfo() override = default; 13684bb0738eSEd Maste 1369435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 13700127ef0fSEd Maste 1371435933ddSDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 1372435933ddSDimitry Andric ThreadSP thread_sp = 1373435933ddSDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 1374435933ddSDimitry Andric if (!thread_sp) { 1375435933ddSDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", 1376435933ddSDimitry Andric tid); 13774bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 13784bb0738eSEd Maste return false; 13790127ef0fSEd Maste } 13800127ef0fSEd Maste 13814bb0738eSEd Maste Thread *thread = thread_sp.get(); 13824bb0738eSEd Maste 13830127ef0fSEd Maste Stream &strm = result.GetOutputStream(); 1384435933ddSDimitry Andric if (!thread->GetDescription(strm, eDescriptionLevelFull, 1385435933ddSDimitry Andric m_options.m_json_thread, 1386435933ddSDimitry Andric m_options.m_json_stopinfo)) { 1387435933ddSDimitry Andric result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n", 1388435933ddSDimitry Andric thread->GetIndexID()); 13890127ef0fSEd Maste result.SetStatus(eReturnStatusFailed); 13900127ef0fSEd Maste return false; 13910127ef0fSEd Maste } 13927aa51b79SEd Maste return true; 13930127ef0fSEd Maste } 13940127ef0fSEd Maste 13950127ef0fSEd Maste CommandOptions m_options; 13960127ef0fSEd Maste }; 13970127ef0fSEd Maste 13980127ef0fSEd Maste //------------------------------------------------------------------------- 1399ac7ddfbfSEd Maste // CommandObjectThreadReturn 1400ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1401ac7ddfbfSEd Maste 1402435933ddSDimitry Andric static OptionDefinition g_thread_return_options[] = { 1403435933ddSDimitry Andric // clang-format off 1404435933ddSDimitry Andric { LLDB_OPT_SET_ALL, false, "from-expression", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Return from the innermost expression evaluation." } 1405435933ddSDimitry Andric // clang-format on 1406435933ddSDimitry Andric }; 1407435933ddSDimitry Andric 1408435933ddSDimitry Andric class CommandObjectThreadReturn : public CommandObjectRaw { 1409ac7ddfbfSEd Maste public: 1410435933ddSDimitry Andric class CommandOptions : public Options { 1411ac7ddfbfSEd Maste public: 1412435933ddSDimitry Andric CommandOptions() : Options(), m_from_expression(false) { 1413435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 1414435933ddSDimitry Andric // () 1415435933ddSDimitry Andric OptionParsingStarting(nullptr); 1416ac7ddfbfSEd Maste } 1417ac7ddfbfSEd Maste 14184bb0738eSEd Maste ~CommandOptions() override = default; 1419ac7ddfbfSEd Maste 1420435933ddSDimitry Andric Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1421435933ddSDimitry Andric ExecutionContext *execution_context) override { 1422ac7ddfbfSEd Maste Error error; 1423ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 1424ac7ddfbfSEd Maste 1425435933ddSDimitry Andric switch (short_option) { 1426435933ddSDimitry Andric case 'x': { 1427ac7ddfbfSEd Maste bool success; 1428ac7ddfbfSEd Maste bool tmp_value = Args::StringToBoolean(option_arg, false, &success); 1429ac7ddfbfSEd Maste if (success) 1430ac7ddfbfSEd Maste m_from_expression = tmp_value; 1431435933ddSDimitry Andric else { 1432435933ddSDimitry Andric error.SetErrorStringWithFormat( 1433435933ddSDimitry Andric "invalid boolean value '%s' for 'x' option", 1434435933ddSDimitry Andric option_arg.str().c_str()); 1435ac7ddfbfSEd Maste } 1436435933ddSDimitry Andric } break; 1437ac7ddfbfSEd Maste default: 1438435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 1439435933ddSDimitry Andric short_option); 1440ac7ddfbfSEd Maste break; 1441ac7ddfbfSEd Maste } 1442ac7ddfbfSEd Maste return error; 1443ac7ddfbfSEd Maste } 1444ac7ddfbfSEd Maste 1445435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 1446ac7ddfbfSEd Maste m_from_expression = false; 1447ac7ddfbfSEd Maste } 1448ac7ddfbfSEd Maste 1449435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1450435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_return_options); 1451ac7ddfbfSEd Maste } 1452ac7ddfbfSEd Maste 1453ac7ddfbfSEd Maste bool m_from_expression; 1454ac7ddfbfSEd Maste 1455ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 1456ac7ddfbfSEd Maste }; 1457ac7ddfbfSEd Maste 14584bb0738eSEd Maste CommandObjectThreadReturn(CommandInterpreter &interpreter) 14594bb0738eSEd Maste : CommandObjectRaw(interpreter, "thread return", 1460435933ddSDimitry Andric "Prematurely return from a stack frame, " 1461435933ddSDimitry Andric "short-circuiting execution of newer frames " 1462435933ddSDimitry Andric "and optionally yielding a specified value. Defaults " 1463435933ddSDimitry Andric "to the exiting the current stack " 14644bb0738eSEd Maste "frame.", 1465435933ddSDimitry Andric "thread return", 1466435933ddSDimitry Andric eCommandRequiresFrame | eCommandTryTargetAPILock | 1467435933ddSDimitry Andric eCommandProcessMustBeLaunched | 1468435933ddSDimitry Andric eCommandProcessMustBePaused), 1469435933ddSDimitry Andric m_options() { 1470ac7ddfbfSEd Maste CommandArgumentEntry arg; 1471ac7ddfbfSEd Maste CommandArgumentData expression_arg; 1472ac7ddfbfSEd Maste 1473ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 1474ac7ddfbfSEd Maste expression_arg.arg_type = eArgTypeExpression; 1475ac7ddfbfSEd Maste expression_arg.arg_repetition = eArgRepeatOptional; 1476ac7ddfbfSEd Maste 1477435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 1478435933ddSDimitry Andric // argument entry. 1479ac7ddfbfSEd Maste arg.push_back(expression_arg); 1480ac7ddfbfSEd Maste 1481ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 1482ac7ddfbfSEd Maste m_arguments.push_back(arg); 1483ac7ddfbfSEd Maste } 1484ac7ddfbfSEd Maste 14854bb0738eSEd Maste ~CommandObjectThreadReturn() override = default; 14864bb0738eSEd Maste 1487435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 1488ac7ddfbfSEd Maste 1489ac7ddfbfSEd Maste protected: 1490435933ddSDimitry Andric bool DoExecute(const char *command, CommandReturnObject &result) override { 1491435933ddSDimitry Andric // I am going to handle this by hand, because I don't want you to have to 1492435933ddSDimitry Andric // say: 1493ac7ddfbfSEd Maste // "thread return -- -5". 1494435933ddSDimitry Andric if (command[0] == '-' && command[1] == 'x') { 1495ac7ddfbfSEd Maste if (command && command[2] != '\0') 1496435933ddSDimitry Andric result.AppendWarning("Return values ignored when returning from user " 1497435933ddSDimitry Andric "called expressions"); 1498ac7ddfbfSEd Maste 1499ac7ddfbfSEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 1500ac7ddfbfSEd Maste Error error; 1501ac7ddfbfSEd Maste error = thread->UnwindInnermostExpression(); 1502435933ddSDimitry Andric if (!error.Success()) { 1503435933ddSDimitry Andric result.AppendErrorWithFormat("Unwinding expression failed - %s.", 1504435933ddSDimitry Andric error.AsCString()); 1505ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1506435933ddSDimitry Andric } else { 1507435933ddSDimitry Andric bool success = 1508435933ddSDimitry Andric thread->SetSelectedFrameByIndexNoisily(0, result.GetOutputStream()); 1509435933ddSDimitry Andric if (success) { 1510ac7ddfbfSEd Maste m_exe_ctx.SetFrameSP(thread->GetSelectedFrame()); 1511ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult); 1512435933ddSDimitry Andric } else { 1513435933ddSDimitry Andric result.AppendErrorWithFormat( 1514435933ddSDimitry Andric "Could not select 0th frame after unwinding expression."); 1515ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1516ac7ddfbfSEd Maste } 1517ac7ddfbfSEd Maste } 1518ac7ddfbfSEd Maste return result.Succeeded(); 1519ac7ddfbfSEd Maste } 1520ac7ddfbfSEd Maste 1521ac7ddfbfSEd Maste ValueObjectSP return_valobj_sp; 1522ac7ddfbfSEd Maste 1523ac7ddfbfSEd Maste StackFrameSP frame_sp = m_exe_ctx.GetFrameSP(); 1524ac7ddfbfSEd Maste uint32_t frame_idx = frame_sp->GetFrameIndex(); 1525ac7ddfbfSEd Maste 1526435933ddSDimitry Andric if (frame_sp->IsInlined()) { 1527ac7ddfbfSEd Maste result.AppendError("Don't know how to return from inlined frames."); 1528ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1529ac7ddfbfSEd Maste return false; 1530ac7ddfbfSEd Maste } 1531ac7ddfbfSEd Maste 1532435933ddSDimitry Andric if (command && command[0] != '\0') { 1533ac7ddfbfSEd Maste Target *target = m_exe_ctx.GetTargetPtr(); 1534ac7ddfbfSEd Maste EvaluateExpressionOptions options; 1535ac7ddfbfSEd Maste 1536ac7ddfbfSEd Maste options.SetUnwindOnError(true); 1537ac7ddfbfSEd Maste options.SetUseDynamic(eNoDynamicValues); 1538ac7ddfbfSEd Maste 15390127ef0fSEd Maste ExpressionResults exe_results = eExpressionSetupError; 1540435933ddSDimitry Andric exe_results = target->EvaluateExpression(command, frame_sp.get(), 1541435933ddSDimitry Andric return_valobj_sp, options); 1542435933ddSDimitry Andric if (exe_results != eExpressionCompleted) { 1543ac7ddfbfSEd Maste if (return_valobj_sp) 1544435933ddSDimitry Andric result.AppendErrorWithFormat( 1545435933ddSDimitry Andric "Error evaluating result expression: %s", 1546435933ddSDimitry Andric return_valobj_sp->GetError().AsCString()); 1547ac7ddfbfSEd Maste else 1548435933ddSDimitry Andric result.AppendErrorWithFormat( 1549435933ddSDimitry Andric "Unknown error evaluating result expression."); 1550ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1551ac7ddfbfSEd Maste return false; 1552ac7ddfbfSEd Maste } 1553ac7ddfbfSEd Maste } 1554ac7ddfbfSEd Maste 1555ac7ddfbfSEd Maste Error error; 1556ac7ddfbfSEd Maste ThreadSP thread_sp = m_exe_ctx.GetThreadSP(); 1557ac7ddfbfSEd Maste const bool broadcast = true; 1558ac7ddfbfSEd Maste error = thread_sp->ReturnFromFrame(frame_sp, return_valobj_sp, broadcast); 1559435933ddSDimitry Andric if (!error.Success()) { 1560435933ddSDimitry Andric result.AppendErrorWithFormat( 1561435933ddSDimitry Andric "Error returning from frame %d of thread %d: %s.", frame_idx, 1562435933ddSDimitry Andric thread_sp->GetIndexID(), error.AsCString()); 1563ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1564ac7ddfbfSEd Maste return false; 1565ac7ddfbfSEd Maste } 1566ac7ddfbfSEd Maste 1567ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult); 1568ac7ddfbfSEd Maste return true; 1569ac7ddfbfSEd Maste } 1570ac7ddfbfSEd Maste 1571ac7ddfbfSEd Maste CommandOptions m_options; 1572ac7ddfbfSEd Maste }; 15734bb0738eSEd Maste 157435617911SEd Maste //------------------------------------------------------------------------- 157535617911SEd Maste // CommandObjectThreadJump 157635617911SEd Maste //------------------------------------------------------------------------- 157735617911SEd Maste 1578435933ddSDimitry Andric static OptionDefinition g_thread_jump_options[] = { 1579435933ddSDimitry Andric // clang-format off 1580435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specifies the source file to jump to." }, 1581435933ddSDimitry Andric { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, "Specifies the line number to jump to." }, 1582435933ddSDimitry Andric { LLDB_OPT_SET_2, true, "by", 'b', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "Jumps by a relative line offset from the current line." }, 1583435933ddSDimitry Andric { LLDB_OPT_SET_3, true, "address", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddressOrExpression, "Jumps to a specific address." }, 1584435933ddSDimitry Andric { LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "force", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Allows the PC to leave the current function." } 1585435933ddSDimitry Andric // clang-format on 1586435933ddSDimitry Andric }; 1587435933ddSDimitry Andric 1588435933ddSDimitry Andric class CommandObjectThreadJump : public CommandObjectParsed { 158935617911SEd Maste public: 1590435933ddSDimitry Andric class CommandOptions : public Options { 159135617911SEd Maste public: 1592435933ddSDimitry Andric CommandOptions() : Options() { OptionParsingStarting(nullptr); } 159335617911SEd Maste 15944bb0738eSEd Maste ~CommandOptions() override = default; 15954bb0738eSEd Maste 1596435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 159735617911SEd Maste m_filenames.Clear(); 159835617911SEd Maste m_line_num = 0; 159935617911SEd Maste m_line_offset = 0; 160035617911SEd Maste m_load_addr = LLDB_INVALID_ADDRESS; 160135617911SEd Maste m_force = false; 160235617911SEd Maste } 160335617911SEd Maste 1604435933ddSDimitry Andric Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1605435933ddSDimitry Andric ExecutionContext *execution_context) override { 160635617911SEd Maste const int short_option = m_getopt_table[option_idx].val; 160735617911SEd Maste Error error; 160835617911SEd Maste 1609435933ddSDimitry Andric switch (short_option) { 161035617911SEd Maste case 'f': 161135617911SEd Maste m_filenames.AppendIfUnique(FileSpec(option_arg, false)); 161235617911SEd Maste if (m_filenames.GetSize() > 1) 161335617911SEd Maste return Error("only one source file expected."); 161435617911SEd Maste break; 161535617911SEd Maste case 'l': 1616435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_line_num)) 1617435933ddSDimitry Andric return Error("invalid line number: '%s'.", option_arg.str().c_str()); 161835617911SEd Maste break; 161935617911SEd Maste case 'b': 1620435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_line_offset)) 1621435933ddSDimitry Andric return Error("invalid line offset: '%s'.", option_arg.str().c_str()); 162235617911SEd Maste break; 162335617911SEd Maste case 'a': 1624435933ddSDimitry Andric m_load_addr = Args::StringToAddress(execution_context, option_arg, 1625435933ddSDimitry Andric LLDB_INVALID_ADDRESS, &error); 162635617911SEd Maste break; 162735617911SEd Maste case 'r': 162835617911SEd Maste m_force = true; 162935617911SEd Maste break; 163035617911SEd Maste default: 163135617911SEd Maste return Error("invalid short option character '%c'", short_option); 163235617911SEd Maste } 163335617911SEd Maste return error; 163435617911SEd Maste } 163535617911SEd Maste 1636435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1637435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_jump_options); 163835617911SEd Maste } 163935617911SEd Maste 164035617911SEd Maste FileSpecList m_filenames; 164135617911SEd Maste uint32_t m_line_num; 164235617911SEd Maste int32_t m_line_offset; 164335617911SEd Maste lldb::addr_t m_load_addr; 164435617911SEd Maste bool m_force; 164535617911SEd Maste }; 164635617911SEd Maste 1647435933ddSDimitry Andric CommandObjectThreadJump(CommandInterpreter &interpreter) 1648435933ddSDimitry Andric : CommandObjectParsed( 1649435933ddSDimitry Andric interpreter, "thread jump", 1650435933ddSDimitry Andric "Sets the program counter to a new address.", "thread jump", 1651435933ddSDimitry Andric eCommandRequiresFrame | eCommandTryTargetAPILock | 1652435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 1653435933ddSDimitry Andric m_options() {} 165435617911SEd Maste 16554bb0738eSEd Maste ~CommandObjectThreadJump() override = default; 16564bb0738eSEd Maste 1657435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 165835617911SEd Maste 165935617911SEd Maste protected: 1660435933ddSDimitry Andric bool DoExecute(Args &args, CommandReturnObject &result) override { 166135617911SEd Maste RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext(); 166235617911SEd Maste StackFrame *frame = m_exe_ctx.GetFramePtr(); 166335617911SEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 166435617911SEd Maste Target *target = m_exe_ctx.GetTargetPtr(); 1665435933ddSDimitry Andric const SymbolContext &sym_ctx = 1666435933ddSDimitry Andric frame->GetSymbolContext(eSymbolContextLineEntry); 166735617911SEd Maste 1668435933ddSDimitry Andric if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) { 166935617911SEd Maste // Use this address directly. 167035617911SEd Maste Address dest = Address(m_options.m_load_addr); 167135617911SEd Maste 167235617911SEd Maste lldb::addr_t callAddr = dest.GetCallableLoadAddress(target); 1673435933ddSDimitry Andric if (callAddr == LLDB_INVALID_ADDRESS) { 167435617911SEd Maste result.AppendErrorWithFormat("Invalid destination address."); 167535617911SEd Maste result.SetStatus(eReturnStatusFailed); 167635617911SEd Maste return false; 167735617911SEd Maste } 167835617911SEd Maste 1679435933ddSDimitry Andric if (!reg_ctx->SetPC(callAddr)) { 1680435933ddSDimitry Andric result.AppendErrorWithFormat("Error changing PC value for thread %d.", 1681435933ddSDimitry Andric thread->GetIndexID()); 168235617911SEd Maste result.SetStatus(eReturnStatusFailed); 168335617911SEd Maste return false; 168435617911SEd Maste } 1685435933ddSDimitry Andric } else { 168635617911SEd Maste // Pick either the absolute line, or work out a relative one. 168735617911SEd Maste int32_t line = (int32_t)m_options.m_line_num; 168835617911SEd Maste if (line == 0) 168935617911SEd Maste line = sym_ctx.line_entry.line + m_options.m_line_offset; 169035617911SEd Maste 169135617911SEd Maste // Try the current file, but override if asked. 169235617911SEd Maste FileSpec file = sym_ctx.line_entry.file; 169335617911SEd Maste if (m_options.m_filenames.GetSize() == 1) 169435617911SEd Maste file = m_options.m_filenames.GetFileSpecAtIndex(0); 169535617911SEd Maste 1696435933ddSDimitry Andric if (!file) { 1697435933ddSDimitry Andric result.AppendErrorWithFormat( 1698435933ddSDimitry Andric "No source file available for the current location."); 169935617911SEd Maste result.SetStatus(eReturnStatusFailed); 170035617911SEd Maste return false; 170135617911SEd Maste } 170235617911SEd Maste 170335617911SEd Maste std::string warnings; 170435617911SEd Maste Error err = thread->JumpToLine(file, line, m_options.m_force, &warnings); 170535617911SEd Maste 1706435933ddSDimitry Andric if (err.Fail()) { 170735617911SEd Maste result.SetError(err); 170835617911SEd Maste return false; 170935617911SEd Maste } 171035617911SEd Maste 171135617911SEd Maste if (!warnings.empty()) 171235617911SEd Maste result.AppendWarning(warnings.c_str()); 171335617911SEd Maste } 171435617911SEd Maste 171535617911SEd Maste result.SetStatus(eReturnStatusSuccessFinishResult); 171635617911SEd Maste return true; 171735617911SEd Maste } 171835617911SEd Maste 171935617911SEd Maste CommandOptions m_options; 172035617911SEd Maste }; 17214bb0738eSEd Maste 1722ac7ddfbfSEd Maste //------------------------------------------------------------------------- 17237aa51b79SEd Maste // Next are the subcommands of CommandObjectMultiwordThreadPlan 17247aa51b79SEd Maste //------------------------------------------------------------------------- 17257aa51b79SEd Maste 17267aa51b79SEd Maste //------------------------------------------------------------------------- 17277aa51b79SEd Maste // CommandObjectThreadPlanList 17287aa51b79SEd Maste //------------------------------------------------------------------------- 17294bb0738eSEd Maste 1730435933ddSDimitry Andric static OptionDefinition g_thread_plan_list_options[] = { 1731435933ddSDimitry Andric // clang-format off 1732435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display more information about the thread plans" }, 1733435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "internal", 'i', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display internal as well as user thread plans" } 1734435933ddSDimitry Andric // clang-format on 1735435933ddSDimitry Andric }; 1736435933ddSDimitry Andric 1737435933ddSDimitry Andric class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads { 17387aa51b79SEd Maste public: 1739435933ddSDimitry Andric class CommandOptions : public Options { 17407aa51b79SEd Maste public: 1741435933ddSDimitry Andric CommandOptions() : Options() { 1742435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 1743435933ddSDimitry Andric // () 1744435933ddSDimitry Andric OptionParsingStarting(nullptr); 17457aa51b79SEd Maste } 17467aa51b79SEd Maste 17474bb0738eSEd Maste ~CommandOptions() override = default; 17487aa51b79SEd Maste 1749435933ddSDimitry Andric Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1750435933ddSDimitry Andric ExecutionContext *execution_context) override { 17517aa51b79SEd Maste Error error; 17527aa51b79SEd Maste const int short_option = m_getopt_table[option_idx].val; 17537aa51b79SEd Maste 1754435933ddSDimitry Andric switch (short_option) { 17557aa51b79SEd Maste case 'i': 17567aa51b79SEd Maste m_internal = true; 17577aa51b79SEd Maste break; 17587aa51b79SEd Maste case 'v': 17597aa51b79SEd Maste m_verbose = true; 17607aa51b79SEd Maste break; 17617aa51b79SEd Maste default: 1762435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 1763435933ddSDimitry Andric short_option); 17647aa51b79SEd Maste break; 17657aa51b79SEd Maste } 17667aa51b79SEd Maste return error; 17677aa51b79SEd Maste } 17687aa51b79SEd Maste 1769435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 17707aa51b79SEd Maste m_verbose = false; 17717aa51b79SEd Maste m_internal = false; 17727aa51b79SEd Maste } 17737aa51b79SEd Maste 1774435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1775435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_plan_list_options); 17767aa51b79SEd Maste } 17777aa51b79SEd Maste 17787aa51b79SEd Maste // Instance variables to hold the values for command options. 17797aa51b79SEd Maste bool m_verbose; 17807aa51b79SEd Maste bool m_internal; 17817aa51b79SEd Maste }; 17827aa51b79SEd Maste 17834bb0738eSEd Maste CommandObjectThreadPlanList(CommandInterpreter &interpreter) 17844bb0738eSEd Maste : CommandObjectIterateOverThreads( 17854bb0738eSEd Maste interpreter, "thread plan list", 1786435933ddSDimitry Andric "Show thread plans for one or more threads. If no threads are " 1787435933ddSDimitry Andric "specified, show the " 17884bb0738eSEd Maste "current thread. Use the thread-index \"all\" to see all threads.", 1789435933ddSDimitry Andric nullptr, 1790435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 1791435933ddSDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 1792435933ddSDimitry Andric eCommandProcessMustBePaused), 1793435933ddSDimitry Andric m_options() {} 17947aa51b79SEd Maste 17954bb0738eSEd Maste ~CommandObjectThreadPlanList() override = default; 17967aa51b79SEd Maste 1797435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 17987aa51b79SEd Maste 17997aa51b79SEd Maste protected: 1800435933ddSDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 1801435933ddSDimitry Andric ThreadSP thread_sp = 1802435933ddSDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 1803435933ddSDimitry Andric if (!thread_sp) { 1804435933ddSDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", 1805435933ddSDimitry Andric tid); 18064bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 18074bb0738eSEd Maste return false; 18084bb0738eSEd Maste } 18094bb0738eSEd Maste 18104bb0738eSEd Maste Thread *thread = thread_sp.get(); 18114bb0738eSEd Maste 18127aa51b79SEd Maste Stream &strm = result.GetOutputStream(); 18137aa51b79SEd Maste DescriptionLevel desc_level = eDescriptionLevelFull; 18147aa51b79SEd Maste if (m_options.m_verbose) 18157aa51b79SEd Maste desc_level = eDescriptionLevelVerbose; 18167aa51b79SEd Maste 18174bb0738eSEd Maste thread->DumpThreadPlans(&strm, desc_level, m_options.m_internal, true); 18187aa51b79SEd Maste return true; 18197aa51b79SEd Maste } 18204bb0738eSEd Maste 18217aa51b79SEd Maste CommandOptions m_options; 18227aa51b79SEd Maste }; 18237aa51b79SEd Maste 1824435933ddSDimitry Andric class CommandObjectThreadPlanDiscard : public CommandObjectParsed { 18257aa51b79SEd Maste public: 18264bb0738eSEd Maste CommandObjectThreadPlanDiscard(CommandInterpreter &interpreter) 1827435933ddSDimitry Andric : CommandObjectParsed(interpreter, "thread plan discard", 1828435933ddSDimitry Andric "Discards thread plans up to and including the " 1829435933ddSDimitry Andric "specified index (see 'thread plan list'.) " 18304bb0738eSEd Maste "Only user visible plans can be discarded.", 1831435933ddSDimitry Andric nullptr, 1832435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 1833435933ddSDimitry Andric eCommandTryTargetAPILock | 1834435933ddSDimitry Andric eCommandProcessMustBeLaunched | 1835435933ddSDimitry Andric eCommandProcessMustBePaused) { 18367aa51b79SEd Maste CommandArgumentEntry arg; 18377aa51b79SEd Maste CommandArgumentData plan_index_arg; 18387aa51b79SEd Maste 18397aa51b79SEd Maste // Define the first (and only) variant of this arg. 18407aa51b79SEd Maste plan_index_arg.arg_type = eArgTypeUnsignedInteger; 18417aa51b79SEd Maste plan_index_arg.arg_repetition = eArgRepeatPlain; 18427aa51b79SEd Maste 1843435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 1844435933ddSDimitry Andric // argument entry. 18457aa51b79SEd Maste arg.push_back(plan_index_arg); 18467aa51b79SEd Maste 18477aa51b79SEd Maste // Push the data for the first argument into the m_arguments vector. 18487aa51b79SEd Maste m_arguments.push_back(arg); 18497aa51b79SEd Maste } 18507aa51b79SEd Maste 18514bb0738eSEd Maste ~CommandObjectThreadPlanDiscard() override = default; 18527aa51b79SEd Maste 1853435933ddSDimitry Andric bool DoExecute(Args &args, CommandReturnObject &result) override { 18547aa51b79SEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 1855435933ddSDimitry Andric if (args.GetArgumentCount() != 1) { 1856435933ddSDimitry Andric result.AppendErrorWithFormat("Too many arguments, expected one - the " 1857435933ddSDimitry Andric "thread plan index - but got %zu.", 18587aa51b79SEd Maste args.GetArgumentCount()); 18597aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 18607aa51b79SEd Maste return false; 18617aa51b79SEd Maste } 18627aa51b79SEd Maste 18637aa51b79SEd Maste bool success; 1864435933ddSDimitry Andric uint32_t thread_plan_idx = 1865435933ddSDimitry Andric StringConvert::ToUInt32(args.GetArgumentAtIndex(0), 0, 0, &success); 1866435933ddSDimitry Andric if (!success) { 1867435933ddSDimitry Andric result.AppendErrorWithFormat( 1868435933ddSDimitry Andric "Invalid thread index: \"%s\" - should be unsigned int.", 18697aa51b79SEd Maste args.GetArgumentAtIndex(0)); 18707aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 18717aa51b79SEd Maste return false; 18727aa51b79SEd Maste } 18737aa51b79SEd Maste 1874435933ddSDimitry Andric if (thread_plan_idx == 0) { 1875435933ddSDimitry Andric result.AppendErrorWithFormat( 1876435933ddSDimitry Andric "You wouldn't really want me to discard the base thread plan."); 18777aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 18787aa51b79SEd Maste return false; 18797aa51b79SEd Maste } 18807aa51b79SEd Maste 1881435933ddSDimitry Andric if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) { 18827aa51b79SEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 18837aa51b79SEd Maste return true; 1884435933ddSDimitry Andric } else { 1885435933ddSDimitry Andric result.AppendErrorWithFormat( 1886435933ddSDimitry Andric "Could not find User thread plan with index %s.", 18877aa51b79SEd Maste args.GetArgumentAtIndex(0)); 18887aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 18897aa51b79SEd Maste return false; 18907aa51b79SEd Maste } 18917aa51b79SEd Maste } 18927aa51b79SEd Maste }; 18937aa51b79SEd Maste 18947aa51b79SEd Maste //------------------------------------------------------------------------- 18957aa51b79SEd Maste // CommandObjectMultiwordThreadPlan 18967aa51b79SEd Maste //------------------------------------------------------------------------- 18977aa51b79SEd Maste 1898435933ddSDimitry Andric class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword { 18997aa51b79SEd Maste public: 19004bb0738eSEd Maste CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter) 1901435933ddSDimitry Andric : CommandObjectMultiword( 1902435933ddSDimitry Andric interpreter, "plan", 1903435933ddSDimitry Andric "Commands for managing thread plans that control execution.", 1904435933ddSDimitry Andric "thread plan <subcommand> [<subcommand objects]") { 1905435933ddSDimitry Andric LoadSubCommand( 1906435933ddSDimitry Andric "list", CommandObjectSP(new CommandObjectThreadPlanList(interpreter))); 1907435933ddSDimitry Andric LoadSubCommand( 1908435933ddSDimitry Andric "discard", 1909435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadPlanDiscard(interpreter))); 19107aa51b79SEd Maste } 19117aa51b79SEd Maste 19124bb0738eSEd Maste ~CommandObjectMultiwordThreadPlan() override = default; 19137aa51b79SEd Maste }; 19147aa51b79SEd Maste 19157aa51b79SEd Maste //------------------------------------------------------------------------- 1916ac7ddfbfSEd Maste // CommandObjectMultiwordThread 1917ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1918ac7ddfbfSEd Maste 1919435933ddSDimitry Andric CommandObjectMultiwordThread::CommandObjectMultiwordThread( 1920435933ddSDimitry Andric CommandInterpreter &interpreter) 1921435933ddSDimitry Andric : CommandObjectMultiword(interpreter, "thread", "Commands for operating on " 1922435933ddSDimitry Andric "one or more threads in " 1923435933ddSDimitry Andric "the current process.", 1924435933ddSDimitry Andric "thread <subcommand> [<subcommand-options>]") { 1925435933ddSDimitry Andric LoadSubCommand("backtrace", CommandObjectSP(new CommandObjectThreadBacktrace( 1926435933ddSDimitry Andric interpreter))); 1927435933ddSDimitry Andric LoadSubCommand("continue", 1928435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadContinue(interpreter))); 1929435933ddSDimitry Andric LoadSubCommand("list", 1930435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadList(interpreter))); 1931435933ddSDimitry Andric LoadSubCommand("return", 1932435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadReturn(interpreter))); 1933435933ddSDimitry Andric LoadSubCommand("jump", 1934435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadJump(interpreter))); 1935435933ddSDimitry Andric LoadSubCommand("select", 1936435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadSelect(interpreter))); 1937435933ddSDimitry Andric LoadSubCommand("until", 1938435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadUntil(interpreter))); 1939435933ddSDimitry Andric LoadSubCommand("info", 1940435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadInfo(interpreter))); 19414bb0738eSEd Maste LoadSubCommand("step-in", 19424bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 19434bb0738eSEd Maste interpreter, "thread step-in", 1944435933ddSDimitry Andric "Source level single step, stepping into calls. Defaults " 1945435933ddSDimitry Andric "to current thread unless specified.", 19464bb0738eSEd Maste nullptr, eStepTypeInto, eStepScopeSource))); 1947ac7ddfbfSEd Maste 19484bb0738eSEd Maste LoadSubCommand("step-out", 19494bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 1950435933ddSDimitry Andric interpreter, "thread step-out", 1951435933ddSDimitry Andric "Finish executing the current stack frame and stop after " 19524bb0738eSEd Maste "returning. Defaults to current thread unless specified.", 19534bb0738eSEd Maste nullptr, eStepTypeOut, eStepScopeSource))); 1954ac7ddfbfSEd Maste 19554bb0738eSEd Maste LoadSubCommand("step-over", 19564bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 19574bb0738eSEd Maste interpreter, "thread step-over", 1958435933ddSDimitry Andric "Source level single step, stepping over calls. Defaults " 1959435933ddSDimitry Andric "to current thread unless specified.", 19604bb0738eSEd Maste nullptr, eStepTypeOver, eStepScopeSource))); 1961ac7ddfbfSEd Maste 1962435933ddSDimitry Andric LoadSubCommand("step-inst", 19634bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 19644bb0738eSEd Maste interpreter, "thread step-inst", 1965435933ddSDimitry Andric "Instruction level single step, stepping into calls. " 1966435933ddSDimitry Andric "Defaults to current thread unless specified.", 19674bb0738eSEd Maste nullptr, eStepTypeTrace, eStepScopeInstruction))); 1968ac7ddfbfSEd Maste 1969435933ddSDimitry Andric LoadSubCommand("step-inst-over", 19704bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 19714bb0738eSEd Maste interpreter, "thread step-inst-over", 1972435933ddSDimitry Andric "Instruction level single step, stepping over calls. " 1973435933ddSDimitry Andric "Defaults to current thread unless specified.", 19744bb0738eSEd Maste nullptr, eStepTypeTraceOver, eStepScopeInstruction))); 19757aa51b79SEd Maste 1976435933ddSDimitry Andric LoadSubCommand( 1977435933ddSDimitry Andric "step-scripted", 1978435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 1979435933ddSDimitry Andric interpreter, "thread step-scripted", 19807aa51b79SEd Maste "Step as instructed by the script class passed in the -C option.", 1981435933ddSDimitry Andric nullptr, eStepTypeScripted, eStepScopeSource))); 19827aa51b79SEd Maste 1983435933ddSDimitry Andric LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan( 1984435933ddSDimitry Andric interpreter))); 1985ac7ddfbfSEd Maste } 1986ac7ddfbfSEd Maste 19874bb0738eSEd Maste CommandObjectMultiwordThread::~CommandObjectMultiwordThread() = default; 1988