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" 20f678e45dSDimitry Andric #include "lldb/Host/OptionParser.h" 211c3bbb01SEd Maste #include "lldb/Host/StringConvert.h" 22ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandInterpreter.h" 23ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandReturnObject.h" 24ac7ddfbfSEd Maste #include "lldb/Interpreter/Options.h" 25ac7ddfbfSEd Maste #include "lldb/Symbol/CompileUnit.h" 26ac7ddfbfSEd Maste #include "lldb/Symbol/Function.h" 27ac7ddfbfSEd Maste #include "lldb/Symbol/LineEntry.h" 28435933ddSDimitry Andric #include "lldb/Symbol/LineTable.h" 29ac7ddfbfSEd Maste #include "lldb/Target/Process.h" 30ac7ddfbfSEd Maste #include "lldb/Target/RegisterContext.h" 31b952cd58SEd Maste #include "lldb/Target/SystemRuntime.h" 32ac7ddfbfSEd Maste #include "lldb/Target/Target.h" 33ac7ddfbfSEd Maste #include "lldb/Target/Thread.h" 34ac7ddfbfSEd Maste #include "lldb/Target/ThreadPlan.h" 35435933ddSDimitry Andric #include "lldb/Target/ThreadPlanStepInRange.h" 36ac7ddfbfSEd Maste #include "lldb/Target/ThreadPlanStepInstruction.h" 37ac7ddfbfSEd Maste #include "lldb/Target/ThreadPlanStepOut.h" 38ac7ddfbfSEd Maste #include "lldb/Target/ThreadPlanStepRange.h" 39435933ddSDimitry Andric #include "lldb/lldb-private.h" 40ac7ddfbfSEd Maste 41ac7ddfbfSEd Maste using namespace lldb; 42ac7ddfbfSEd Maste using namespace lldb_private; 43ac7ddfbfSEd Maste 44ac7ddfbfSEd Maste //------------------------------------------------------------------------- 45ac7ddfbfSEd Maste // CommandObjectThreadBacktrace 46ac7ddfbfSEd Maste //------------------------------------------------------------------------- 47ac7ddfbfSEd Maste 48435933ddSDimitry Andric class CommandObjectIterateOverThreads : public CommandObjectParsed { 497aa51b79SEd Maste public: 507aa51b79SEd Maste CommandObjectIterateOverThreads(CommandInterpreter &interpreter, 51435933ddSDimitry Andric const char *name, const char *help, 52435933ddSDimitry Andric const char *syntax, uint32_t flags) 53435933ddSDimitry Andric : CommandObjectParsed(interpreter, name, help, syntax, flags) {} 547aa51b79SEd Maste 554bb0738eSEd Maste ~CommandObjectIterateOverThreads() override = default; 569f2f44ceSEd Maste 57435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 587aa51b79SEd Maste result.SetStatus(m_success_return); 597aa51b79SEd Maste 60435933ddSDimitry Andric if (command.GetArgumentCount() == 0) { 617aa51b79SEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 624bb0738eSEd Maste if (!HandleOneThread(thread->GetID(), result)) 637aa51b79SEd Maste return false; 644bb0738eSEd Maste return result.Succeeded(); 657aa51b79SEd Maste } 664bb0738eSEd Maste 67435933ddSDimitry Andric // Use tids instead of ThreadSPs to prevent deadlocking problems which 68435933ddSDimitry Andric // result from JIT-ing 694bb0738eSEd Maste // code while iterating over the (locked) ThreadSP list. 704bb0738eSEd Maste std::vector<lldb::tid_t> tids; 714bb0738eSEd Maste 72435933ddSDimitry Andric if (command.GetArgumentCount() == 1 && 73435933ddSDimitry Andric ::strcmp(command.GetArgumentAtIndex(0), "all") == 0) { 747aa51b79SEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 757aa51b79SEd Maste 764bb0738eSEd Maste for (ThreadSP thread_sp : process->Threads()) 774bb0738eSEd Maste tids.push_back(thread_sp->GetID()); 78435933ddSDimitry Andric } else { 797aa51b79SEd Maste const size_t num_args = command.GetArgumentCount(); 807aa51b79SEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 814bb0738eSEd Maste 82435933ddSDimitry Andric std::lock_guard<std::recursive_mutex> guard( 83435933ddSDimitry Andric process->GetThreadList().GetMutex()); 847aa51b79SEd Maste 85435933ddSDimitry Andric for (size_t i = 0; i < num_args; i++) { 867aa51b79SEd Maste bool success; 877aa51b79SEd Maste 88435933ddSDimitry Andric uint32_t thread_idx = StringConvert::ToUInt32( 89435933ddSDimitry Andric command.GetArgumentAtIndex(i), 0, 0, &success); 90435933ddSDimitry Andric if (!success) { 91435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", 92435933ddSDimitry Andric command.GetArgumentAtIndex(i)); 937aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 947aa51b79SEd Maste return false; 957aa51b79SEd Maste } 967aa51b79SEd Maste 97435933ddSDimitry Andric ThreadSP thread = 98435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(thread_idx); 997aa51b79SEd Maste 100435933ddSDimitry Andric if (!thread) { 101435933ddSDimitry Andric result.AppendErrorWithFormat("no thread with index: \"%s\"\n", 102435933ddSDimitry Andric command.GetArgumentAtIndex(i)); 1037aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 1047aa51b79SEd Maste return false; 1057aa51b79SEd Maste } 1067aa51b79SEd Maste 1074bb0738eSEd Maste tids.push_back(thread->GetID()); 1084bb0738eSEd Maste } 1097aa51b79SEd Maste } 1107aa51b79SEd Maste 1114bb0738eSEd Maste uint32_t idx = 0; 112435933ddSDimitry Andric for (const lldb::tid_t &tid : tids) { 1134bb0738eSEd Maste if (idx != 0 && m_add_return) 1144bb0738eSEd Maste result.AppendMessage(""); 1154bb0738eSEd Maste 1164bb0738eSEd Maste if (!HandleOneThread(tid, result)) 1177aa51b79SEd Maste return false; 1187aa51b79SEd Maste 1194bb0738eSEd Maste ++idx; 1207aa51b79SEd Maste } 1217aa51b79SEd Maste return result.Succeeded(); 1227aa51b79SEd Maste } 1237aa51b79SEd Maste 1247aa51b79SEd Maste protected: 1257aa51b79SEd Maste // Override this to do whatever you need to do for one thread. 1267aa51b79SEd Maste // 1277aa51b79SEd Maste // If you return false, the iteration will stop, otherwise it will proceed. 128435933ddSDimitry Andric // The result is set to m_success_return (defaults to 129435933ddSDimitry Andric // eReturnStatusSuccessFinishResult) before the iteration, 130435933ddSDimitry Andric // so you only need to set the return status in HandleOneThread if you want to 131435933ddSDimitry Andric // indicate an error. 132435933ddSDimitry Andric // If m_add_return is true, a blank line will be inserted between each of the 133435933ddSDimitry Andric // listings (except the last one.) 1347aa51b79SEd Maste 135435933ddSDimitry Andric virtual bool HandleOneThread(lldb::tid_t, CommandReturnObject &result) = 0; 1367aa51b79SEd Maste 1377aa51b79SEd Maste ReturnStatus m_success_return = eReturnStatusSuccessFinishResult; 1387aa51b79SEd Maste bool m_add_return = true; 1397aa51b79SEd Maste }; 1407aa51b79SEd Maste 1417aa51b79SEd Maste //------------------------------------------------------------------------- 1427aa51b79SEd Maste // CommandObjectThreadBacktrace 1437aa51b79SEd Maste //------------------------------------------------------------------------- 1447aa51b79SEd Maste 145435933ddSDimitry Andric static OptionDefinition g_thread_backtrace_options[] = { 146435933ddSDimitry Andric // clang-format off 147435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "How many frames to display (-1 for all)" }, 148435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "start", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFrameIndex, "Frame in which to start the backtrace" }, 149435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "extended", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Show the extended backtrace, if available" } 150435933ddSDimitry Andric // clang-format on 151435933ddSDimitry Andric }; 152435933ddSDimitry Andric 153435933ddSDimitry Andric class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads { 154ac7ddfbfSEd Maste public: 155435933ddSDimitry Andric class CommandOptions : public Options { 156ac7ddfbfSEd Maste public: 157435933ddSDimitry Andric CommandOptions() : Options() { 158435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 159435933ddSDimitry Andric // () 160435933ddSDimitry Andric OptionParsingStarting(nullptr); 161ac7ddfbfSEd Maste } 162ac7ddfbfSEd Maste 1634bb0738eSEd Maste ~CommandOptions() override = default; 164ac7ddfbfSEd Maste 1655517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 166435933ddSDimitry Andric ExecutionContext *execution_context) override { 1675517e702SDimitry Andric Status error; 168ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 169ac7ddfbfSEd Maste 170435933ddSDimitry Andric switch (short_option) { 171435933ddSDimitry Andric case 'c': { 172435933ddSDimitry Andric int32_t input_count = 0; 173435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_count)) { 174ac7ddfbfSEd Maste m_count = UINT32_MAX; 175435933ddSDimitry Andric error.SetErrorStringWithFormat( 176435933ddSDimitry Andric "invalid integer value for option '%c'", short_option); 177435933ddSDimitry Andric } else if (input_count < 0) 178435933ddSDimitry Andric m_count = UINT32_MAX; 179435933ddSDimitry Andric } break; 180ac7ddfbfSEd Maste case 's': 181435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_start)) 182435933ddSDimitry Andric error.SetErrorStringWithFormat( 183435933ddSDimitry Andric "invalid integer value for option '%c'", short_option); 1844bb0738eSEd Maste break; 185435933ddSDimitry Andric case 'e': { 186b952cd58SEd Maste bool success; 187435933ddSDimitry Andric m_extended_backtrace = 188435933ddSDimitry Andric Args::StringToBoolean(option_arg, false, &success); 189b952cd58SEd Maste if (!success) 190435933ddSDimitry Andric error.SetErrorStringWithFormat( 191435933ddSDimitry Andric "invalid boolean value for option '%c'", short_option); 192435933ddSDimitry Andric } break; 193ac7ddfbfSEd Maste default: 194435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 195435933ddSDimitry Andric short_option); 196ac7ddfbfSEd Maste break; 197ac7ddfbfSEd Maste } 198ac7ddfbfSEd Maste return error; 199ac7ddfbfSEd Maste } 200ac7ddfbfSEd Maste 201435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 202ac7ddfbfSEd Maste m_count = UINT32_MAX; 203ac7ddfbfSEd Maste m_start = 0; 204b952cd58SEd Maste m_extended_backtrace = false; 205ac7ddfbfSEd Maste } 206ac7ddfbfSEd Maste 207435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 208435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_backtrace_options); 209ac7ddfbfSEd Maste } 210ac7ddfbfSEd Maste 211ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 212ac7ddfbfSEd Maste uint32_t m_count; 213ac7ddfbfSEd Maste uint32_t m_start; 214b952cd58SEd Maste bool m_extended_backtrace; 215ac7ddfbfSEd Maste }; 216ac7ddfbfSEd Maste 2174bb0738eSEd Maste CommandObjectThreadBacktrace(CommandInterpreter &interpreter) 2184bb0738eSEd Maste : CommandObjectIterateOverThreads( 219435933ddSDimitry Andric interpreter, "thread backtrace", 220435933ddSDimitry Andric "Show thread call stacks. Defaults to the current thread, thread " 221435933ddSDimitry Andric "indexes can be specified as arguments. Use the thread-index " 222435933ddSDimitry Andric "\"all\" " 2234bb0738eSEd Maste "to see all threads.", 224435933ddSDimitry Andric nullptr, 225435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 226435933ddSDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 227435933ddSDimitry Andric eCommandProcessMustBePaused), 228435933ddSDimitry Andric m_options() {} 229ac7ddfbfSEd Maste 2304bb0738eSEd Maste ~CommandObjectThreadBacktrace() override = default; 231ac7ddfbfSEd Maste 232435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 233ac7ddfbfSEd Maste 234ac7ddfbfSEd Maste protected: 235435933ddSDimitry Andric void DoExtendedBacktrace(Thread *thread, CommandReturnObject &result) { 236b952cd58SEd Maste SystemRuntime *runtime = thread->GetProcess()->GetSystemRuntime(); 237435933ddSDimitry Andric if (runtime) { 238b952cd58SEd Maste Stream &strm = result.GetOutputStream(); 239435933ddSDimitry Andric const std::vector<ConstString> &types = 240435933ddSDimitry Andric runtime->GetExtendedBacktraceTypes(); 241435933ddSDimitry Andric for (auto type : types) { 242435933ddSDimitry Andric ThreadSP ext_thread_sp = runtime->GetExtendedBacktraceThread( 243435933ddSDimitry Andric thread->shared_from_this(), type); 244435933ddSDimitry Andric if (ext_thread_sp && ext_thread_sp->IsValid()) { 245b952cd58SEd Maste const uint32_t num_frames_with_source = 0; 246435933ddSDimitry Andric const bool stop_format = false; 247435933ddSDimitry Andric if (ext_thread_sp->GetStatus(strm, m_options.m_start, 248b952cd58SEd Maste m_options.m_count, 249435933ddSDimitry Andric num_frames_with_source, 250435933ddSDimitry Andric stop_format)) { 251b952cd58SEd Maste DoExtendedBacktrace(ext_thread_sp.get(), result); 252b952cd58SEd Maste } 253b952cd58SEd Maste } 254b952cd58SEd Maste } 255b952cd58SEd Maste } 256b952cd58SEd Maste } 257b952cd58SEd Maste 258435933ddSDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 259435933ddSDimitry Andric ThreadSP thread_sp = 260435933ddSDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 261435933ddSDimitry Andric if (!thread_sp) { 262435933ddSDimitry Andric result.AppendErrorWithFormat( 263435933ddSDimitry Andric "thread disappeared while computing backtraces: 0x%" PRIx64 "\n", 264435933ddSDimitry Andric tid); 2654bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 2664bb0738eSEd Maste return false; 2674bb0738eSEd Maste } 2684bb0738eSEd Maste 2694bb0738eSEd Maste Thread *thread = thread_sp.get(); 2704bb0738eSEd Maste 271ac7ddfbfSEd Maste Stream &strm = result.GetOutputStream(); 272ac7ddfbfSEd Maste 273ac7ddfbfSEd Maste // Don't show source context when doing backtraces. 274ac7ddfbfSEd Maste const uint32_t num_frames_with_source = 0; 275435933ddSDimitry Andric const bool stop_format = true; 276435933ddSDimitry Andric if (!thread->GetStatus(strm, m_options.m_start, m_options.m_count, 277435933ddSDimitry Andric num_frames_with_source, stop_format)) { 278435933ddSDimitry Andric result.AppendErrorWithFormat( 279435933ddSDimitry Andric "error displaying backtrace for thread: \"0x%4.4x\"\n", 280435933ddSDimitry Andric thread->GetIndexID()); 281ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 282ac7ddfbfSEd Maste return false; 283ac7ddfbfSEd Maste } 284435933ddSDimitry Andric if (m_options.m_extended_backtrace) { 2854bb0738eSEd Maste DoExtendedBacktrace(thread, result); 286b952cd58SEd Maste } 287ac7ddfbfSEd Maste 2887aa51b79SEd Maste return true; 289ac7ddfbfSEd Maste } 290ac7ddfbfSEd Maste 291ac7ddfbfSEd Maste CommandOptions m_options; 292ac7ddfbfSEd Maste }; 293ac7ddfbfSEd Maste 294435933ddSDimitry Andric enum StepScope { eStepScopeSource, eStepScopeInstruction }; 295435933ddSDimitry Andric 296435933ddSDimitry Andric static OptionEnumValueElement g_tri_running_mode[] = { 297435933ddSDimitry Andric {eOnlyThisThread, "this-thread", "Run only this thread"}, 298435933ddSDimitry Andric {eAllThreads, "all-threads", "Run all threads"}, 299435933ddSDimitry Andric {eOnlyDuringStepping, "while-stepping", 300435933ddSDimitry Andric "Run only this thread while stepping"}, 301435933ddSDimitry Andric {0, nullptr, nullptr}}; 302435933ddSDimitry Andric 303435933ddSDimitry Andric static OptionEnumValueElement g_duo_running_mode[] = { 304435933ddSDimitry Andric {eOnlyThisThread, "this-thread", "Run only this thread"}, 305435933ddSDimitry Andric {eAllThreads, "all-threads", "Run all threads"}, 306435933ddSDimitry Andric {0, nullptr, nullptr}}; 307435933ddSDimitry Andric 308435933ddSDimitry Andric static OptionDefinition g_thread_step_scope_options[] = { 309435933ddSDimitry Andric // clang-format off 310435933ddSDimitry 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." }, 311435933ddSDimitry 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." }, 312435933ddSDimitry 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." }, 313435933ddSDimitry 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." }, 314435933ddSDimitry 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." }, 315435933ddSDimitry 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." }, 316435933ddSDimitry 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." }, 317435933ddSDimitry 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." } 318435933ddSDimitry Andric // clang-format on 319ac7ddfbfSEd Maste }; 320ac7ddfbfSEd Maste 321435933ddSDimitry Andric class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed { 322ac7ddfbfSEd Maste public: 323435933ddSDimitry Andric class CommandOptions : public Options { 324ac7ddfbfSEd Maste public: 325435933ddSDimitry Andric CommandOptions() : Options() { 326435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 327435933ddSDimitry Andric // () 328435933ddSDimitry Andric OptionParsingStarting(nullptr); 329ac7ddfbfSEd Maste } 330ac7ddfbfSEd Maste 3314bb0738eSEd Maste ~CommandOptions() override = default; 332ac7ddfbfSEd Maste 3335517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 334435933ddSDimitry Andric ExecutionContext *execution_context) override { 3355517e702SDimitry Andric Status error; 336ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 337ac7ddfbfSEd Maste 338435933ddSDimitry Andric switch (short_option) { 339435933ddSDimitry Andric case 'a': { 340ac7ddfbfSEd Maste bool success; 3410127ef0fSEd Maste bool avoid_no_debug = Args::StringToBoolean(option_arg, true, &success); 342ac7ddfbfSEd Maste if (!success) 343435933ddSDimitry Andric error.SetErrorStringWithFormat( 344435933ddSDimitry Andric "invalid boolean value for option '%c'", short_option); 345435933ddSDimitry Andric else { 346435933ddSDimitry Andric m_step_in_avoid_no_debug = 347435933ddSDimitry Andric avoid_no_debug ? eLazyBoolYes : eLazyBoolNo; 3480127ef0fSEd Maste } 349435933ddSDimitry Andric } break; 350ac7ddfbfSEd Maste 351435933ddSDimitry Andric case 'A': { 3520127ef0fSEd Maste bool success; 3530127ef0fSEd Maste bool avoid_no_debug = Args::StringToBoolean(option_arg, true, &success); 3540127ef0fSEd Maste if (!success) 355435933ddSDimitry Andric error.SetErrorStringWithFormat( 356435933ddSDimitry Andric "invalid boolean value for option '%c'", short_option); 357435933ddSDimitry Andric else { 358435933ddSDimitry Andric m_step_out_avoid_no_debug = 359435933ddSDimitry Andric avoid_no_debug ? eLazyBoolYes : eLazyBoolNo; 3600127ef0fSEd Maste } 361435933ddSDimitry Andric } break; 3620127ef0fSEd Maste 3630127ef0fSEd Maste case 'c': 364435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_step_count)) 365435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid step count '%s'", 366435933ddSDimitry Andric option_arg.str().c_str()); 3670127ef0fSEd Maste break; 3684bb0738eSEd Maste 3697aa51b79SEd Maste case 'C': 3707aa51b79SEd Maste m_class_name.clear(); 3717aa51b79SEd Maste m_class_name.assign(option_arg); 3727aa51b79SEd Maste break; 3734bb0738eSEd Maste 374435933ddSDimitry Andric case 'm': { 375435933ddSDimitry Andric OptionEnumValueElement *enum_values = 376435933ddSDimitry Andric GetDefinitions()[option_idx].enum_values; 377435933ddSDimitry Andric m_run_mode = (lldb::RunMode)Args::StringToOptionEnum( 378435933ddSDimitry Andric option_arg, enum_values, eOnlyDuringStepping, error); 379435933ddSDimitry Andric } break; 380ac7ddfbfSEd Maste 3814bb0738eSEd Maste case 'e': 382435933ddSDimitry Andric if (option_arg == "block") { 3834bb0738eSEd Maste m_end_line_is_block_end = 1; 3844bb0738eSEd Maste break; 3854bb0738eSEd Maste } 386435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_end_line)) 387435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid end line number '%s'", 388435933ddSDimitry Andric option_arg.str().c_str()); 3894bb0738eSEd Maste break; 3904bb0738eSEd Maste 3914bb0738eSEd Maste case 'r': 392ac7ddfbfSEd Maste m_avoid_regexp.clear(); 393ac7ddfbfSEd Maste m_avoid_regexp.assign(option_arg); 394ac7ddfbfSEd Maste break; 395ac7ddfbfSEd Maste 396ac7ddfbfSEd Maste case 't': 397ac7ddfbfSEd Maste m_step_in_target.clear(); 398ac7ddfbfSEd Maste m_step_in_target.assign(option_arg); 399ac7ddfbfSEd Maste break; 4004bb0738eSEd Maste 401ac7ddfbfSEd Maste default: 402435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 403435933ddSDimitry Andric short_option); 404ac7ddfbfSEd Maste break; 405ac7ddfbfSEd Maste } 406ac7ddfbfSEd Maste return error; 407ac7ddfbfSEd Maste } 408ac7ddfbfSEd Maste 409435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 4100127ef0fSEd Maste m_step_in_avoid_no_debug = eLazyBoolCalculate; 4110127ef0fSEd Maste m_step_out_avoid_no_debug = eLazyBoolCalculate; 412ac7ddfbfSEd Maste m_run_mode = eOnlyDuringStepping; 4131c3bbb01SEd Maste 4141c3bbb01SEd Maste // Check if we are in Non-Stop mode 415435933ddSDimitry Andric TargetSP target_sp = 416435933ddSDimitry Andric execution_context ? execution_context->GetTargetSP() : TargetSP(); 4174bb0738eSEd Maste if (target_sp && target_sp->GetNonStopModeEnabled()) 4181c3bbb01SEd Maste m_run_mode = eOnlyThisThread; 4191c3bbb01SEd Maste 420ac7ddfbfSEd Maste m_avoid_regexp.clear(); 421ac7ddfbfSEd Maste m_step_in_target.clear(); 4227aa51b79SEd Maste m_class_name.clear(); 4230127ef0fSEd Maste m_step_count = 1; 4244bb0738eSEd Maste m_end_line = LLDB_INVALID_LINE_NUMBER; 4254bb0738eSEd Maste m_end_line_is_block_end = false; 426ac7ddfbfSEd Maste } 427ac7ddfbfSEd Maste 428435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 429435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_step_scope_options); 430ac7ddfbfSEd Maste } 431ac7ddfbfSEd Maste 432ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 4330127ef0fSEd Maste LazyBool m_step_in_avoid_no_debug; 4340127ef0fSEd Maste LazyBool m_step_out_avoid_no_debug; 435ac7ddfbfSEd Maste RunMode m_run_mode; 436ac7ddfbfSEd Maste std::string m_avoid_regexp; 437ac7ddfbfSEd Maste std::string m_step_in_target; 4387aa51b79SEd Maste std::string m_class_name; 4397aa51b79SEd Maste uint32_t m_step_count; 4404bb0738eSEd Maste uint32_t m_end_line; 4414bb0738eSEd Maste bool m_end_line_is_block_end; 442ac7ddfbfSEd Maste }; 443ac7ddfbfSEd Maste 444ac7ddfbfSEd Maste CommandObjectThreadStepWithTypeAndScope(CommandInterpreter &interpreter, 445435933ddSDimitry Andric const char *name, const char *help, 446ac7ddfbfSEd Maste const char *syntax, 447ac7ddfbfSEd Maste StepType step_type, 448435933ddSDimitry Andric StepScope step_scope) 449435933ddSDimitry Andric : CommandObjectParsed(interpreter, name, help, syntax, 450435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 4511c3bbb01SEd Maste eCommandTryTargetAPILock | 4521c3bbb01SEd Maste eCommandProcessMustBeLaunched | 4531c3bbb01SEd Maste eCommandProcessMustBePaused), 454435933ddSDimitry Andric m_step_type(step_type), m_step_scope(step_scope), m_options() { 455ac7ddfbfSEd Maste CommandArgumentEntry arg; 456ac7ddfbfSEd Maste CommandArgumentData thread_id_arg; 457ac7ddfbfSEd Maste 458ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 459ac7ddfbfSEd Maste thread_id_arg.arg_type = eArgTypeThreadID; 460ac7ddfbfSEd Maste thread_id_arg.arg_repetition = eArgRepeatOptional; 461ac7ddfbfSEd Maste 462435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 463435933ddSDimitry Andric // argument entry. 464ac7ddfbfSEd Maste arg.push_back(thread_id_arg); 465ac7ddfbfSEd Maste 466ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 467ac7ddfbfSEd Maste m_arguments.push_back(arg); 468ac7ddfbfSEd Maste } 469ac7ddfbfSEd Maste 4704bb0738eSEd Maste ~CommandObjectThreadStepWithTypeAndScope() override = default; 471ac7ddfbfSEd Maste 472435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 473ac7ddfbfSEd Maste 474ac7ddfbfSEd Maste protected: 475435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 476ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 477ac7ddfbfSEd Maste bool synchronous_execution = m_interpreter.GetSynchronous(); 478ac7ddfbfSEd Maste 479ac7ddfbfSEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 4804bb0738eSEd Maste Thread *thread = nullptr; 481ac7ddfbfSEd Maste 482435933ddSDimitry Andric if (command.GetArgumentCount() == 0) { 4834bb0738eSEd Maste thread = GetDefaultThread(); 4844bb0738eSEd Maste 485435933ddSDimitry Andric if (thread == nullptr) { 486ac7ddfbfSEd Maste result.AppendError("no selected thread in process"); 487ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 488ac7ddfbfSEd Maste return false; 489ac7ddfbfSEd Maste } 490435933ddSDimitry Andric } else { 491ac7ddfbfSEd Maste const char *thread_idx_cstr = command.GetArgumentAtIndex(0); 492435933ddSDimitry Andric uint32_t step_thread_idx = 493435933ddSDimitry Andric StringConvert::ToUInt32(thread_idx_cstr, LLDB_INVALID_INDEX32); 494435933ddSDimitry Andric if (step_thread_idx == LLDB_INVALID_INDEX32) { 495435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread index '%s'.\n", 496435933ddSDimitry Andric thread_idx_cstr); 497ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 498ac7ddfbfSEd Maste return false; 499ac7ddfbfSEd Maste } 500435933ddSDimitry Andric thread = 501435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(step_thread_idx).get(); 502435933ddSDimitry Andric if (thread == nullptr) { 503435933ddSDimitry Andric result.AppendErrorWithFormat( 504435933ddSDimitry Andric "Thread index %u is out of range (valid values are 0 - %u).\n", 505ac7ddfbfSEd Maste step_thread_idx, num_threads); 506ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 507ac7ddfbfSEd Maste return false; 508ac7ddfbfSEd Maste } 509ac7ddfbfSEd Maste } 510ac7ddfbfSEd Maste 511435933ddSDimitry Andric if (m_step_type == eStepTypeScripted) { 512435933ddSDimitry Andric if (m_options.m_class_name.empty()) { 5137aa51b79SEd Maste result.AppendErrorWithFormat("empty class name for scripted step."); 5147aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 5157aa51b79SEd Maste return false; 516435933ddSDimitry Andric } else if (!m_interpreter.GetScriptInterpreter()->CheckObjectExists( 517435933ddSDimitry Andric m_options.m_class_name.c_str())) { 518435933ddSDimitry Andric result.AppendErrorWithFormat( 519435933ddSDimitry Andric "class for scripted step: \"%s\" does not exist.", 520435933ddSDimitry Andric m_options.m_class_name.c_str()); 5217aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 5227aa51b79SEd Maste return false; 5237aa51b79SEd Maste } 5247aa51b79SEd Maste } 5257aa51b79SEd Maste 526435933ddSDimitry Andric if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER && 527435933ddSDimitry Andric m_step_type != eStepTypeInto) { 528435933ddSDimitry Andric result.AppendErrorWithFormat( 529435933ddSDimitry Andric "end line option is only valid for step into"); 5304bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 5314bb0738eSEd Maste return false; 5324bb0738eSEd Maste } 5334bb0738eSEd Maste 534ac7ddfbfSEd Maste const bool abort_other_plans = false; 535ac7ddfbfSEd Maste const lldb::RunMode stop_other_threads = m_options.m_run_mode; 536ac7ddfbfSEd Maste 537435933ddSDimitry Andric // This is a bit unfortunate, but not all the commands in this command 538435933ddSDimitry Andric // object support 539ac7ddfbfSEd Maste // only while stepping, so I use the bool for them. 540ac7ddfbfSEd Maste bool bool_stop_other_threads; 541ac7ddfbfSEd Maste if (m_options.m_run_mode == eAllThreads) 542ac7ddfbfSEd Maste bool_stop_other_threads = false; 543ac7ddfbfSEd Maste else if (m_options.m_run_mode == eOnlyDuringStepping) 544435933ddSDimitry Andric bool_stop_other_threads = 545435933ddSDimitry Andric (m_step_type != eStepTypeOut && m_step_type != eStepTypeScripted); 546ac7ddfbfSEd Maste else 547ac7ddfbfSEd Maste bool_stop_other_threads = true; 548ac7ddfbfSEd Maste 549ac7ddfbfSEd Maste ThreadPlanSP new_plan_sp; 550ac7ddfbfSEd Maste 551435933ddSDimitry Andric if (m_step_type == eStepTypeInto) { 552ac7ddfbfSEd Maste StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); 5531c3bbb01SEd Maste assert(frame != nullptr); 554ac7ddfbfSEd Maste 555435933ddSDimitry Andric if (frame->HasDebugInformation()) { 5564bb0738eSEd Maste AddressRange range; 5574bb0738eSEd Maste SymbolContext sc = frame->GetSymbolContext(eSymbolContextEverything); 558435933ddSDimitry Andric if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER) { 5595517e702SDimitry Andric Status error; 560435933ddSDimitry Andric if (!sc.GetAddressRangeFromHereToEndLine(m_options.m_end_line, range, 561435933ddSDimitry Andric error)) { 562435933ddSDimitry Andric result.AppendErrorWithFormat("invalid end-line option: %s.", 563435933ddSDimitry Andric error.AsCString()); 5644bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 5654bb0738eSEd Maste return false; 5664bb0738eSEd Maste } 567435933ddSDimitry Andric } else if (m_options.m_end_line_is_block_end) { 5685517e702SDimitry Andric Status error; 5694bb0738eSEd Maste Block *block = frame->GetSymbolContext(eSymbolContextBlock).block; 570435933ddSDimitry Andric if (!block) { 5714bb0738eSEd Maste result.AppendErrorWithFormat("Could not find the current block."); 5724bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 5734bb0738eSEd Maste return false; 5744bb0738eSEd Maste } 5754bb0738eSEd Maste 5764bb0738eSEd Maste AddressRange block_range; 5774bb0738eSEd Maste Address pc_address = frame->GetFrameCodeAddress(); 5784bb0738eSEd Maste block->GetRangeContainingAddress(pc_address, block_range); 579435933ddSDimitry Andric if (!block_range.GetBaseAddress().IsValid()) { 580435933ddSDimitry Andric result.AppendErrorWithFormat( 581435933ddSDimitry Andric "Could not find the current block address."); 5824bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 5834bb0738eSEd Maste return false; 5844bb0738eSEd Maste } 585435933ddSDimitry Andric lldb::addr_t pc_offset_in_block = 586435933ddSDimitry Andric pc_address.GetFileAddress() - 587435933ddSDimitry Andric block_range.GetBaseAddress().GetFileAddress(); 588435933ddSDimitry Andric lldb::addr_t range_length = 589435933ddSDimitry Andric block_range.GetByteSize() - pc_offset_in_block; 5904bb0738eSEd Maste range = AddressRange(pc_address, range_length); 591435933ddSDimitry Andric } else { 5924bb0738eSEd Maste range = sc.line_entry.range; 5934bb0738eSEd Maste } 5944bb0738eSEd Maste 595435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepInRange( 596435933ddSDimitry Andric abort_other_plans, range, 597ac7ddfbfSEd Maste frame->GetSymbolContext(eSymbolContextEverything), 598435933ddSDimitry Andric m_options.m_step_in_target.c_str(), stop_other_threads, 5990127ef0fSEd Maste m_options.m_step_in_avoid_no_debug, 6000127ef0fSEd Maste m_options.m_step_out_avoid_no_debug); 6010127ef0fSEd Maste 602435933ddSDimitry Andric if (new_plan_sp && !m_options.m_avoid_regexp.empty()) { 603435933ddSDimitry Andric ThreadPlanStepInRange *step_in_range_plan = 604435933ddSDimitry Andric static_cast<ThreadPlanStepInRange *>(new_plan_sp.get()); 605ac7ddfbfSEd Maste step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str()); 606ac7ddfbfSEd Maste } 607435933ddSDimitry Andric } else 608435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 609435933ddSDimitry Andric false, abort_other_plans, bool_stop_other_threads); 610435933ddSDimitry Andric } else if (m_step_type == eStepTypeOver) { 611ac7ddfbfSEd Maste StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); 612ac7ddfbfSEd Maste 613ac7ddfbfSEd Maste if (frame->HasDebugInformation()) 614435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepOverRange( 615435933ddSDimitry Andric abort_other_plans, 6169f2f44ceSEd Maste frame->GetSymbolContext(eSymbolContextEverything).line_entry, 617ac7ddfbfSEd Maste frame->GetSymbolContext(eSymbolContextEverything), 618435933ddSDimitry Andric stop_other_threads, m_options.m_step_out_avoid_no_debug); 619ac7ddfbfSEd Maste else 620435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 621435933ddSDimitry Andric true, abort_other_plans, bool_stop_other_threads); 622435933ddSDimitry Andric } else if (m_step_type == eStepTypeTrace) { 623435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 624435933ddSDimitry Andric false, abort_other_plans, bool_stop_other_threads); 625435933ddSDimitry Andric } else if (m_step_type == eStepTypeTraceOver) { 626435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 627435933ddSDimitry Andric true, abort_other_plans, bool_stop_other_threads); 628435933ddSDimitry Andric } else if (m_step_type == eStepTypeOut) { 629435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepOut( 630435933ddSDimitry Andric abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes, 631435933ddSDimitry Andric eVoteNoOpinion, thread->GetSelectedFrameIndex(), 6320127ef0fSEd Maste m_options.m_step_out_avoid_no_debug); 633435933ddSDimitry Andric } else if (m_step_type == eStepTypeScripted) { 634435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepScripted( 635435933ddSDimitry Andric abort_other_plans, m_options.m_class_name.c_str(), 6367aa51b79SEd Maste bool_stop_other_threads); 637435933ddSDimitry Andric } else { 638ac7ddfbfSEd Maste result.AppendError("step type is not supported"); 639ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 640ac7ddfbfSEd Maste return false; 641ac7ddfbfSEd Maste } 642ac7ddfbfSEd Maste 643435933ddSDimitry Andric // If we got a new plan, then set it to be a master plan (User level Plans 644435933ddSDimitry Andric // should be master plans 645ac7ddfbfSEd Maste // so that they can be interruptible). Then resume the process. 646ac7ddfbfSEd Maste 647435933ddSDimitry Andric if (new_plan_sp) { 648ac7ddfbfSEd Maste new_plan_sp->SetIsMasterPlan(true); 649ac7ddfbfSEd Maste new_plan_sp->SetOkayToDiscard(false); 650ac7ddfbfSEd Maste 651435933ddSDimitry Andric if (m_options.m_step_count > 1) { 652302affcbSDimitry Andric if (!new_plan_sp->SetIterationCount(m_options.m_step_count)) { 653435933ddSDimitry Andric result.AppendWarning( 654435933ddSDimitry Andric "step operation does not support iteration count."); 6550127ef0fSEd Maste } 6560127ef0fSEd Maste } 6570127ef0fSEd Maste 658ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(thread->GetID()); 6597aa51b79SEd Maste 6601c3bbb01SEd Maste const uint32_t iohandler_id = process->GetIOHandlerID(); 6611c3bbb01SEd Maste 6627aa51b79SEd Maste StreamString stream; 6635517e702SDimitry Andric Status error; 6647aa51b79SEd Maste if (synchronous_execution) 6657aa51b79SEd Maste error = process->ResumeSynchronous(&stream); 6667aa51b79SEd Maste else 6677aa51b79SEd Maste error = process->Resume(); 668ac7ddfbfSEd Maste 669435933ddSDimitry Andric // There is a race condition where this thread will return up the call 670435933ddSDimitry Andric // stack to the main command handler 671435933ddSDimitry Andric // and show an (lldb) prompt before HandlePrivateEvent (from 672435933ddSDimitry Andric // PrivateStateThread) has 6730127ef0fSEd Maste // a chance to call PushProcessIOHandler(). 6741c3bbb01SEd Maste process->SyncIOHandler(iohandler_id, 2000); 675ac7ddfbfSEd Maste 676435933ddSDimitry Andric if (synchronous_execution) { 677435933ddSDimitry Andric // If any state changed events had anything to say, add that to the 678435933ddSDimitry Andric // result 679435933ddSDimitry Andric if (stream.GetSize() > 0) 680435933ddSDimitry Andric result.AppendMessage(stream.GetString()); 681ac7ddfbfSEd Maste 682ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(thread->GetID()); 683ac7ddfbfSEd Maste result.SetDidChangeProcessState(true); 684ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 685435933ddSDimitry Andric } else { 686ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessContinuingNoResult); 687ac7ddfbfSEd Maste } 688435933ddSDimitry Andric } else { 689ac7ddfbfSEd Maste result.AppendError("Couldn't find thread plan to implement step type."); 690ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 691ac7ddfbfSEd Maste } 692ac7ddfbfSEd Maste return result.Succeeded(); 693ac7ddfbfSEd Maste } 694ac7ddfbfSEd Maste 695ac7ddfbfSEd Maste protected: 696ac7ddfbfSEd Maste StepType m_step_type; 697ac7ddfbfSEd Maste StepScope m_step_scope; 698ac7ddfbfSEd Maste CommandOptions m_options; 699ac7ddfbfSEd Maste }; 700ac7ddfbfSEd Maste 701ac7ddfbfSEd Maste //------------------------------------------------------------------------- 702ac7ddfbfSEd Maste // CommandObjectThreadContinue 703ac7ddfbfSEd Maste //------------------------------------------------------------------------- 704ac7ddfbfSEd Maste 705435933ddSDimitry Andric class CommandObjectThreadContinue : public CommandObjectParsed { 706ac7ddfbfSEd Maste public: 7074bb0738eSEd Maste CommandObjectThreadContinue(CommandInterpreter &interpreter) 708435933ddSDimitry Andric : CommandObjectParsed( 709435933ddSDimitry Andric interpreter, "thread continue", 710435933ddSDimitry Andric "Continue execution of the current target process. One " 7114bb0738eSEd Maste "or more threads may be specified, by default all " 7124bb0738eSEd Maste "threads continue.", 713435933ddSDimitry Andric nullptr, 714435933ddSDimitry Andric eCommandRequiresThread | eCommandTryTargetAPILock | 715435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { 716ac7ddfbfSEd Maste CommandArgumentEntry arg; 717ac7ddfbfSEd Maste CommandArgumentData thread_idx_arg; 718ac7ddfbfSEd Maste 719ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 720ac7ddfbfSEd Maste thread_idx_arg.arg_type = eArgTypeThreadIndex; 721ac7ddfbfSEd Maste thread_idx_arg.arg_repetition = eArgRepeatPlus; 722ac7ddfbfSEd Maste 723435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 724435933ddSDimitry Andric // argument entry. 725ac7ddfbfSEd Maste arg.push_back(thread_idx_arg); 726ac7ddfbfSEd Maste 727ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 728ac7ddfbfSEd Maste m_arguments.push_back(arg); 729ac7ddfbfSEd Maste } 730ac7ddfbfSEd Maste 7314bb0738eSEd Maste ~CommandObjectThreadContinue() override = default; 732ac7ddfbfSEd Maste 733435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 734ac7ddfbfSEd Maste bool synchronous_execution = m_interpreter.GetSynchronous(); 735ac7ddfbfSEd Maste 736435933ddSDimitry Andric if (!m_interpreter.GetDebugger().GetSelectedTarget()) { 737435933ddSDimitry Andric result.AppendError("invalid target, create a debug target using the " 738435933ddSDimitry Andric "'target create' command"); 739ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 740ac7ddfbfSEd Maste return false; 741ac7ddfbfSEd Maste } 742ac7ddfbfSEd Maste 743ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 744435933ddSDimitry Andric if (process == nullptr) { 745ac7ddfbfSEd Maste result.AppendError("no process exists. Cannot continue"); 746ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 747ac7ddfbfSEd Maste return false; 748ac7ddfbfSEd Maste } 749ac7ddfbfSEd Maste 750ac7ddfbfSEd Maste StateType state = process->GetState(); 751435933ddSDimitry Andric if ((state == eStateCrashed) || (state == eStateStopped) || 752435933ddSDimitry Andric (state == eStateSuspended)) { 753ac7ddfbfSEd Maste const size_t argc = command.GetArgumentCount(); 754435933ddSDimitry Andric if (argc > 0) { 75535617911SEd Maste // These two lines appear at the beginning of both blocks in 75635617911SEd Maste // this if..else, but that is because we need to release the 75735617911SEd Maste // lock before calling process->Resume below. 758435933ddSDimitry Andric std::lock_guard<std::recursive_mutex> guard( 759435933ddSDimitry Andric process->GetThreadList().GetMutex()); 76035617911SEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 761ac7ddfbfSEd Maste std::vector<Thread *> resume_threads; 762435933ddSDimitry Andric for (auto &entry : command.entries()) { 763435933ddSDimitry Andric uint32_t thread_idx; 764435933ddSDimitry Andric if (entry.ref.getAsInteger(0, thread_idx)) { 765435933ddSDimitry Andric result.AppendErrorWithFormat( 766435933ddSDimitry Andric "invalid thread index argument: \"%s\".\n", entry.c_str()); 767435933ddSDimitry Andric result.SetStatus(eReturnStatusFailed); 768435933ddSDimitry Andric return false; 769435933ddSDimitry Andric } 770435933ddSDimitry Andric Thread *thread = 771435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(thread_idx).get(); 772ac7ddfbfSEd Maste 773435933ddSDimitry Andric if (thread) { 774ac7ddfbfSEd Maste resume_threads.push_back(thread); 775435933ddSDimitry Andric } else { 776435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread index %u.\n", 777435933ddSDimitry Andric thread_idx); 778ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 779ac7ddfbfSEd Maste return false; 780ac7ddfbfSEd Maste } 781ac7ddfbfSEd Maste } 782ac7ddfbfSEd Maste 783435933ddSDimitry Andric if (resume_threads.empty()) { 784ac7ddfbfSEd Maste result.AppendError("no valid thread indexes were specified"); 785ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 786ac7ddfbfSEd Maste return false; 787435933ddSDimitry Andric } else { 788ac7ddfbfSEd Maste if (resume_threads.size() == 1) 789ac7ddfbfSEd Maste result.AppendMessageWithFormat("Resuming thread: "); 790ac7ddfbfSEd Maste else 791ac7ddfbfSEd Maste result.AppendMessageWithFormat("Resuming threads: "); 792ac7ddfbfSEd Maste 793435933ddSDimitry Andric for (uint32_t idx = 0; idx < num_threads; ++idx) { 794435933ddSDimitry Andric Thread *thread = 795435933ddSDimitry Andric process->GetThreadList().GetThreadAtIndex(idx).get(); 796435933ddSDimitry Andric std::vector<Thread *>::iterator this_thread_pos = 797435933ddSDimitry Andric find(resume_threads.begin(), resume_threads.end(), thread); 798ac7ddfbfSEd Maste 799435933ddSDimitry Andric if (this_thread_pos != resume_threads.end()) { 800ac7ddfbfSEd Maste resume_threads.erase(this_thread_pos); 8014bb0738eSEd Maste if (!resume_threads.empty()) 802ac7ddfbfSEd Maste result.AppendMessageWithFormat("%u, ", thread->GetIndexID()); 803ac7ddfbfSEd Maste else 804ac7ddfbfSEd Maste result.AppendMessageWithFormat("%u ", thread->GetIndexID()); 805ac7ddfbfSEd Maste 8060127ef0fSEd Maste const bool override_suspend = true; 8070127ef0fSEd Maste thread->SetResumeState(eStateRunning, override_suspend); 808435933ddSDimitry Andric } else { 809ac7ddfbfSEd Maste thread->SetResumeState(eStateSuspended); 810ac7ddfbfSEd Maste } 811ac7ddfbfSEd Maste } 812435933ddSDimitry Andric result.AppendMessageWithFormat("in process %" PRIu64 "\n", 813435933ddSDimitry Andric process->GetID()); 814ac7ddfbfSEd Maste } 815435933ddSDimitry Andric } else { 81635617911SEd Maste // These two lines appear at the beginning of both blocks in 81735617911SEd Maste // this if..else, but that is because we need to release the 81835617911SEd Maste // lock before calling process->Resume below. 819435933ddSDimitry Andric std::lock_guard<std::recursive_mutex> guard( 820435933ddSDimitry Andric process->GetThreadList().GetMutex()); 82135617911SEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 8224bb0738eSEd Maste Thread *current_thread = GetDefaultThread(); 823435933ddSDimitry Andric if (current_thread == nullptr) { 824ac7ddfbfSEd Maste result.AppendError("the process doesn't have a current thread"); 825ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 826ac7ddfbfSEd Maste return false; 827ac7ddfbfSEd Maste } 828ac7ddfbfSEd Maste // Set the actions that the threads should each take when resuming 829435933ddSDimitry Andric for (uint32_t idx = 0; idx < num_threads; ++idx) { 830ac7ddfbfSEd Maste Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get(); 831435933ddSDimitry Andric if (thread == current_thread) { 832435933ddSDimitry Andric result.AppendMessageWithFormat("Resuming thread 0x%4.4" PRIx64 833435933ddSDimitry Andric " in process %" PRIu64 "\n", 834435933ddSDimitry Andric thread->GetID(), process->GetID()); 8350127ef0fSEd Maste const bool override_suspend = true; 8360127ef0fSEd Maste thread->SetResumeState(eStateRunning, override_suspend); 837435933ddSDimitry Andric } else { 838ac7ddfbfSEd Maste thread->SetResumeState(eStateSuspended); 839ac7ddfbfSEd Maste } 840ac7ddfbfSEd Maste } 841ac7ddfbfSEd Maste } 842ac7ddfbfSEd Maste 8437aa51b79SEd Maste StreamString stream; 8445517e702SDimitry Andric Status error; 8457aa51b79SEd Maste if (synchronous_execution) 8467aa51b79SEd Maste error = process->ResumeSynchronous(&stream); 8477aa51b79SEd Maste else 8487aa51b79SEd Maste error = process->Resume(); 8497aa51b79SEd Maste 85035617911SEd Maste // We should not be holding the thread list lock when we do this. 851435933ddSDimitry Andric if (error.Success()) { 852435933ddSDimitry Andric result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n", 853435933ddSDimitry Andric process->GetID()); 854435933ddSDimitry Andric if (synchronous_execution) { 855435933ddSDimitry Andric // If any state changed events had anything to say, add that to the 856435933ddSDimitry Andric // result 857435933ddSDimitry Andric if (stream.GetSize() > 0) 858435933ddSDimitry Andric result.AppendMessage(stream.GetString()); 859ac7ddfbfSEd Maste 860ac7ddfbfSEd Maste result.SetDidChangeProcessState(true); 861ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 862435933ddSDimitry Andric } else { 863ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessContinuingNoResult); 864ac7ddfbfSEd Maste } 865435933ddSDimitry Andric } else { 866435933ddSDimitry Andric result.AppendErrorWithFormat("Failed to resume process: %s\n", 867435933ddSDimitry Andric error.AsCString()); 868ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 869ac7ddfbfSEd Maste } 870435933ddSDimitry Andric } else { 871435933ddSDimitry Andric result.AppendErrorWithFormat( 872435933ddSDimitry Andric "Process cannot be continued from its current state (%s).\n", 873ac7ddfbfSEd Maste StateAsCString(state)); 874ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 875ac7ddfbfSEd Maste } 876ac7ddfbfSEd Maste 877ac7ddfbfSEd Maste return result.Succeeded(); 878ac7ddfbfSEd Maste } 879ac7ddfbfSEd Maste }; 880ac7ddfbfSEd Maste 881ac7ddfbfSEd Maste //------------------------------------------------------------------------- 882ac7ddfbfSEd Maste // CommandObjectThreadUntil 883ac7ddfbfSEd Maste //------------------------------------------------------------------------- 884ac7ddfbfSEd Maste 885435933ddSDimitry Andric static OptionDefinition g_thread_until_options[] = { 886435933ddSDimitry Andric // clang-format off 887435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "frame", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFrameIndex, "Frame index for until operation - defaults to 0" }, 888435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "thread", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadIndex, "Thread index for the thread for until operation" }, 889435933ddSDimitry 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" }, 890435933ddSDimitry 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." } 891435933ddSDimitry Andric // clang-format on 892435933ddSDimitry Andric }; 893435933ddSDimitry Andric 894435933ddSDimitry Andric class CommandObjectThreadUntil : public CommandObjectParsed { 895ac7ddfbfSEd Maste public: 896435933ddSDimitry Andric class CommandOptions : public Options { 897ac7ddfbfSEd Maste public: 898ac7ddfbfSEd Maste uint32_t m_thread_idx; 899ac7ddfbfSEd Maste uint32_t m_frame_idx; 900ac7ddfbfSEd Maste 901435933ddSDimitry Andric CommandOptions() 902435933ddSDimitry Andric : Options(), m_thread_idx(LLDB_INVALID_THREAD_ID), 903435933ddSDimitry Andric m_frame_idx(LLDB_INVALID_FRAME_ID) { 904435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 905435933ddSDimitry Andric // () 906435933ddSDimitry Andric OptionParsingStarting(nullptr); 907ac7ddfbfSEd Maste } 908ac7ddfbfSEd Maste 9094bb0738eSEd Maste ~CommandOptions() override = default; 910ac7ddfbfSEd Maste 9115517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 912435933ddSDimitry Andric ExecutionContext *execution_context) override { 9135517e702SDimitry Andric Status error; 914ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 915ac7ddfbfSEd Maste 916435933ddSDimitry Andric switch (short_option) { 917435933ddSDimitry Andric case 'a': { 918435933ddSDimitry Andric lldb::addr_t tmp_addr = Args::StringToAddress( 919435933ddSDimitry Andric execution_context, option_arg, LLDB_INVALID_ADDRESS, &error); 9201c3bbb01SEd Maste if (error.Success()) 9211c3bbb01SEd Maste m_until_addrs.push_back(tmp_addr); 922435933ddSDimitry Andric } break; 923ac7ddfbfSEd Maste case 't': 924435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_thread_idx)) { 925435933ddSDimitry Andric m_thread_idx = LLDB_INVALID_INDEX32; 926435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid thread index '%s'", 927435933ddSDimitry Andric option_arg.str().c_str()); 928ac7ddfbfSEd Maste } 929ac7ddfbfSEd Maste break; 930ac7ddfbfSEd Maste case 'f': 931435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_frame_idx)) { 932435933ddSDimitry Andric m_frame_idx = LLDB_INVALID_FRAME_ID; 933435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid frame index '%s'", 934435933ddSDimitry Andric option_arg.str().c_str()); 935ac7ddfbfSEd Maste } 936ac7ddfbfSEd Maste break; 937435933ddSDimitry Andric case 'm': { 938435933ddSDimitry Andric OptionEnumValueElement *enum_values = 939435933ddSDimitry Andric GetDefinitions()[option_idx].enum_values; 940435933ddSDimitry Andric lldb::RunMode run_mode = (lldb::RunMode)Args::StringToOptionEnum( 941435933ddSDimitry Andric option_arg, enum_values, eOnlyDuringStepping, error); 942ac7ddfbfSEd Maste 943435933ddSDimitry Andric if (error.Success()) { 944ac7ddfbfSEd Maste if (run_mode == eAllThreads) 945ac7ddfbfSEd Maste m_stop_others = false; 946ac7ddfbfSEd Maste else 947ac7ddfbfSEd Maste m_stop_others = true; 948ac7ddfbfSEd Maste } 949435933ddSDimitry Andric } break; 950ac7ddfbfSEd Maste default: 951435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 952435933ddSDimitry Andric short_option); 953ac7ddfbfSEd Maste break; 954ac7ddfbfSEd Maste } 955ac7ddfbfSEd Maste return error; 956ac7ddfbfSEd Maste } 957ac7ddfbfSEd Maste 958435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 959ac7ddfbfSEd Maste m_thread_idx = LLDB_INVALID_THREAD_ID; 960ac7ddfbfSEd Maste m_frame_idx = 0; 961ac7ddfbfSEd Maste m_stop_others = false; 9621c3bbb01SEd Maste m_until_addrs.clear(); 963ac7ddfbfSEd Maste } 964ac7ddfbfSEd Maste 965435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 966435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_until_options); 967ac7ddfbfSEd Maste } 968ac7ddfbfSEd Maste 969ac7ddfbfSEd Maste uint32_t m_step_thread_idx; 970ac7ddfbfSEd Maste bool m_stop_others; 9711c3bbb01SEd Maste std::vector<lldb::addr_t> m_until_addrs; 972ac7ddfbfSEd Maste 973ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 974ac7ddfbfSEd Maste }; 975ac7ddfbfSEd Maste 9764bb0738eSEd Maste CommandObjectThreadUntil(CommandInterpreter &interpreter) 977435933ddSDimitry Andric : CommandObjectParsed( 978435933ddSDimitry Andric interpreter, "thread until", 979435933ddSDimitry Andric "Continue until a line number or address is reached by the " 9804bb0738eSEd Maste "current or specified thread. Stops when returning from " 981435933ddSDimitry Andric "the current function as a safety measure. " 982435933ddSDimitry Andric "The target line number(s) are given as arguments, and if more than one" 983435933ddSDimitry Andric " is provided, stepping will stop when the first one is hit.", 984435933ddSDimitry Andric nullptr, 985435933ddSDimitry Andric eCommandRequiresThread | eCommandTryTargetAPILock | 9864bb0738eSEd Maste eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 987435933ddSDimitry Andric m_options() { 988ac7ddfbfSEd Maste CommandArgumentEntry arg; 989ac7ddfbfSEd Maste CommandArgumentData line_num_arg; 990ac7ddfbfSEd Maste 991ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 992ac7ddfbfSEd Maste line_num_arg.arg_type = eArgTypeLineNum; 993ac7ddfbfSEd Maste line_num_arg.arg_repetition = eArgRepeatPlain; 994ac7ddfbfSEd Maste 995435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 996435933ddSDimitry Andric // argument entry. 997ac7ddfbfSEd Maste arg.push_back(line_num_arg); 998ac7ddfbfSEd Maste 999ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 1000ac7ddfbfSEd Maste m_arguments.push_back(arg); 1001ac7ddfbfSEd Maste } 1002ac7ddfbfSEd Maste 10034bb0738eSEd Maste ~CommandObjectThreadUntil() override = default; 1004ac7ddfbfSEd Maste 1005435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 1006ac7ddfbfSEd Maste 1007ac7ddfbfSEd Maste protected: 1008435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 1009ac7ddfbfSEd Maste bool synchronous_execution = m_interpreter.GetSynchronous(); 1010ac7ddfbfSEd Maste 1011ac7ddfbfSEd Maste Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 1012435933ddSDimitry Andric if (target == nullptr) { 1013435933ddSDimitry Andric result.AppendError("invalid target, create a debug target using the " 1014435933ddSDimitry Andric "'target create' command"); 1015ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1016ac7ddfbfSEd Maste return false; 1017ac7ddfbfSEd Maste } 1018ac7ddfbfSEd Maste 1019ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 1020435933ddSDimitry Andric if (process == nullptr) { 1021ac7ddfbfSEd Maste result.AppendError("need a valid process to step"); 1022ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1023435933ddSDimitry Andric } else { 10244bb0738eSEd Maste Thread *thread = nullptr; 10251c3bbb01SEd Maste std::vector<uint32_t> line_numbers; 1026ac7ddfbfSEd Maste 1027435933ddSDimitry Andric if (command.GetArgumentCount() >= 1) { 10281c3bbb01SEd Maste size_t num_args = command.GetArgumentCount(); 1029435933ddSDimitry Andric for (size_t i = 0; i < num_args; i++) { 10301c3bbb01SEd Maste uint32_t line_number; 1031435933ddSDimitry Andric line_number = StringConvert::ToUInt32(command.GetArgumentAtIndex(i), 1032435933ddSDimitry Andric UINT32_MAX); 1033435933ddSDimitry Andric if (line_number == UINT32_MAX) { 1034435933ddSDimitry Andric result.AppendErrorWithFormat("invalid line number: '%s'.\n", 1035435933ddSDimitry Andric command.GetArgumentAtIndex(i)); 1036ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1037ac7ddfbfSEd Maste return false; 1038435933ddSDimitry Andric } else 10391c3bbb01SEd Maste line_numbers.push_back(line_number); 10401c3bbb01SEd Maste } 1041435933ddSDimitry Andric } else if (m_options.m_until_addrs.empty()) { 1042435933ddSDimitry Andric result.AppendErrorWithFormat("No line number or address provided:\n%s", 1043435933ddSDimitry Andric GetSyntax().str().c_str()); 10441c3bbb01SEd Maste result.SetStatus(eReturnStatusFailed); 10451c3bbb01SEd Maste return false; 10461c3bbb01SEd Maste } 10471c3bbb01SEd Maste 1048435933ddSDimitry Andric if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) { 10494bb0738eSEd Maste thread = GetDefaultThread(); 1050435933ddSDimitry Andric } else { 1051435933ddSDimitry Andric thread = process->GetThreadList() 1052435933ddSDimitry Andric .FindThreadByIndexID(m_options.m_thread_idx) 1053435933ddSDimitry Andric .get(); 1054ac7ddfbfSEd Maste } 1055ac7ddfbfSEd Maste 1056435933ddSDimitry Andric if (thread == nullptr) { 1057ac7ddfbfSEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 1058435933ddSDimitry Andric result.AppendErrorWithFormat( 1059435933ddSDimitry Andric "Thread index %u is out of range (valid values are 0 - %u).\n", 1060435933ddSDimitry Andric m_options.m_thread_idx, num_threads); 1061ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1062ac7ddfbfSEd Maste return false; 1063ac7ddfbfSEd Maste } 1064ac7ddfbfSEd Maste 1065ac7ddfbfSEd Maste const bool abort_other_plans = false; 1066ac7ddfbfSEd Maste 1067435933ddSDimitry Andric StackFrame *frame = 1068435933ddSDimitry Andric thread->GetStackFrameAtIndex(m_options.m_frame_idx).get(); 1069435933ddSDimitry Andric if (frame == nullptr) { 1070435933ddSDimitry Andric result.AppendErrorWithFormat( 1071435933ddSDimitry Andric "Frame index %u is out of range for thread %u.\n", 1072435933ddSDimitry Andric m_options.m_frame_idx, m_options.m_thread_idx); 1073ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1074ac7ddfbfSEd Maste return false; 1075ac7ddfbfSEd Maste } 1076ac7ddfbfSEd Maste 1077ac7ddfbfSEd Maste ThreadPlanSP new_plan_sp; 1078ac7ddfbfSEd Maste 1079435933ddSDimitry Andric if (frame->HasDebugInformation()) { 1080435933ddSDimitry Andric // Finally we got here... Translate the given line number to a bunch of 1081435933ddSDimitry Andric // addresses: 1082ac7ddfbfSEd Maste SymbolContext sc(frame->GetSymbolContext(eSymbolContextCompUnit)); 10834bb0738eSEd Maste LineTable *line_table = nullptr; 1084ac7ddfbfSEd Maste if (sc.comp_unit) 1085ac7ddfbfSEd Maste line_table = sc.comp_unit->GetLineTable(); 1086ac7ddfbfSEd Maste 1087435933ddSDimitry Andric if (line_table == nullptr) { 1088435933ddSDimitry Andric result.AppendErrorWithFormat("Failed to resolve the line table for " 1089435933ddSDimitry Andric "frame %u of thread index %u.\n", 1090435933ddSDimitry Andric m_options.m_frame_idx, 1091435933ddSDimitry Andric m_options.m_thread_idx); 1092ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1093ac7ddfbfSEd Maste return false; 1094ac7ddfbfSEd Maste } 1095ac7ddfbfSEd Maste 1096ac7ddfbfSEd Maste LineEntry function_start; 1097ac7ddfbfSEd Maste uint32_t index_ptr = 0, end_ptr; 1098ac7ddfbfSEd Maste std::vector<addr_t> address_list; 1099ac7ddfbfSEd Maste 1100ac7ddfbfSEd Maste // Find the beginning & end index of the 1101ac7ddfbfSEd Maste AddressRange fun_addr_range = sc.function->GetAddressRange(); 1102ac7ddfbfSEd Maste Address fun_start_addr = fun_addr_range.GetBaseAddress(); 1103435933ddSDimitry Andric line_table->FindLineEntryByAddress(fun_start_addr, function_start, 1104435933ddSDimitry Andric &index_ptr); 1105ac7ddfbfSEd Maste 1106ac7ddfbfSEd Maste Address fun_end_addr(fun_start_addr.GetSection(), 1107435933ddSDimitry Andric fun_start_addr.GetOffset() + 1108435933ddSDimitry Andric fun_addr_range.GetByteSize()); 1109ac7ddfbfSEd Maste 1110ac7ddfbfSEd Maste bool all_in_function = true; 1111ac7ddfbfSEd Maste 1112435933ddSDimitry Andric line_table->FindLineEntryByAddress(fun_end_addr, function_start, 1113435933ddSDimitry Andric &end_ptr); 11141c3bbb01SEd Maste 1115435933ddSDimitry Andric for (uint32_t line_number : line_numbers) { 11161c3bbb01SEd Maste uint32_t start_idx_ptr = index_ptr; 1117435933ddSDimitry Andric while (start_idx_ptr <= end_ptr) { 1118ac7ddfbfSEd Maste LineEntry line_entry; 1119ac7ddfbfSEd Maste const bool exact = false; 1120435933ddSDimitry Andric start_idx_ptr = sc.comp_unit->FindLineEntry( 1121435933ddSDimitry Andric start_idx_ptr, line_number, sc.comp_unit, exact, &line_entry); 11221c3bbb01SEd Maste if (start_idx_ptr == UINT32_MAX) 1123ac7ddfbfSEd Maste break; 1124ac7ddfbfSEd Maste 1125435933ddSDimitry Andric addr_t address = 1126435933ddSDimitry Andric line_entry.range.GetBaseAddress().GetLoadAddress(target); 1127435933ddSDimitry Andric if (address != LLDB_INVALID_ADDRESS) { 1128ac7ddfbfSEd Maste if (fun_addr_range.ContainsLoadAddress(address, target)) 1129ac7ddfbfSEd Maste address_list.push_back(address); 1130ac7ddfbfSEd Maste else 1131ac7ddfbfSEd Maste all_in_function = false; 1132ac7ddfbfSEd Maste } 11331c3bbb01SEd Maste start_idx_ptr++; 11341c3bbb01SEd Maste } 11351c3bbb01SEd Maste } 11361c3bbb01SEd Maste 1137435933ddSDimitry Andric for (lldb::addr_t address : m_options.m_until_addrs) { 11381c3bbb01SEd Maste if (fun_addr_range.ContainsLoadAddress(address, target)) 11391c3bbb01SEd Maste address_list.push_back(address); 11401c3bbb01SEd Maste else 11411c3bbb01SEd Maste all_in_function = false; 1142ac7ddfbfSEd Maste } 1143ac7ddfbfSEd Maste 1144435933ddSDimitry Andric if (address_list.empty()) { 1145ac7ddfbfSEd Maste if (all_in_function) 1146435933ddSDimitry Andric result.AppendErrorWithFormat( 1147435933ddSDimitry Andric "No line entries matching until target.\n"); 1148ac7ddfbfSEd Maste else 1149435933ddSDimitry Andric result.AppendErrorWithFormat( 1150435933ddSDimitry Andric "Until target outside of the current function.\n"); 1151ac7ddfbfSEd Maste 1152ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1153ac7ddfbfSEd Maste return false; 1154ac7ddfbfSEd Maste } 1155ac7ddfbfSEd Maste 1156435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepUntil( 1157435933ddSDimitry Andric abort_other_plans, &address_list.front(), address_list.size(), 1158435933ddSDimitry Andric m_options.m_stop_others, m_options.m_frame_idx); 1159435933ddSDimitry Andric // User level plans should be master plans so they can be interrupted 1160435933ddSDimitry Andric // (e.g. by hitting a breakpoint) 1161435933ddSDimitry Andric // and other plans executed by the user (stepping around the breakpoint) 1162435933ddSDimitry Andric // and then a "continue" 1163ac7ddfbfSEd Maste // will resume the original plan. 1164ac7ddfbfSEd Maste new_plan_sp->SetIsMasterPlan(true); 1165ac7ddfbfSEd Maste new_plan_sp->SetOkayToDiscard(false); 1166435933ddSDimitry Andric } else { 1167435933ddSDimitry Andric result.AppendErrorWithFormat( 1168435933ddSDimitry Andric "Frame index %u of thread %u has no debug information.\n", 1169435933ddSDimitry Andric m_options.m_frame_idx, m_options.m_thread_idx); 1170ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1171ac7ddfbfSEd Maste return false; 1172ac7ddfbfSEd Maste } 1173ac7ddfbfSEd Maste 1174ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(m_options.m_thread_idx); 11757aa51b79SEd Maste 11767aa51b79SEd Maste StreamString stream; 11775517e702SDimitry Andric Status error; 11787aa51b79SEd Maste if (synchronous_execution) 11797aa51b79SEd Maste error = process->ResumeSynchronous(&stream); 11807aa51b79SEd Maste else 11817aa51b79SEd Maste error = process->Resume(); 11827aa51b79SEd Maste 1183435933ddSDimitry Andric if (error.Success()) { 1184435933ddSDimitry Andric result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n", 1185435933ddSDimitry Andric process->GetID()); 1186435933ddSDimitry Andric if (synchronous_execution) { 1187435933ddSDimitry Andric // If any state changed events had anything to say, add that to the 1188435933ddSDimitry Andric // result 1189435933ddSDimitry Andric if (stream.GetSize() > 0) 1190435933ddSDimitry Andric result.AppendMessage(stream.GetString()); 1191ac7ddfbfSEd Maste 1192ac7ddfbfSEd Maste result.SetDidChangeProcessState(true); 1193ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 1194435933ddSDimitry Andric } else { 1195ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessContinuingNoResult); 1196ac7ddfbfSEd Maste } 1197435933ddSDimitry Andric } else { 1198435933ddSDimitry Andric result.AppendErrorWithFormat("Failed to resume process: %s.\n", 1199435933ddSDimitry Andric error.AsCString()); 1200ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1201ac7ddfbfSEd Maste } 1202ac7ddfbfSEd Maste } 1203ac7ddfbfSEd Maste return result.Succeeded(); 1204ac7ddfbfSEd Maste } 1205ac7ddfbfSEd Maste 1206ac7ddfbfSEd Maste CommandOptions m_options; 1207ac7ddfbfSEd Maste }; 1208ac7ddfbfSEd Maste 1209ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1210ac7ddfbfSEd Maste // CommandObjectThreadSelect 1211ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1212ac7ddfbfSEd Maste 1213435933ddSDimitry Andric class CommandObjectThreadSelect : public CommandObjectParsed { 1214ac7ddfbfSEd Maste public: 12154bb0738eSEd Maste CommandObjectThreadSelect(CommandInterpreter &interpreter) 1216435933ddSDimitry Andric : CommandObjectParsed(interpreter, "thread select", 1217435933ddSDimitry Andric "Change the currently selected thread.", nullptr, 1218435933ddSDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 1219435933ddSDimitry Andric eCommandProcessMustBeLaunched | 1220435933ddSDimitry Andric eCommandProcessMustBePaused) { 1221ac7ddfbfSEd Maste CommandArgumentEntry arg; 1222ac7ddfbfSEd Maste CommandArgumentData thread_idx_arg; 1223ac7ddfbfSEd Maste 1224ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 1225ac7ddfbfSEd Maste thread_idx_arg.arg_type = eArgTypeThreadIndex; 1226ac7ddfbfSEd Maste thread_idx_arg.arg_repetition = eArgRepeatPlain; 1227ac7ddfbfSEd Maste 1228435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 1229435933ddSDimitry Andric // argument entry. 1230ac7ddfbfSEd Maste arg.push_back(thread_idx_arg); 1231ac7ddfbfSEd Maste 1232ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 1233ac7ddfbfSEd Maste m_arguments.push_back(arg); 1234ac7ddfbfSEd Maste } 1235ac7ddfbfSEd Maste 12364bb0738eSEd Maste ~CommandObjectThreadSelect() override = default; 1237ac7ddfbfSEd Maste 1238ac7ddfbfSEd Maste protected: 1239435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 1240ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 1241435933ddSDimitry Andric if (process == nullptr) { 1242ac7ddfbfSEd Maste result.AppendError("no process"); 1243ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1244ac7ddfbfSEd Maste return false; 1245435933ddSDimitry Andric } else if (command.GetArgumentCount() != 1) { 1246435933ddSDimitry Andric result.AppendErrorWithFormat( 1247435933ddSDimitry Andric "'%s' takes exactly one thread index argument:\nUsage: %s\n", 1248435933ddSDimitry Andric m_cmd_name.c_str(), m_cmd_syntax.c_str()); 1249ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1250ac7ddfbfSEd Maste return false; 1251ac7ddfbfSEd Maste } 1252ac7ddfbfSEd Maste 1253435933ddSDimitry Andric uint32_t index_id = 1254435933ddSDimitry Andric StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 1255ac7ddfbfSEd Maste 1256435933ddSDimitry Andric Thread *new_thread = 1257435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(index_id).get(); 1258435933ddSDimitry Andric if (new_thread == nullptr) { 1259435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread #%s.\n", 1260435933ddSDimitry Andric command.GetArgumentAtIndex(0)); 1261ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1262ac7ddfbfSEd Maste return false; 1263ac7ddfbfSEd Maste } 1264ac7ddfbfSEd Maste 1265ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true); 1266ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 1267ac7ddfbfSEd Maste 1268ac7ddfbfSEd Maste return result.Succeeded(); 1269ac7ddfbfSEd Maste } 1270ac7ddfbfSEd Maste }; 1271ac7ddfbfSEd Maste 1272ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1273ac7ddfbfSEd Maste // CommandObjectThreadList 1274ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1275ac7ddfbfSEd Maste 1276435933ddSDimitry Andric class CommandObjectThreadList : public CommandObjectParsed { 1277ac7ddfbfSEd Maste public: 12784bb0738eSEd Maste CommandObjectThreadList(CommandInterpreter &interpreter) 1279435933ddSDimitry Andric : CommandObjectParsed( 1280435933ddSDimitry Andric interpreter, "thread list", 1281435933ddSDimitry Andric "Show a summary of each thread in the current target process.", 1282435933ddSDimitry Andric "thread list", 1283435933ddSDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 1284435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 1285ac7ddfbfSEd Maste 12864bb0738eSEd Maste ~CommandObjectThreadList() override = default; 1287ac7ddfbfSEd Maste 1288ac7ddfbfSEd Maste protected: 1289435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 1290ac7ddfbfSEd Maste Stream &strm = result.GetOutputStream(); 1291ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 1292ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 1293ac7ddfbfSEd Maste const bool only_threads_with_stop_reason = false; 1294ac7ddfbfSEd Maste const uint32_t start_frame = 0; 1295ac7ddfbfSEd Maste const uint32_t num_frames = 0; 1296ac7ddfbfSEd Maste const uint32_t num_frames_with_source = 0; 1297ac7ddfbfSEd Maste process->GetStatus(strm); 1298435933ddSDimitry Andric process->GetThreadStatus(strm, only_threads_with_stop_reason, start_frame, 1299435933ddSDimitry Andric num_frames, num_frames_with_source, false); 1300ac7ddfbfSEd Maste return result.Succeeded(); 1301ac7ddfbfSEd Maste } 1302ac7ddfbfSEd Maste }; 1303ac7ddfbfSEd Maste 1304ac7ddfbfSEd Maste //------------------------------------------------------------------------- 13050127ef0fSEd Maste // CommandObjectThreadInfo 13060127ef0fSEd Maste //------------------------------------------------------------------------- 13070127ef0fSEd Maste 1308435933ddSDimitry Andric static OptionDefinition g_thread_info_options[] = { 1309435933ddSDimitry Andric // clang-format off 1310435933ddSDimitry Andric { LLDB_OPT_SET_ALL, false, "json", 'j', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display the thread info in JSON format." }, 1311435933ddSDimitry Andric { LLDB_OPT_SET_ALL, false, "stop-info", 's', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display the extended stop info in JSON format." } 1312435933ddSDimitry Andric // clang-format on 1313435933ddSDimitry Andric }; 1314435933ddSDimitry Andric 1315435933ddSDimitry Andric class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { 13160127ef0fSEd Maste public: 1317435933ddSDimitry Andric class CommandOptions : public Options { 13180127ef0fSEd Maste public: 1319435933ddSDimitry Andric CommandOptions() : Options() { OptionParsingStarting(nullptr); } 13200127ef0fSEd Maste 13214bb0738eSEd Maste ~CommandOptions() override = default; 13224bb0738eSEd Maste 1323435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 13247aa51b79SEd Maste m_json_thread = false; 13257aa51b79SEd Maste m_json_stopinfo = false; 13260127ef0fSEd Maste } 13270127ef0fSEd Maste 13285517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1329435933ddSDimitry Andric ExecutionContext *execution_context) override { 13300127ef0fSEd Maste const int short_option = m_getopt_table[option_idx].val; 13315517e702SDimitry Andric Status error; 13320127ef0fSEd Maste 1333435933ddSDimitry Andric switch (short_option) { 13340127ef0fSEd Maste case 'j': 13357aa51b79SEd Maste m_json_thread = true; 13367aa51b79SEd Maste break; 13377aa51b79SEd Maste 13387aa51b79SEd Maste case 's': 13397aa51b79SEd Maste m_json_stopinfo = true; 13400127ef0fSEd Maste break; 13410127ef0fSEd Maste 13420127ef0fSEd Maste default: 13435517e702SDimitry Andric return Status("invalid short option character '%c'", short_option); 13440127ef0fSEd Maste } 13450127ef0fSEd Maste return error; 13460127ef0fSEd Maste } 13470127ef0fSEd Maste 1348435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1349435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_info_options); 13500127ef0fSEd Maste } 13510127ef0fSEd Maste 13527aa51b79SEd Maste bool m_json_thread; 13537aa51b79SEd Maste bool m_json_stopinfo; 13540127ef0fSEd Maste }; 13550127ef0fSEd Maste 13564bb0738eSEd Maste CommandObjectThreadInfo(CommandInterpreter &interpreter) 13574bb0738eSEd Maste : CommandObjectIterateOverThreads( 1358435933ddSDimitry Andric interpreter, "thread info", "Show an extended summary of one or " 1359435933ddSDimitry Andric "more threads. Defaults to the " 1360435933ddSDimitry Andric "current thread.", 1361435933ddSDimitry Andric "thread info", 1362435933ddSDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 1363435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 1364435933ddSDimitry Andric m_options() { 13654bb0738eSEd Maste m_add_return = false; 13664bb0738eSEd Maste } 13674bb0738eSEd Maste 13684bb0738eSEd Maste ~CommandObjectThreadInfo() override = default; 13694bb0738eSEd Maste 1370435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 13710127ef0fSEd Maste 1372435933ddSDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 1373435933ddSDimitry Andric ThreadSP thread_sp = 1374435933ddSDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 1375435933ddSDimitry Andric if (!thread_sp) { 1376435933ddSDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", 1377435933ddSDimitry Andric tid); 13784bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 13794bb0738eSEd Maste return false; 13800127ef0fSEd Maste } 13810127ef0fSEd Maste 13824bb0738eSEd Maste Thread *thread = thread_sp.get(); 13834bb0738eSEd Maste 13840127ef0fSEd Maste Stream &strm = result.GetOutputStream(); 1385435933ddSDimitry Andric if (!thread->GetDescription(strm, eDescriptionLevelFull, 1386435933ddSDimitry Andric m_options.m_json_thread, 1387435933ddSDimitry Andric m_options.m_json_stopinfo)) { 1388435933ddSDimitry Andric result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n", 1389435933ddSDimitry Andric thread->GetIndexID()); 13900127ef0fSEd Maste result.SetStatus(eReturnStatusFailed); 13910127ef0fSEd Maste return false; 13920127ef0fSEd Maste } 13937aa51b79SEd Maste return true; 13940127ef0fSEd Maste } 13950127ef0fSEd Maste 13960127ef0fSEd Maste CommandOptions m_options; 13970127ef0fSEd Maste }; 13980127ef0fSEd Maste 13990127ef0fSEd Maste //------------------------------------------------------------------------- 1400ac7ddfbfSEd Maste // CommandObjectThreadReturn 1401ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1402ac7ddfbfSEd Maste 1403435933ddSDimitry Andric static OptionDefinition g_thread_return_options[] = { 1404435933ddSDimitry Andric // clang-format off 1405435933ddSDimitry Andric { LLDB_OPT_SET_ALL, false, "from-expression", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Return from the innermost expression evaluation." } 1406435933ddSDimitry Andric // clang-format on 1407435933ddSDimitry Andric }; 1408435933ddSDimitry Andric 1409435933ddSDimitry Andric class CommandObjectThreadReturn : public CommandObjectRaw { 1410ac7ddfbfSEd Maste public: 1411435933ddSDimitry Andric class CommandOptions : public Options { 1412ac7ddfbfSEd Maste public: 1413435933ddSDimitry Andric CommandOptions() : Options(), m_from_expression(false) { 1414435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 1415435933ddSDimitry Andric // () 1416435933ddSDimitry Andric OptionParsingStarting(nullptr); 1417ac7ddfbfSEd Maste } 1418ac7ddfbfSEd Maste 14194bb0738eSEd Maste ~CommandOptions() override = default; 1420ac7ddfbfSEd Maste 14215517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1422435933ddSDimitry Andric ExecutionContext *execution_context) override { 14235517e702SDimitry Andric Status error; 1424ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 1425ac7ddfbfSEd Maste 1426435933ddSDimitry Andric switch (short_option) { 1427435933ddSDimitry Andric case 'x': { 1428ac7ddfbfSEd Maste bool success; 1429ac7ddfbfSEd Maste bool tmp_value = Args::StringToBoolean(option_arg, false, &success); 1430ac7ddfbfSEd Maste if (success) 1431ac7ddfbfSEd Maste m_from_expression = tmp_value; 1432435933ddSDimitry Andric else { 1433435933ddSDimitry Andric error.SetErrorStringWithFormat( 1434435933ddSDimitry Andric "invalid boolean value '%s' for 'x' option", 1435435933ddSDimitry Andric option_arg.str().c_str()); 1436ac7ddfbfSEd Maste } 1437435933ddSDimitry Andric } break; 1438ac7ddfbfSEd Maste default: 1439435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 1440435933ddSDimitry Andric short_option); 1441ac7ddfbfSEd Maste break; 1442ac7ddfbfSEd Maste } 1443ac7ddfbfSEd Maste return error; 1444ac7ddfbfSEd Maste } 1445ac7ddfbfSEd Maste 1446435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 1447ac7ddfbfSEd Maste m_from_expression = false; 1448ac7ddfbfSEd Maste } 1449ac7ddfbfSEd Maste 1450435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1451435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_return_options); 1452ac7ddfbfSEd Maste } 1453ac7ddfbfSEd Maste 1454ac7ddfbfSEd Maste bool m_from_expression; 1455ac7ddfbfSEd Maste 1456ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 1457ac7ddfbfSEd Maste }; 1458ac7ddfbfSEd Maste 14594bb0738eSEd Maste CommandObjectThreadReturn(CommandInterpreter &interpreter) 14604bb0738eSEd Maste : CommandObjectRaw(interpreter, "thread return", 1461435933ddSDimitry Andric "Prematurely return from a stack frame, " 1462435933ddSDimitry Andric "short-circuiting execution of newer frames " 1463435933ddSDimitry Andric "and optionally yielding a specified value. Defaults " 1464435933ddSDimitry Andric "to the exiting the current stack " 14654bb0738eSEd Maste "frame.", 1466435933ddSDimitry Andric "thread return", 1467435933ddSDimitry Andric eCommandRequiresFrame | eCommandTryTargetAPILock | 1468435933ddSDimitry Andric eCommandProcessMustBeLaunched | 1469435933ddSDimitry Andric eCommandProcessMustBePaused), 1470435933ddSDimitry Andric m_options() { 1471ac7ddfbfSEd Maste CommandArgumentEntry arg; 1472ac7ddfbfSEd Maste CommandArgumentData expression_arg; 1473ac7ddfbfSEd Maste 1474ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 1475ac7ddfbfSEd Maste expression_arg.arg_type = eArgTypeExpression; 1476ac7ddfbfSEd Maste expression_arg.arg_repetition = eArgRepeatOptional; 1477ac7ddfbfSEd Maste 1478435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 1479435933ddSDimitry Andric // argument entry. 1480ac7ddfbfSEd Maste arg.push_back(expression_arg); 1481ac7ddfbfSEd Maste 1482ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 1483ac7ddfbfSEd Maste m_arguments.push_back(arg); 1484ac7ddfbfSEd Maste } 1485ac7ddfbfSEd Maste 14864bb0738eSEd Maste ~CommandObjectThreadReturn() override = default; 14874bb0738eSEd Maste 1488435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 1489ac7ddfbfSEd Maste 1490ac7ddfbfSEd Maste protected: 1491435933ddSDimitry Andric bool DoExecute(const char *command, CommandReturnObject &result) override { 1492435933ddSDimitry Andric // I am going to handle this by hand, because I don't want you to have to 1493435933ddSDimitry Andric // say: 1494ac7ddfbfSEd Maste // "thread return -- -5". 1495435933ddSDimitry Andric if (command[0] == '-' && command[1] == 'x') { 1496ac7ddfbfSEd Maste if (command && command[2] != '\0') 1497435933ddSDimitry Andric result.AppendWarning("Return values ignored when returning from user " 1498435933ddSDimitry Andric "called expressions"); 1499ac7ddfbfSEd Maste 1500ac7ddfbfSEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 15015517e702SDimitry Andric Status error; 1502ac7ddfbfSEd Maste error = thread->UnwindInnermostExpression(); 1503435933ddSDimitry Andric if (!error.Success()) { 1504435933ddSDimitry Andric result.AppendErrorWithFormat("Unwinding expression failed - %s.", 1505435933ddSDimitry Andric error.AsCString()); 1506ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1507435933ddSDimitry Andric } else { 1508435933ddSDimitry Andric bool success = 1509435933ddSDimitry Andric thread->SetSelectedFrameByIndexNoisily(0, result.GetOutputStream()); 1510435933ddSDimitry Andric if (success) { 1511ac7ddfbfSEd Maste m_exe_ctx.SetFrameSP(thread->GetSelectedFrame()); 1512ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult); 1513435933ddSDimitry Andric } else { 1514435933ddSDimitry Andric result.AppendErrorWithFormat( 1515435933ddSDimitry Andric "Could not select 0th frame after unwinding expression."); 1516ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1517ac7ddfbfSEd Maste } 1518ac7ddfbfSEd Maste } 1519ac7ddfbfSEd Maste return result.Succeeded(); 1520ac7ddfbfSEd Maste } 1521ac7ddfbfSEd Maste 1522ac7ddfbfSEd Maste ValueObjectSP return_valobj_sp; 1523ac7ddfbfSEd Maste 1524ac7ddfbfSEd Maste StackFrameSP frame_sp = m_exe_ctx.GetFrameSP(); 1525ac7ddfbfSEd Maste uint32_t frame_idx = frame_sp->GetFrameIndex(); 1526ac7ddfbfSEd Maste 1527435933ddSDimitry Andric if (frame_sp->IsInlined()) { 1528ac7ddfbfSEd Maste result.AppendError("Don't know how to return from inlined frames."); 1529ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1530ac7ddfbfSEd Maste return false; 1531ac7ddfbfSEd Maste } 1532ac7ddfbfSEd Maste 1533435933ddSDimitry Andric if (command && command[0] != '\0') { 1534ac7ddfbfSEd Maste Target *target = m_exe_ctx.GetTargetPtr(); 1535ac7ddfbfSEd Maste EvaluateExpressionOptions options; 1536ac7ddfbfSEd Maste 1537ac7ddfbfSEd Maste options.SetUnwindOnError(true); 1538ac7ddfbfSEd Maste options.SetUseDynamic(eNoDynamicValues); 1539ac7ddfbfSEd Maste 15400127ef0fSEd Maste ExpressionResults exe_results = eExpressionSetupError; 1541435933ddSDimitry Andric exe_results = target->EvaluateExpression(command, frame_sp.get(), 1542435933ddSDimitry Andric return_valobj_sp, options); 1543435933ddSDimitry Andric if (exe_results != eExpressionCompleted) { 1544ac7ddfbfSEd Maste if (return_valobj_sp) 1545435933ddSDimitry Andric result.AppendErrorWithFormat( 1546435933ddSDimitry Andric "Error evaluating result expression: %s", 1547435933ddSDimitry Andric return_valobj_sp->GetError().AsCString()); 1548ac7ddfbfSEd Maste else 1549435933ddSDimitry Andric result.AppendErrorWithFormat( 1550435933ddSDimitry Andric "Unknown error evaluating result expression."); 1551ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1552ac7ddfbfSEd Maste return false; 1553ac7ddfbfSEd Maste } 1554ac7ddfbfSEd Maste } 1555ac7ddfbfSEd Maste 15565517e702SDimitry Andric Status error; 1557ac7ddfbfSEd Maste ThreadSP thread_sp = m_exe_ctx.GetThreadSP(); 1558ac7ddfbfSEd Maste const bool broadcast = true; 1559ac7ddfbfSEd Maste error = thread_sp->ReturnFromFrame(frame_sp, return_valobj_sp, broadcast); 1560435933ddSDimitry Andric if (!error.Success()) { 1561435933ddSDimitry Andric result.AppendErrorWithFormat( 1562435933ddSDimitry Andric "Error returning from frame %d of thread %d: %s.", frame_idx, 1563435933ddSDimitry Andric thread_sp->GetIndexID(), error.AsCString()); 1564ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1565ac7ddfbfSEd Maste return false; 1566ac7ddfbfSEd Maste } 1567ac7ddfbfSEd Maste 1568ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult); 1569ac7ddfbfSEd Maste return true; 1570ac7ddfbfSEd Maste } 1571ac7ddfbfSEd Maste 1572ac7ddfbfSEd Maste CommandOptions m_options; 1573ac7ddfbfSEd Maste }; 15744bb0738eSEd Maste 157535617911SEd Maste //------------------------------------------------------------------------- 157635617911SEd Maste // CommandObjectThreadJump 157735617911SEd Maste //------------------------------------------------------------------------- 157835617911SEd Maste 1579435933ddSDimitry Andric static OptionDefinition g_thread_jump_options[] = { 1580435933ddSDimitry Andric // clang-format off 1581435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specifies the source file to jump to." }, 1582435933ddSDimitry Andric { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, "Specifies the line number to jump to." }, 1583435933ddSDimitry Andric { LLDB_OPT_SET_2, true, "by", 'b', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "Jumps by a relative line offset from the current line." }, 1584435933ddSDimitry Andric { LLDB_OPT_SET_3, true, "address", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddressOrExpression, "Jumps to a specific address." }, 1585435933ddSDimitry 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." } 1586435933ddSDimitry Andric // clang-format on 1587435933ddSDimitry Andric }; 1588435933ddSDimitry Andric 1589435933ddSDimitry Andric class CommandObjectThreadJump : public CommandObjectParsed { 159035617911SEd Maste public: 1591435933ddSDimitry Andric class CommandOptions : public Options { 159235617911SEd Maste public: 1593435933ddSDimitry Andric CommandOptions() : Options() { OptionParsingStarting(nullptr); } 159435617911SEd Maste 15954bb0738eSEd Maste ~CommandOptions() override = default; 15964bb0738eSEd Maste 1597435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 159835617911SEd Maste m_filenames.Clear(); 159935617911SEd Maste m_line_num = 0; 160035617911SEd Maste m_line_offset = 0; 160135617911SEd Maste m_load_addr = LLDB_INVALID_ADDRESS; 160235617911SEd Maste m_force = false; 160335617911SEd Maste } 160435617911SEd Maste 16055517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1606435933ddSDimitry Andric ExecutionContext *execution_context) override { 160735617911SEd Maste const int short_option = m_getopt_table[option_idx].val; 16085517e702SDimitry Andric Status error; 160935617911SEd Maste 1610435933ddSDimitry Andric switch (short_option) { 161135617911SEd Maste case 'f': 161235617911SEd Maste m_filenames.AppendIfUnique(FileSpec(option_arg, false)); 161335617911SEd Maste if (m_filenames.GetSize() > 1) 16145517e702SDimitry Andric return Status("only one source file expected."); 161535617911SEd Maste break; 161635617911SEd Maste case 'l': 1617435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_line_num)) 16185517e702SDimitry Andric return Status("invalid line number: '%s'.", option_arg.str().c_str()); 161935617911SEd Maste break; 162035617911SEd Maste case 'b': 1621435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_line_offset)) 16225517e702SDimitry Andric return Status("invalid line offset: '%s'.", option_arg.str().c_str()); 162335617911SEd Maste break; 162435617911SEd Maste case 'a': 1625435933ddSDimitry Andric m_load_addr = Args::StringToAddress(execution_context, option_arg, 1626435933ddSDimitry Andric LLDB_INVALID_ADDRESS, &error); 162735617911SEd Maste break; 162835617911SEd Maste case 'r': 162935617911SEd Maste m_force = true; 163035617911SEd Maste break; 163135617911SEd Maste default: 16325517e702SDimitry Andric return Status("invalid short option character '%c'", short_option); 163335617911SEd Maste } 163435617911SEd Maste return error; 163535617911SEd Maste } 163635617911SEd Maste 1637435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1638435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_jump_options); 163935617911SEd Maste } 164035617911SEd Maste 164135617911SEd Maste FileSpecList m_filenames; 164235617911SEd Maste uint32_t m_line_num; 164335617911SEd Maste int32_t m_line_offset; 164435617911SEd Maste lldb::addr_t m_load_addr; 164535617911SEd Maste bool m_force; 164635617911SEd Maste }; 164735617911SEd Maste 1648435933ddSDimitry Andric CommandObjectThreadJump(CommandInterpreter &interpreter) 1649435933ddSDimitry Andric : CommandObjectParsed( 1650435933ddSDimitry Andric interpreter, "thread jump", 1651435933ddSDimitry Andric "Sets the program counter to a new address.", "thread jump", 1652435933ddSDimitry Andric eCommandRequiresFrame | eCommandTryTargetAPILock | 1653435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 1654435933ddSDimitry Andric m_options() {} 165535617911SEd Maste 16564bb0738eSEd Maste ~CommandObjectThreadJump() override = default; 16574bb0738eSEd Maste 1658435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 165935617911SEd Maste 166035617911SEd Maste protected: 1661435933ddSDimitry Andric bool DoExecute(Args &args, CommandReturnObject &result) override { 166235617911SEd Maste RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext(); 166335617911SEd Maste StackFrame *frame = m_exe_ctx.GetFramePtr(); 166435617911SEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 166535617911SEd Maste Target *target = m_exe_ctx.GetTargetPtr(); 1666435933ddSDimitry Andric const SymbolContext &sym_ctx = 1667435933ddSDimitry Andric frame->GetSymbolContext(eSymbolContextLineEntry); 166835617911SEd Maste 1669435933ddSDimitry Andric if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) { 167035617911SEd Maste // Use this address directly. 167135617911SEd Maste Address dest = Address(m_options.m_load_addr); 167235617911SEd Maste 167335617911SEd Maste lldb::addr_t callAddr = dest.GetCallableLoadAddress(target); 1674435933ddSDimitry Andric if (callAddr == LLDB_INVALID_ADDRESS) { 167535617911SEd Maste result.AppendErrorWithFormat("Invalid destination address."); 167635617911SEd Maste result.SetStatus(eReturnStatusFailed); 167735617911SEd Maste return false; 167835617911SEd Maste } 167935617911SEd Maste 1680435933ddSDimitry Andric if (!reg_ctx->SetPC(callAddr)) { 1681435933ddSDimitry Andric result.AppendErrorWithFormat("Error changing PC value for thread %d.", 1682435933ddSDimitry Andric thread->GetIndexID()); 168335617911SEd Maste result.SetStatus(eReturnStatusFailed); 168435617911SEd Maste return false; 168535617911SEd Maste } 1686435933ddSDimitry Andric } else { 168735617911SEd Maste // Pick either the absolute line, or work out a relative one. 168835617911SEd Maste int32_t line = (int32_t)m_options.m_line_num; 168935617911SEd Maste if (line == 0) 169035617911SEd Maste line = sym_ctx.line_entry.line + m_options.m_line_offset; 169135617911SEd Maste 169235617911SEd Maste // Try the current file, but override if asked. 169335617911SEd Maste FileSpec file = sym_ctx.line_entry.file; 169435617911SEd Maste if (m_options.m_filenames.GetSize() == 1) 169535617911SEd Maste file = m_options.m_filenames.GetFileSpecAtIndex(0); 169635617911SEd Maste 1697435933ddSDimitry Andric if (!file) { 1698435933ddSDimitry Andric result.AppendErrorWithFormat( 1699435933ddSDimitry Andric "No source file available for the current location."); 170035617911SEd Maste result.SetStatus(eReturnStatusFailed); 170135617911SEd Maste return false; 170235617911SEd Maste } 170335617911SEd Maste 170435617911SEd Maste std::string warnings; 17055517e702SDimitry Andric Status err = thread->JumpToLine(file, line, m_options.m_force, &warnings); 170635617911SEd Maste 1707435933ddSDimitry Andric if (err.Fail()) { 170835617911SEd Maste result.SetError(err); 170935617911SEd Maste return false; 171035617911SEd Maste } 171135617911SEd Maste 171235617911SEd Maste if (!warnings.empty()) 171335617911SEd Maste result.AppendWarning(warnings.c_str()); 171435617911SEd Maste } 171535617911SEd Maste 171635617911SEd Maste result.SetStatus(eReturnStatusSuccessFinishResult); 171735617911SEd Maste return true; 171835617911SEd Maste } 171935617911SEd Maste 172035617911SEd Maste CommandOptions m_options; 172135617911SEd Maste }; 17224bb0738eSEd Maste 1723ac7ddfbfSEd Maste //------------------------------------------------------------------------- 17247aa51b79SEd Maste // Next are the subcommands of CommandObjectMultiwordThreadPlan 17257aa51b79SEd Maste //------------------------------------------------------------------------- 17267aa51b79SEd Maste 17277aa51b79SEd Maste //------------------------------------------------------------------------- 17287aa51b79SEd Maste // CommandObjectThreadPlanList 17297aa51b79SEd Maste //------------------------------------------------------------------------- 17304bb0738eSEd Maste 1731435933ddSDimitry Andric static OptionDefinition g_thread_plan_list_options[] = { 1732435933ddSDimitry Andric // clang-format off 1733435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display more information about the thread plans" }, 1734435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "internal", 'i', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display internal as well as user thread plans" } 1735435933ddSDimitry Andric // clang-format on 1736435933ddSDimitry Andric }; 1737435933ddSDimitry Andric 1738435933ddSDimitry Andric class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads { 17397aa51b79SEd Maste public: 1740435933ddSDimitry Andric class CommandOptions : public Options { 17417aa51b79SEd Maste public: 1742435933ddSDimitry Andric CommandOptions() : Options() { 1743435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 1744435933ddSDimitry Andric // () 1745435933ddSDimitry Andric OptionParsingStarting(nullptr); 17467aa51b79SEd Maste } 17477aa51b79SEd Maste 17484bb0738eSEd Maste ~CommandOptions() override = default; 17497aa51b79SEd Maste 17505517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1751435933ddSDimitry Andric ExecutionContext *execution_context) override { 17525517e702SDimitry Andric Status error; 17537aa51b79SEd Maste const int short_option = m_getopt_table[option_idx].val; 17547aa51b79SEd Maste 1755435933ddSDimitry Andric switch (short_option) { 17567aa51b79SEd Maste case 'i': 17577aa51b79SEd Maste m_internal = true; 17587aa51b79SEd Maste break; 17597aa51b79SEd Maste case 'v': 17607aa51b79SEd Maste m_verbose = true; 17617aa51b79SEd Maste break; 17627aa51b79SEd Maste default: 1763435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 1764435933ddSDimitry Andric short_option); 17657aa51b79SEd Maste break; 17667aa51b79SEd Maste } 17677aa51b79SEd Maste return error; 17687aa51b79SEd Maste } 17697aa51b79SEd Maste 1770435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 17717aa51b79SEd Maste m_verbose = false; 17727aa51b79SEd Maste m_internal = false; 17737aa51b79SEd Maste } 17747aa51b79SEd Maste 1775435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1776435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_plan_list_options); 17777aa51b79SEd Maste } 17787aa51b79SEd Maste 17797aa51b79SEd Maste // Instance variables to hold the values for command options. 17807aa51b79SEd Maste bool m_verbose; 17817aa51b79SEd Maste bool m_internal; 17827aa51b79SEd Maste }; 17837aa51b79SEd Maste 17844bb0738eSEd Maste CommandObjectThreadPlanList(CommandInterpreter &interpreter) 17854bb0738eSEd Maste : CommandObjectIterateOverThreads( 17864bb0738eSEd Maste interpreter, "thread plan list", 1787435933ddSDimitry Andric "Show thread plans for one or more threads. If no threads are " 1788435933ddSDimitry Andric "specified, show the " 17894bb0738eSEd Maste "current thread. Use the thread-index \"all\" to see all threads.", 1790435933ddSDimitry Andric nullptr, 1791435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 1792435933ddSDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 1793435933ddSDimitry Andric eCommandProcessMustBePaused), 1794435933ddSDimitry Andric m_options() {} 17957aa51b79SEd Maste 17964bb0738eSEd Maste ~CommandObjectThreadPlanList() override = default; 17977aa51b79SEd Maste 1798435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 17997aa51b79SEd Maste 18007aa51b79SEd Maste protected: 1801435933ddSDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 1802435933ddSDimitry Andric ThreadSP thread_sp = 1803435933ddSDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 1804435933ddSDimitry Andric if (!thread_sp) { 1805435933ddSDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", 1806435933ddSDimitry Andric tid); 18074bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 18084bb0738eSEd Maste return false; 18094bb0738eSEd Maste } 18104bb0738eSEd Maste 18114bb0738eSEd Maste Thread *thread = thread_sp.get(); 18124bb0738eSEd Maste 18137aa51b79SEd Maste Stream &strm = result.GetOutputStream(); 18147aa51b79SEd Maste DescriptionLevel desc_level = eDescriptionLevelFull; 18157aa51b79SEd Maste if (m_options.m_verbose) 18167aa51b79SEd Maste desc_level = eDescriptionLevelVerbose; 18177aa51b79SEd Maste 18184bb0738eSEd Maste thread->DumpThreadPlans(&strm, desc_level, m_options.m_internal, true); 18197aa51b79SEd Maste return true; 18207aa51b79SEd Maste } 18214bb0738eSEd Maste 18227aa51b79SEd Maste CommandOptions m_options; 18237aa51b79SEd Maste }; 18247aa51b79SEd Maste 1825435933ddSDimitry Andric class CommandObjectThreadPlanDiscard : public CommandObjectParsed { 18267aa51b79SEd Maste public: 18274bb0738eSEd Maste CommandObjectThreadPlanDiscard(CommandInterpreter &interpreter) 1828435933ddSDimitry Andric : CommandObjectParsed(interpreter, "thread plan discard", 1829435933ddSDimitry Andric "Discards thread plans up to and including the " 1830435933ddSDimitry Andric "specified index (see 'thread plan list'.) " 18314bb0738eSEd Maste "Only user visible plans can be discarded.", 1832435933ddSDimitry Andric nullptr, 1833435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 1834435933ddSDimitry Andric eCommandTryTargetAPILock | 1835435933ddSDimitry Andric eCommandProcessMustBeLaunched | 1836435933ddSDimitry Andric eCommandProcessMustBePaused) { 18377aa51b79SEd Maste CommandArgumentEntry arg; 18387aa51b79SEd Maste CommandArgumentData plan_index_arg; 18397aa51b79SEd Maste 18407aa51b79SEd Maste // Define the first (and only) variant of this arg. 18417aa51b79SEd Maste plan_index_arg.arg_type = eArgTypeUnsignedInteger; 18427aa51b79SEd Maste plan_index_arg.arg_repetition = eArgRepeatPlain; 18437aa51b79SEd Maste 1844435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 1845435933ddSDimitry Andric // argument entry. 18467aa51b79SEd Maste arg.push_back(plan_index_arg); 18477aa51b79SEd Maste 18487aa51b79SEd Maste // Push the data for the first argument into the m_arguments vector. 18497aa51b79SEd Maste m_arguments.push_back(arg); 18507aa51b79SEd Maste } 18517aa51b79SEd Maste 18524bb0738eSEd Maste ~CommandObjectThreadPlanDiscard() override = default; 18537aa51b79SEd Maste 1854435933ddSDimitry Andric bool DoExecute(Args &args, CommandReturnObject &result) override { 18557aa51b79SEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 1856435933ddSDimitry Andric if (args.GetArgumentCount() != 1) { 1857435933ddSDimitry Andric result.AppendErrorWithFormat("Too many arguments, expected one - the " 1858435933ddSDimitry Andric "thread plan index - but got %zu.", 18597aa51b79SEd Maste args.GetArgumentCount()); 18607aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 18617aa51b79SEd Maste return false; 18627aa51b79SEd Maste } 18637aa51b79SEd Maste 18647aa51b79SEd Maste bool success; 1865435933ddSDimitry Andric uint32_t thread_plan_idx = 1866435933ddSDimitry Andric StringConvert::ToUInt32(args.GetArgumentAtIndex(0), 0, 0, &success); 1867435933ddSDimitry Andric if (!success) { 1868435933ddSDimitry Andric result.AppendErrorWithFormat( 1869435933ddSDimitry Andric "Invalid thread index: \"%s\" - should be unsigned int.", 18707aa51b79SEd Maste args.GetArgumentAtIndex(0)); 18717aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 18727aa51b79SEd Maste return false; 18737aa51b79SEd Maste } 18747aa51b79SEd Maste 1875435933ddSDimitry Andric if (thread_plan_idx == 0) { 1876435933ddSDimitry Andric result.AppendErrorWithFormat( 1877435933ddSDimitry Andric "You wouldn't really want me to discard the base thread plan."); 18787aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 18797aa51b79SEd Maste return false; 18807aa51b79SEd Maste } 18817aa51b79SEd Maste 1882435933ddSDimitry Andric if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) { 18837aa51b79SEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 18847aa51b79SEd Maste return true; 1885435933ddSDimitry Andric } else { 1886435933ddSDimitry Andric result.AppendErrorWithFormat( 1887435933ddSDimitry Andric "Could not find User thread plan with index %s.", 18887aa51b79SEd Maste args.GetArgumentAtIndex(0)); 18897aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 18907aa51b79SEd Maste return false; 18917aa51b79SEd Maste } 18927aa51b79SEd Maste } 18937aa51b79SEd Maste }; 18947aa51b79SEd Maste 18957aa51b79SEd Maste //------------------------------------------------------------------------- 18967aa51b79SEd Maste // CommandObjectMultiwordThreadPlan 18977aa51b79SEd Maste //------------------------------------------------------------------------- 18987aa51b79SEd Maste 1899435933ddSDimitry Andric class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword { 19007aa51b79SEd Maste public: 19014bb0738eSEd Maste CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter) 1902435933ddSDimitry Andric : CommandObjectMultiword( 1903435933ddSDimitry Andric interpreter, "plan", 1904435933ddSDimitry Andric "Commands for managing thread plans that control execution.", 1905435933ddSDimitry Andric "thread plan <subcommand> [<subcommand objects]") { 1906435933ddSDimitry Andric LoadSubCommand( 1907435933ddSDimitry Andric "list", CommandObjectSP(new CommandObjectThreadPlanList(interpreter))); 1908435933ddSDimitry Andric LoadSubCommand( 1909435933ddSDimitry Andric "discard", 1910435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadPlanDiscard(interpreter))); 19117aa51b79SEd Maste } 19127aa51b79SEd Maste 19134bb0738eSEd Maste ~CommandObjectMultiwordThreadPlan() override = default; 19147aa51b79SEd Maste }; 19157aa51b79SEd Maste 19167aa51b79SEd Maste //------------------------------------------------------------------------- 1917ac7ddfbfSEd Maste // CommandObjectMultiwordThread 1918ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1919ac7ddfbfSEd Maste 1920435933ddSDimitry Andric CommandObjectMultiwordThread::CommandObjectMultiwordThread( 1921435933ddSDimitry Andric CommandInterpreter &interpreter) 1922435933ddSDimitry Andric : CommandObjectMultiword(interpreter, "thread", "Commands for operating on " 1923435933ddSDimitry Andric "one or more threads in " 1924435933ddSDimitry Andric "the current process.", 1925435933ddSDimitry Andric "thread <subcommand> [<subcommand-options>]") { 1926435933ddSDimitry Andric LoadSubCommand("backtrace", CommandObjectSP(new CommandObjectThreadBacktrace( 1927435933ddSDimitry Andric interpreter))); 1928435933ddSDimitry Andric LoadSubCommand("continue", 1929435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadContinue(interpreter))); 1930435933ddSDimitry Andric LoadSubCommand("list", 1931435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadList(interpreter))); 1932435933ddSDimitry Andric LoadSubCommand("return", 1933435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadReturn(interpreter))); 1934435933ddSDimitry Andric LoadSubCommand("jump", 1935435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadJump(interpreter))); 1936435933ddSDimitry Andric LoadSubCommand("select", 1937435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadSelect(interpreter))); 1938435933ddSDimitry Andric LoadSubCommand("until", 1939435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadUntil(interpreter))); 1940435933ddSDimitry Andric LoadSubCommand("info", 1941435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadInfo(interpreter))); 19424bb0738eSEd Maste LoadSubCommand("step-in", 19434bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 19444bb0738eSEd Maste interpreter, "thread step-in", 1945435933ddSDimitry Andric "Source level single step, stepping into calls. Defaults " 1946435933ddSDimitry Andric "to current thread unless specified.", 19474bb0738eSEd Maste nullptr, eStepTypeInto, eStepScopeSource))); 1948ac7ddfbfSEd Maste 19494bb0738eSEd Maste LoadSubCommand("step-out", 19504bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 1951435933ddSDimitry Andric interpreter, "thread step-out", 1952435933ddSDimitry Andric "Finish executing the current stack frame and stop after " 19534bb0738eSEd Maste "returning. Defaults to current thread unless specified.", 19544bb0738eSEd Maste nullptr, eStepTypeOut, eStepScopeSource))); 1955ac7ddfbfSEd Maste 19564bb0738eSEd Maste LoadSubCommand("step-over", 19574bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 19584bb0738eSEd Maste interpreter, "thread step-over", 1959435933ddSDimitry Andric "Source level single step, stepping over calls. Defaults " 1960435933ddSDimitry Andric "to current thread unless specified.", 19614bb0738eSEd Maste nullptr, eStepTypeOver, eStepScopeSource))); 1962ac7ddfbfSEd Maste 1963435933ddSDimitry Andric LoadSubCommand("step-inst", 19644bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 19654bb0738eSEd Maste interpreter, "thread step-inst", 1966435933ddSDimitry Andric "Instruction level single step, stepping into calls. " 1967435933ddSDimitry Andric "Defaults to current thread unless specified.", 19684bb0738eSEd Maste nullptr, eStepTypeTrace, eStepScopeInstruction))); 1969ac7ddfbfSEd Maste 1970435933ddSDimitry Andric LoadSubCommand("step-inst-over", 19714bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 19724bb0738eSEd Maste interpreter, "thread step-inst-over", 1973435933ddSDimitry Andric "Instruction level single step, stepping over calls. " 1974435933ddSDimitry Andric "Defaults to current thread unless specified.", 19754bb0738eSEd Maste nullptr, eStepTypeTraceOver, eStepScopeInstruction))); 19767aa51b79SEd Maste 1977435933ddSDimitry Andric LoadSubCommand( 1978435933ddSDimitry Andric "step-scripted", 1979435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 1980435933ddSDimitry Andric interpreter, "thread step-scripted", 19817aa51b79SEd Maste "Step as instructed by the script class passed in the -C option.", 1982435933ddSDimitry Andric nullptr, eStepTypeScripted, eStepScopeSource))); 19837aa51b79SEd Maste 1984435933ddSDimitry Andric LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan( 1985435933ddSDimitry Andric interpreter))); 1986ac7ddfbfSEd Maste } 1987ac7ddfbfSEd Maste 19884bb0738eSEd Maste CommandObjectMultiwordThread::~CommandObjectMultiwordThread() = default; 1989