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 //------------------------------------------------------------------------- 4524d58133SDimitry Andric // CommandObjectIterateOverThreads 46ac7ddfbfSEd Maste //------------------------------------------------------------------------- 47ac7ddfbfSEd Maste 48435933ddSDimitry Andric class CommandObjectIterateOverThreads : public CommandObjectParsed { 4924d58133SDimitry Andric 5024d58133SDimitry Andric class UniqueStack { 5124d58133SDimitry Andric 5224d58133SDimitry Andric public: 5324d58133SDimitry Andric UniqueStack(std::stack<lldb::addr_t> stack_frames, uint32_t thread_index_id) 5424d58133SDimitry Andric : m_stack_frames(stack_frames) { 5524d58133SDimitry Andric m_thread_index_ids.push_back(thread_index_id); 5624d58133SDimitry Andric } 5724d58133SDimitry Andric 5824d58133SDimitry Andric void AddThread(uint32_t thread_index_id) const { 5924d58133SDimitry Andric m_thread_index_ids.push_back(thread_index_id); 6024d58133SDimitry Andric } 6124d58133SDimitry Andric 6224d58133SDimitry Andric const std::vector<uint32_t> &GetUniqueThreadIndexIDs() const { 6324d58133SDimitry Andric return m_thread_index_ids; 6424d58133SDimitry Andric } 6524d58133SDimitry Andric 6624d58133SDimitry Andric lldb::tid_t GetRepresentativeThread() const { 6724d58133SDimitry Andric return m_thread_index_ids.front(); 6824d58133SDimitry Andric } 6924d58133SDimitry Andric 7024d58133SDimitry Andric friend bool inline operator<(const UniqueStack &lhs, 7124d58133SDimitry Andric const UniqueStack &rhs) { 7224d58133SDimitry Andric return lhs.m_stack_frames < rhs.m_stack_frames; 7324d58133SDimitry Andric } 7424d58133SDimitry Andric 7524d58133SDimitry Andric protected: 7624d58133SDimitry Andric // Mark the thread index as mutable, as we don't care about it from a const 7724d58133SDimitry Andric // perspective, we only care about m_stack_frames so we keep our std::set 7824d58133SDimitry Andric // sorted. 7924d58133SDimitry Andric mutable std::vector<uint32_t> m_thread_index_ids; 8024d58133SDimitry Andric std::stack<lldb::addr_t> m_stack_frames; 8124d58133SDimitry Andric }; 8224d58133SDimitry Andric 837aa51b79SEd Maste public: 847aa51b79SEd Maste CommandObjectIterateOverThreads(CommandInterpreter &interpreter, 85435933ddSDimitry Andric const char *name, const char *help, 86435933ddSDimitry Andric const char *syntax, uint32_t flags) 87435933ddSDimitry Andric : CommandObjectParsed(interpreter, name, help, syntax, flags) {} 887aa51b79SEd Maste 894bb0738eSEd Maste ~CommandObjectIterateOverThreads() override = default; 909f2f44ceSEd Maste 91435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 927aa51b79SEd Maste result.SetStatus(m_success_return); 937aa51b79SEd Maste 9424d58133SDimitry Andric bool all_threads = false; 95435933ddSDimitry Andric if (command.GetArgumentCount() == 0) { 967aa51b79SEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 97acac075bSDimitry Andric if (!thread || !HandleOneThread(thread->GetID(), result)) 987aa51b79SEd Maste return false; 994bb0738eSEd Maste return result.Succeeded(); 10024d58133SDimitry Andric } else if (command.GetArgumentCount() == 1) { 10124d58133SDimitry Andric all_threads = ::strcmp(command.GetArgumentAtIndex(0), "all") == 0; 10224d58133SDimitry Andric m_unique_stacks = ::strcmp(command.GetArgumentAtIndex(0), "unique") == 0; 1037aa51b79SEd Maste } 1044bb0738eSEd Maste 105435933ddSDimitry Andric // Use tids instead of ThreadSPs to prevent deadlocking problems which 106435933ddSDimitry Andric // result from JIT-ing 1074bb0738eSEd Maste // code while iterating over the (locked) ThreadSP list. 1084bb0738eSEd Maste std::vector<lldb::tid_t> tids; 1094bb0738eSEd Maste 11024d58133SDimitry Andric if (all_threads || m_unique_stacks) { 1117aa51b79SEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 1127aa51b79SEd Maste 1134bb0738eSEd Maste for (ThreadSP thread_sp : process->Threads()) 1144bb0738eSEd Maste tids.push_back(thread_sp->GetID()); 115435933ddSDimitry Andric } else { 1167aa51b79SEd Maste const size_t num_args = command.GetArgumentCount(); 1177aa51b79SEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 1184bb0738eSEd Maste 119435933ddSDimitry Andric std::lock_guard<std::recursive_mutex> guard( 120435933ddSDimitry Andric process->GetThreadList().GetMutex()); 1217aa51b79SEd Maste 122435933ddSDimitry Andric for (size_t i = 0; i < num_args; i++) { 1237aa51b79SEd Maste bool success; 1247aa51b79SEd Maste 125435933ddSDimitry Andric uint32_t thread_idx = StringConvert::ToUInt32( 126435933ddSDimitry Andric command.GetArgumentAtIndex(i), 0, 0, &success); 127435933ddSDimitry Andric if (!success) { 128435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", 129435933ddSDimitry Andric command.GetArgumentAtIndex(i)); 1307aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 1317aa51b79SEd Maste return false; 1327aa51b79SEd Maste } 1337aa51b79SEd Maste 134435933ddSDimitry Andric ThreadSP thread = 135435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(thread_idx); 1367aa51b79SEd Maste 137435933ddSDimitry Andric if (!thread) { 138435933ddSDimitry Andric result.AppendErrorWithFormat("no thread with index: \"%s\"\n", 139435933ddSDimitry Andric command.GetArgumentAtIndex(i)); 1407aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 1417aa51b79SEd Maste return false; 1427aa51b79SEd Maste } 1437aa51b79SEd Maste 1444bb0738eSEd Maste tids.push_back(thread->GetID()); 1454bb0738eSEd Maste } 1467aa51b79SEd Maste } 1477aa51b79SEd Maste 14824d58133SDimitry Andric if (m_unique_stacks) { 14924d58133SDimitry Andric // Iterate over threads, finding unique stack buckets. 15024d58133SDimitry Andric std::set<UniqueStack> unique_stacks; 15124d58133SDimitry Andric for (const lldb::tid_t &tid : tids) { 15224d58133SDimitry Andric if (!BucketThread(tid, unique_stacks, result)) { 15324d58133SDimitry Andric return false; 15424d58133SDimitry Andric } 15524d58133SDimitry Andric } 15624d58133SDimitry Andric 15724d58133SDimitry Andric // Write the thread id's and unique call stacks to the output stream 15824d58133SDimitry Andric Stream &strm = result.GetOutputStream(); 15924d58133SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr(); 16024d58133SDimitry Andric for (const UniqueStack &stack : unique_stacks) { 16124d58133SDimitry Andric // List the common thread ID's 16224d58133SDimitry Andric const std::vector<uint32_t> &thread_index_ids = 16324d58133SDimitry Andric stack.GetUniqueThreadIndexIDs(); 164c4394386SDimitry Andric strm.Format("{0} thread(s) ", thread_index_ids.size()); 16524d58133SDimitry Andric for (const uint32_t &thread_index_id : thread_index_ids) { 166c4394386SDimitry Andric strm.Format("#{0} ", thread_index_id); 16724d58133SDimitry Andric } 16824d58133SDimitry Andric strm.EOL(); 16924d58133SDimitry Andric 17024d58133SDimitry Andric // List the shared call stack for this set of threads 17124d58133SDimitry Andric uint32_t representative_thread_id = stack.GetRepresentativeThread(); 17224d58133SDimitry Andric ThreadSP thread = process->GetThreadList().FindThreadByIndexID( 17324d58133SDimitry Andric representative_thread_id); 17424d58133SDimitry Andric if (!HandleOneThread(thread->GetID(), result)) { 17524d58133SDimitry Andric return false; 17624d58133SDimitry Andric } 17724d58133SDimitry Andric } 17824d58133SDimitry Andric } else { 1794bb0738eSEd Maste uint32_t idx = 0; 180435933ddSDimitry Andric for (const lldb::tid_t &tid : tids) { 1814bb0738eSEd Maste if (idx != 0 && m_add_return) 1824bb0738eSEd Maste result.AppendMessage(""); 1834bb0738eSEd Maste 1844bb0738eSEd Maste if (!HandleOneThread(tid, result)) 1857aa51b79SEd Maste return false; 1867aa51b79SEd Maste 1874bb0738eSEd Maste ++idx; 1887aa51b79SEd Maste } 18924d58133SDimitry Andric } 1907aa51b79SEd Maste return result.Succeeded(); 1917aa51b79SEd Maste } 1927aa51b79SEd Maste 1937aa51b79SEd Maste protected: 1947aa51b79SEd Maste // Override this to do whatever you need to do for one thread. 1957aa51b79SEd Maste // 1967aa51b79SEd Maste // If you return false, the iteration will stop, otherwise it will proceed. 197435933ddSDimitry Andric // The result is set to m_success_return (defaults to 198435933ddSDimitry Andric // eReturnStatusSuccessFinishResult) before the iteration, 199435933ddSDimitry Andric // so you only need to set the return status in HandleOneThread if you want to 200435933ddSDimitry Andric // indicate an error. 201435933ddSDimitry Andric // If m_add_return is true, a blank line will be inserted between each of the 202435933ddSDimitry Andric // listings (except the last one.) 2037aa51b79SEd Maste 204435933ddSDimitry Andric virtual bool HandleOneThread(lldb::tid_t, CommandReturnObject &result) = 0; 2057aa51b79SEd Maste 20624d58133SDimitry Andric bool BucketThread(lldb::tid_t tid, std::set<UniqueStack> &unique_stacks, 20724d58133SDimitry Andric CommandReturnObject &result) { 20824d58133SDimitry Andric // Grab the corresponding thread for the given thread id. 20924d58133SDimitry Andric Process *process = m_exe_ctx.GetProcessPtr(); 21024d58133SDimitry Andric Thread *thread = process->GetThreadList().FindThreadByID(tid).get(); 21124d58133SDimitry Andric if (thread == nullptr) { 212c4394386SDimitry Andric result.AppendErrorWithFormatv("Failed to process thread #{0}.\n", tid); 21324d58133SDimitry Andric result.SetStatus(eReturnStatusFailed); 21424d58133SDimitry Andric return false; 21524d58133SDimitry Andric } 21624d58133SDimitry Andric 21724d58133SDimitry Andric // Collect the each frame's address for this call-stack 21824d58133SDimitry Andric std::stack<lldb::addr_t> stack_frames; 21924d58133SDimitry Andric const uint32_t frame_count = thread->GetStackFrameCount(); 22024d58133SDimitry Andric for (uint32_t frame_index = 0; frame_index < frame_count; frame_index++) { 22124d58133SDimitry Andric const lldb::StackFrameSP frame_sp = 22224d58133SDimitry Andric thread->GetStackFrameAtIndex(frame_index); 22324d58133SDimitry Andric const lldb::addr_t pc = frame_sp->GetStackID().GetPC(); 22424d58133SDimitry Andric stack_frames.push(pc); 22524d58133SDimitry Andric } 22624d58133SDimitry Andric 22724d58133SDimitry Andric uint32_t thread_index_id = thread->GetIndexID(); 22824d58133SDimitry Andric UniqueStack new_unique_stack(stack_frames, thread_index_id); 22924d58133SDimitry Andric 23024d58133SDimitry Andric // Try to match the threads stack to and existing entry. 23124d58133SDimitry Andric std::set<UniqueStack>::iterator matching_stack = 23224d58133SDimitry Andric unique_stacks.find(new_unique_stack); 23324d58133SDimitry Andric if (matching_stack != unique_stacks.end()) { 23424d58133SDimitry Andric matching_stack->AddThread(thread_index_id); 23524d58133SDimitry Andric } else { 23624d58133SDimitry Andric unique_stacks.insert(new_unique_stack); 23724d58133SDimitry Andric } 23824d58133SDimitry Andric return true; 23924d58133SDimitry Andric } 24024d58133SDimitry Andric 2417aa51b79SEd Maste ReturnStatus m_success_return = eReturnStatusSuccessFinishResult; 24224d58133SDimitry Andric bool m_unique_stacks = false; 2437aa51b79SEd Maste bool m_add_return = true; 2447aa51b79SEd Maste }; 2457aa51b79SEd Maste 2467aa51b79SEd Maste //------------------------------------------------------------------------- 2477aa51b79SEd Maste // CommandObjectThreadBacktrace 2487aa51b79SEd Maste //------------------------------------------------------------------------- 2497aa51b79SEd Maste 250435933ddSDimitry Andric static OptionDefinition g_thread_backtrace_options[] = { 251435933ddSDimitry Andric // clang-format off 252435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "How many frames to display (-1 for all)" }, 253435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "start", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFrameIndex, "Frame in which to start the backtrace" }, 254435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "extended", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Show the extended backtrace, if available" } 255435933ddSDimitry Andric // clang-format on 256435933ddSDimitry Andric }; 257435933ddSDimitry Andric 258435933ddSDimitry Andric class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads { 259ac7ddfbfSEd Maste public: 260435933ddSDimitry Andric class CommandOptions : public Options { 261ac7ddfbfSEd Maste public: 262435933ddSDimitry Andric CommandOptions() : Options() { 263435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 264435933ddSDimitry Andric // () 265435933ddSDimitry Andric OptionParsingStarting(nullptr); 266ac7ddfbfSEd Maste } 267ac7ddfbfSEd Maste 2684bb0738eSEd Maste ~CommandOptions() override = default; 269ac7ddfbfSEd Maste 2705517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 271435933ddSDimitry Andric ExecutionContext *execution_context) override { 2725517e702SDimitry Andric Status error; 273ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 274ac7ddfbfSEd Maste 275435933ddSDimitry Andric switch (short_option) { 276435933ddSDimitry Andric case 'c': { 277435933ddSDimitry Andric int32_t input_count = 0; 278435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_count)) { 279ac7ddfbfSEd Maste m_count = UINT32_MAX; 280435933ddSDimitry Andric error.SetErrorStringWithFormat( 281435933ddSDimitry Andric "invalid integer value for option '%c'", short_option); 282435933ddSDimitry Andric } else if (input_count < 0) 283435933ddSDimitry Andric m_count = UINT32_MAX; 284435933ddSDimitry Andric } break; 285ac7ddfbfSEd Maste case 's': 286435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_start)) 287435933ddSDimitry Andric error.SetErrorStringWithFormat( 288435933ddSDimitry Andric "invalid integer value for option '%c'", short_option); 2894bb0738eSEd Maste break; 290435933ddSDimitry Andric case 'e': { 291b952cd58SEd Maste bool success; 292435933ddSDimitry Andric m_extended_backtrace = 293435933ddSDimitry Andric Args::StringToBoolean(option_arg, false, &success); 294b952cd58SEd Maste if (!success) 295435933ddSDimitry Andric error.SetErrorStringWithFormat( 296435933ddSDimitry Andric "invalid boolean value for option '%c'", short_option); 297435933ddSDimitry Andric } break; 298ac7ddfbfSEd Maste default: 299435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 300435933ddSDimitry Andric short_option); 301ac7ddfbfSEd Maste break; 302ac7ddfbfSEd Maste } 303ac7ddfbfSEd Maste return error; 304ac7ddfbfSEd Maste } 305ac7ddfbfSEd Maste 306435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 307ac7ddfbfSEd Maste m_count = UINT32_MAX; 308ac7ddfbfSEd Maste m_start = 0; 309b952cd58SEd Maste m_extended_backtrace = false; 310ac7ddfbfSEd Maste } 311ac7ddfbfSEd Maste 312435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 313435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_backtrace_options); 314ac7ddfbfSEd Maste } 315ac7ddfbfSEd Maste 316ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 317ac7ddfbfSEd Maste uint32_t m_count; 318ac7ddfbfSEd Maste uint32_t m_start; 319b952cd58SEd Maste bool m_extended_backtrace; 320ac7ddfbfSEd Maste }; 321ac7ddfbfSEd Maste 3224bb0738eSEd Maste CommandObjectThreadBacktrace(CommandInterpreter &interpreter) 3234bb0738eSEd Maste : CommandObjectIterateOverThreads( 324435933ddSDimitry Andric interpreter, "thread backtrace", 325435933ddSDimitry Andric "Show thread call stacks. Defaults to the current thread, thread " 32624d58133SDimitry Andric "indexes can be specified as arguments.\n" 32724d58133SDimitry Andric "Use the thread-index \"all\" to see all threads.\n" 32824d58133SDimitry Andric "Use the thread-index \"unique\" to see threads grouped by unique " 32924d58133SDimitry Andric "call stacks.", 330435933ddSDimitry Andric nullptr, 331435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 332435933ddSDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 333435933ddSDimitry Andric eCommandProcessMustBePaused), 334435933ddSDimitry Andric m_options() {} 335ac7ddfbfSEd Maste 3364bb0738eSEd Maste ~CommandObjectThreadBacktrace() override = default; 337ac7ddfbfSEd Maste 338435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 339ac7ddfbfSEd Maste 340ac7ddfbfSEd Maste protected: 341435933ddSDimitry Andric void DoExtendedBacktrace(Thread *thread, CommandReturnObject &result) { 342b952cd58SEd Maste SystemRuntime *runtime = thread->GetProcess()->GetSystemRuntime(); 343435933ddSDimitry Andric if (runtime) { 344b952cd58SEd Maste Stream &strm = result.GetOutputStream(); 345435933ddSDimitry Andric const std::vector<ConstString> &types = 346435933ddSDimitry Andric runtime->GetExtendedBacktraceTypes(); 347435933ddSDimitry Andric for (auto type : types) { 348435933ddSDimitry Andric ThreadSP ext_thread_sp = runtime->GetExtendedBacktraceThread( 349435933ddSDimitry Andric thread->shared_from_this(), type); 350435933ddSDimitry Andric if (ext_thread_sp && ext_thread_sp->IsValid()) { 351b952cd58SEd Maste const uint32_t num_frames_with_source = 0; 352435933ddSDimitry Andric const bool stop_format = false; 353435933ddSDimitry Andric if (ext_thread_sp->GetStatus(strm, m_options.m_start, 354b952cd58SEd Maste m_options.m_count, 355435933ddSDimitry Andric num_frames_with_source, 356435933ddSDimitry Andric stop_format)) { 357b952cd58SEd Maste DoExtendedBacktrace(ext_thread_sp.get(), result); 358b952cd58SEd Maste } 359b952cd58SEd Maste } 360b952cd58SEd Maste } 361b952cd58SEd Maste } 362b952cd58SEd Maste } 363b952cd58SEd Maste 364435933ddSDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 365435933ddSDimitry Andric ThreadSP thread_sp = 366435933ddSDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 367435933ddSDimitry Andric if (!thread_sp) { 368435933ddSDimitry Andric result.AppendErrorWithFormat( 369435933ddSDimitry Andric "thread disappeared while computing backtraces: 0x%" PRIx64 "\n", 370435933ddSDimitry Andric tid); 3714bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 3724bb0738eSEd Maste return false; 3734bb0738eSEd Maste } 3744bb0738eSEd Maste 3754bb0738eSEd Maste Thread *thread = thread_sp.get(); 3764bb0738eSEd Maste 377ac7ddfbfSEd Maste Stream &strm = result.GetOutputStream(); 378ac7ddfbfSEd Maste 37924d58133SDimitry Andric // Only dump stack info if we processing unique stacks. 38024d58133SDimitry Andric const bool only_stacks = m_unique_stacks; 38124d58133SDimitry Andric 382ac7ddfbfSEd Maste // Don't show source context when doing backtraces. 383ac7ddfbfSEd Maste const uint32_t num_frames_with_source = 0; 384435933ddSDimitry Andric const bool stop_format = true; 385435933ddSDimitry Andric if (!thread->GetStatus(strm, m_options.m_start, m_options.m_count, 38624d58133SDimitry Andric num_frames_with_source, stop_format, only_stacks)) { 387435933ddSDimitry Andric result.AppendErrorWithFormat( 388435933ddSDimitry Andric "error displaying backtrace for thread: \"0x%4.4x\"\n", 389435933ddSDimitry Andric thread->GetIndexID()); 390ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 391ac7ddfbfSEd Maste return false; 392ac7ddfbfSEd Maste } 393435933ddSDimitry Andric if (m_options.m_extended_backtrace) { 3944bb0738eSEd Maste DoExtendedBacktrace(thread, result); 395b952cd58SEd Maste } 396ac7ddfbfSEd Maste 3977aa51b79SEd Maste return true; 398ac7ddfbfSEd Maste } 399ac7ddfbfSEd Maste 400ac7ddfbfSEd Maste CommandOptions m_options; 401ac7ddfbfSEd Maste }; 402ac7ddfbfSEd Maste 403435933ddSDimitry Andric enum StepScope { eStepScopeSource, eStepScopeInstruction }; 404435933ddSDimitry Andric 405435933ddSDimitry Andric static OptionEnumValueElement g_tri_running_mode[] = { 406435933ddSDimitry Andric {eOnlyThisThread, "this-thread", "Run only this thread"}, 407435933ddSDimitry Andric {eAllThreads, "all-threads", "Run all threads"}, 408435933ddSDimitry Andric {eOnlyDuringStepping, "while-stepping", 409435933ddSDimitry Andric "Run only this thread while stepping"}, 410435933ddSDimitry Andric {0, nullptr, nullptr}}; 411435933ddSDimitry Andric 412435933ddSDimitry Andric static OptionEnumValueElement g_duo_running_mode[] = { 413435933ddSDimitry Andric {eOnlyThisThread, "this-thread", "Run only this thread"}, 414435933ddSDimitry Andric {eAllThreads, "all-threads", "Run all threads"}, 415435933ddSDimitry Andric {0, nullptr, nullptr}}; 416435933ddSDimitry Andric 417435933ddSDimitry Andric static OptionDefinition g_thread_step_scope_options[] = { 418435933ddSDimitry Andric // clang-format off 419435933ddSDimitry 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." }, 420435933ddSDimitry 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." }, 421435933ddSDimitry 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." }, 422435933ddSDimitry 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." }, 423435933ddSDimitry 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." }, 424435933ddSDimitry 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." }, 425435933ddSDimitry 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." }, 426435933ddSDimitry 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." } 427435933ddSDimitry Andric // clang-format on 428ac7ddfbfSEd Maste }; 429ac7ddfbfSEd Maste 430435933ddSDimitry Andric class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed { 431ac7ddfbfSEd Maste public: 432435933ddSDimitry Andric class CommandOptions : public Options { 433ac7ddfbfSEd Maste public: 434435933ddSDimitry Andric CommandOptions() : Options() { 435435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 436435933ddSDimitry Andric // () 437435933ddSDimitry Andric OptionParsingStarting(nullptr); 438ac7ddfbfSEd Maste } 439ac7ddfbfSEd Maste 4404bb0738eSEd Maste ~CommandOptions() override = default; 441ac7ddfbfSEd Maste 4425517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 443435933ddSDimitry Andric ExecutionContext *execution_context) override { 4445517e702SDimitry Andric Status error; 445ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 446ac7ddfbfSEd Maste 447435933ddSDimitry Andric switch (short_option) { 448435933ddSDimitry Andric case 'a': { 449ac7ddfbfSEd Maste bool success; 4500127ef0fSEd Maste bool avoid_no_debug = Args::StringToBoolean(option_arg, true, &success); 451ac7ddfbfSEd Maste if (!success) 452435933ddSDimitry Andric error.SetErrorStringWithFormat( 453435933ddSDimitry Andric "invalid boolean value for option '%c'", short_option); 454435933ddSDimitry Andric else { 455435933ddSDimitry Andric m_step_in_avoid_no_debug = 456435933ddSDimitry Andric avoid_no_debug ? eLazyBoolYes : eLazyBoolNo; 4570127ef0fSEd Maste } 458435933ddSDimitry Andric } break; 459ac7ddfbfSEd Maste 460435933ddSDimitry Andric case 'A': { 4610127ef0fSEd Maste bool success; 4620127ef0fSEd Maste bool avoid_no_debug = Args::StringToBoolean(option_arg, true, &success); 4630127ef0fSEd Maste if (!success) 464435933ddSDimitry Andric error.SetErrorStringWithFormat( 465435933ddSDimitry Andric "invalid boolean value for option '%c'", short_option); 466435933ddSDimitry Andric else { 467435933ddSDimitry Andric m_step_out_avoid_no_debug = 468435933ddSDimitry Andric avoid_no_debug ? eLazyBoolYes : eLazyBoolNo; 4690127ef0fSEd Maste } 470435933ddSDimitry Andric } break; 4710127ef0fSEd Maste 4720127ef0fSEd Maste case 'c': 473435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_step_count)) 474435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid step count '%s'", 475435933ddSDimitry Andric option_arg.str().c_str()); 4760127ef0fSEd Maste break; 4774bb0738eSEd Maste 4787aa51b79SEd Maste case 'C': 4797aa51b79SEd Maste m_class_name.clear(); 4807aa51b79SEd Maste m_class_name.assign(option_arg); 4817aa51b79SEd Maste break; 4824bb0738eSEd Maste 483435933ddSDimitry Andric case 'm': { 484435933ddSDimitry Andric OptionEnumValueElement *enum_values = 485435933ddSDimitry Andric GetDefinitions()[option_idx].enum_values; 486435933ddSDimitry Andric m_run_mode = (lldb::RunMode)Args::StringToOptionEnum( 487435933ddSDimitry Andric option_arg, enum_values, eOnlyDuringStepping, error); 488435933ddSDimitry Andric } break; 489ac7ddfbfSEd Maste 4904bb0738eSEd Maste case 'e': 491435933ddSDimitry Andric if (option_arg == "block") { 4924bb0738eSEd Maste m_end_line_is_block_end = 1; 4934bb0738eSEd Maste break; 4944bb0738eSEd Maste } 495435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_end_line)) 496435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid end line number '%s'", 497435933ddSDimitry Andric option_arg.str().c_str()); 4984bb0738eSEd Maste break; 4994bb0738eSEd Maste 5004bb0738eSEd Maste case 'r': 501ac7ddfbfSEd Maste m_avoid_regexp.clear(); 502ac7ddfbfSEd Maste m_avoid_regexp.assign(option_arg); 503ac7ddfbfSEd Maste break; 504ac7ddfbfSEd Maste 505ac7ddfbfSEd Maste case 't': 506ac7ddfbfSEd Maste m_step_in_target.clear(); 507ac7ddfbfSEd Maste m_step_in_target.assign(option_arg); 508ac7ddfbfSEd Maste break; 5094bb0738eSEd Maste 510ac7ddfbfSEd Maste default: 511435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 512435933ddSDimitry Andric short_option); 513ac7ddfbfSEd Maste break; 514ac7ddfbfSEd Maste } 515ac7ddfbfSEd Maste return error; 516ac7ddfbfSEd Maste } 517ac7ddfbfSEd Maste 518435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 5190127ef0fSEd Maste m_step_in_avoid_no_debug = eLazyBoolCalculate; 5200127ef0fSEd Maste m_step_out_avoid_no_debug = eLazyBoolCalculate; 521ac7ddfbfSEd Maste m_run_mode = eOnlyDuringStepping; 5221c3bbb01SEd Maste 5231c3bbb01SEd Maste // Check if we are in Non-Stop mode 524435933ddSDimitry Andric TargetSP target_sp = 525435933ddSDimitry Andric execution_context ? execution_context->GetTargetSP() : TargetSP(); 5264bb0738eSEd Maste if (target_sp && target_sp->GetNonStopModeEnabled()) 5271c3bbb01SEd Maste m_run_mode = eOnlyThisThread; 5281c3bbb01SEd Maste 529ac7ddfbfSEd Maste m_avoid_regexp.clear(); 530ac7ddfbfSEd Maste m_step_in_target.clear(); 5317aa51b79SEd Maste m_class_name.clear(); 5320127ef0fSEd Maste m_step_count = 1; 5334bb0738eSEd Maste m_end_line = LLDB_INVALID_LINE_NUMBER; 5344bb0738eSEd Maste m_end_line_is_block_end = false; 535ac7ddfbfSEd Maste } 536ac7ddfbfSEd Maste 537435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 538435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_step_scope_options); 539ac7ddfbfSEd Maste } 540ac7ddfbfSEd Maste 541ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 5420127ef0fSEd Maste LazyBool m_step_in_avoid_no_debug; 5430127ef0fSEd Maste LazyBool m_step_out_avoid_no_debug; 544ac7ddfbfSEd Maste RunMode m_run_mode; 545ac7ddfbfSEd Maste std::string m_avoid_regexp; 546ac7ddfbfSEd Maste std::string m_step_in_target; 5477aa51b79SEd Maste std::string m_class_name; 5487aa51b79SEd Maste uint32_t m_step_count; 5494bb0738eSEd Maste uint32_t m_end_line; 5504bb0738eSEd Maste bool m_end_line_is_block_end; 551ac7ddfbfSEd Maste }; 552ac7ddfbfSEd Maste 553ac7ddfbfSEd Maste CommandObjectThreadStepWithTypeAndScope(CommandInterpreter &interpreter, 554435933ddSDimitry Andric const char *name, const char *help, 555ac7ddfbfSEd Maste const char *syntax, 556ac7ddfbfSEd Maste StepType step_type, 557435933ddSDimitry Andric StepScope step_scope) 558435933ddSDimitry Andric : CommandObjectParsed(interpreter, name, help, syntax, 559435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 5601c3bbb01SEd Maste eCommandTryTargetAPILock | 5611c3bbb01SEd Maste eCommandProcessMustBeLaunched | 5621c3bbb01SEd Maste eCommandProcessMustBePaused), 563435933ddSDimitry Andric m_step_type(step_type), m_step_scope(step_scope), m_options() { 564ac7ddfbfSEd Maste CommandArgumentEntry arg; 565ac7ddfbfSEd Maste CommandArgumentData thread_id_arg; 566ac7ddfbfSEd Maste 567ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 568ac7ddfbfSEd Maste thread_id_arg.arg_type = eArgTypeThreadID; 569ac7ddfbfSEd Maste thread_id_arg.arg_repetition = eArgRepeatOptional; 570ac7ddfbfSEd Maste 571435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 572435933ddSDimitry Andric // argument entry. 573ac7ddfbfSEd Maste arg.push_back(thread_id_arg); 574ac7ddfbfSEd Maste 575ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 576ac7ddfbfSEd Maste m_arguments.push_back(arg); 577ac7ddfbfSEd Maste } 578ac7ddfbfSEd Maste 5794bb0738eSEd Maste ~CommandObjectThreadStepWithTypeAndScope() override = default; 580ac7ddfbfSEd Maste 581435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 582ac7ddfbfSEd Maste 583ac7ddfbfSEd Maste protected: 584435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 585ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 586ac7ddfbfSEd Maste bool synchronous_execution = m_interpreter.GetSynchronous(); 587ac7ddfbfSEd Maste 588ac7ddfbfSEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 5894bb0738eSEd Maste Thread *thread = nullptr; 590ac7ddfbfSEd Maste 591435933ddSDimitry Andric if (command.GetArgumentCount() == 0) { 5924bb0738eSEd Maste thread = GetDefaultThread(); 5934bb0738eSEd Maste 594435933ddSDimitry Andric if (thread == nullptr) { 595ac7ddfbfSEd Maste result.AppendError("no selected thread in process"); 596ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 597ac7ddfbfSEd Maste return false; 598ac7ddfbfSEd Maste } 599435933ddSDimitry Andric } else { 600ac7ddfbfSEd Maste const char *thread_idx_cstr = command.GetArgumentAtIndex(0); 601435933ddSDimitry Andric uint32_t step_thread_idx = 602435933ddSDimitry Andric StringConvert::ToUInt32(thread_idx_cstr, LLDB_INVALID_INDEX32); 603435933ddSDimitry Andric if (step_thread_idx == LLDB_INVALID_INDEX32) { 604435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread index '%s'.\n", 605435933ddSDimitry Andric thread_idx_cstr); 606ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 607ac7ddfbfSEd Maste return false; 608ac7ddfbfSEd Maste } 609435933ddSDimitry Andric thread = 610435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(step_thread_idx).get(); 611435933ddSDimitry Andric if (thread == nullptr) { 612435933ddSDimitry Andric result.AppendErrorWithFormat( 613435933ddSDimitry Andric "Thread index %u is out of range (valid values are 0 - %u).\n", 614ac7ddfbfSEd Maste step_thread_idx, num_threads); 615ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 616ac7ddfbfSEd Maste return false; 617ac7ddfbfSEd Maste } 618ac7ddfbfSEd Maste } 619ac7ddfbfSEd Maste 620435933ddSDimitry Andric if (m_step_type == eStepTypeScripted) { 621435933ddSDimitry Andric if (m_options.m_class_name.empty()) { 6227aa51b79SEd Maste result.AppendErrorWithFormat("empty class name for scripted step."); 6237aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 6247aa51b79SEd Maste return false; 625435933ddSDimitry Andric } else if (!m_interpreter.GetScriptInterpreter()->CheckObjectExists( 626435933ddSDimitry Andric m_options.m_class_name.c_str())) { 627435933ddSDimitry Andric result.AppendErrorWithFormat( 628435933ddSDimitry Andric "class for scripted step: \"%s\" does not exist.", 629435933ddSDimitry Andric m_options.m_class_name.c_str()); 6307aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 6317aa51b79SEd Maste return false; 6327aa51b79SEd Maste } 6337aa51b79SEd Maste } 6347aa51b79SEd Maste 635435933ddSDimitry Andric if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER && 636435933ddSDimitry Andric m_step_type != eStepTypeInto) { 637435933ddSDimitry Andric result.AppendErrorWithFormat( 638435933ddSDimitry Andric "end line option is only valid for step into"); 6394bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 6404bb0738eSEd Maste return false; 6414bb0738eSEd Maste } 6424bb0738eSEd Maste 643ac7ddfbfSEd Maste const bool abort_other_plans = false; 644ac7ddfbfSEd Maste const lldb::RunMode stop_other_threads = m_options.m_run_mode; 645ac7ddfbfSEd Maste 646435933ddSDimitry Andric // This is a bit unfortunate, but not all the commands in this command 647435933ddSDimitry Andric // object support 648ac7ddfbfSEd Maste // only while stepping, so I use the bool for them. 649ac7ddfbfSEd Maste bool bool_stop_other_threads; 650ac7ddfbfSEd Maste if (m_options.m_run_mode == eAllThreads) 651ac7ddfbfSEd Maste bool_stop_other_threads = false; 652ac7ddfbfSEd Maste else if (m_options.m_run_mode == eOnlyDuringStepping) 653435933ddSDimitry Andric bool_stop_other_threads = 654435933ddSDimitry Andric (m_step_type != eStepTypeOut && m_step_type != eStepTypeScripted); 655ac7ddfbfSEd Maste else 656ac7ddfbfSEd Maste bool_stop_other_threads = true; 657ac7ddfbfSEd Maste 658ac7ddfbfSEd Maste ThreadPlanSP new_plan_sp; 659ac7ddfbfSEd Maste 660435933ddSDimitry Andric if (m_step_type == eStepTypeInto) { 661ac7ddfbfSEd Maste StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); 6621c3bbb01SEd Maste assert(frame != nullptr); 663ac7ddfbfSEd Maste 664435933ddSDimitry Andric if (frame->HasDebugInformation()) { 6654bb0738eSEd Maste AddressRange range; 6664bb0738eSEd Maste SymbolContext sc = frame->GetSymbolContext(eSymbolContextEverything); 667435933ddSDimitry Andric if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER) { 6685517e702SDimitry Andric Status error; 669435933ddSDimitry Andric if (!sc.GetAddressRangeFromHereToEndLine(m_options.m_end_line, range, 670435933ddSDimitry Andric error)) { 671435933ddSDimitry Andric result.AppendErrorWithFormat("invalid end-line option: %s.", 672435933ddSDimitry Andric error.AsCString()); 6734bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 6744bb0738eSEd Maste return false; 6754bb0738eSEd Maste } 676435933ddSDimitry Andric } else if (m_options.m_end_line_is_block_end) { 6775517e702SDimitry Andric Status error; 6784bb0738eSEd Maste Block *block = frame->GetSymbolContext(eSymbolContextBlock).block; 679435933ddSDimitry Andric if (!block) { 6804bb0738eSEd Maste result.AppendErrorWithFormat("Could not find the current block."); 6814bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 6824bb0738eSEd Maste return false; 6834bb0738eSEd Maste } 6844bb0738eSEd Maste 6854bb0738eSEd Maste AddressRange block_range; 6864bb0738eSEd Maste Address pc_address = frame->GetFrameCodeAddress(); 6874bb0738eSEd Maste block->GetRangeContainingAddress(pc_address, block_range); 688435933ddSDimitry Andric if (!block_range.GetBaseAddress().IsValid()) { 689435933ddSDimitry Andric result.AppendErrorWithFormat( 690435933ddSDimitry Andric "Could not find the current block address."); 6914bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 6924bb0738eSEd Maste return false; 6934bb0738eSEd Maste } 694435933ddSDimitry Andric lldb::addr_t pc_offset_in_block = 695435933ddSDimitry Andric pc_address.GetFileAddress() - 696435933ddSDimitry Andric block_range.GetBaseAddress().GetFileAddress(); 697435933ddSDimitry Andric lldb::addr_t range_length = 698435933ddSDimitry Andric block_range.GetByteSize() - pc_offset_in_block; 6994bb0738eSEd Maste range = AddressRange(pc_address, range_length); 700435933ddSDimitry Andric } else { 7014bb0738eSEd Maste range = sc.line_entry.range; 7024bb0738eSEd Maste } 7034bb0738eSEd Maste 704435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepInRange( 705435933ddSDimitry Andric abort_other_plans, range, 706ac7ddfbfSEd Maste frame->GetSymbolContext(eSymbolContextEverything), 707435933ddSDimitry Andric m_options.m_step_in_target.c_str(), stop_other_threads, 7080127ef0fSEd Maste m_options.m_step_in_avoid_no_debug, 7090127ef0fSEd Maste m_options.m_step_out_avoid_no_debug); 7100127ef0fSEd Maste 711435933ddSDimitry Andric if (new_plan_sp && !m_options.m_avoid_regexp.empty()) { 712435933ddSDimitry Andric ThreadPlanStepInRange *step_in_range_plan = 713435933ddSDimitry Andric static_cast<ThreadPlanStepInRange *>(new_plan_sp.get()); 714ac7ddfbfSEd Maste step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str()); 715ac7ddfbfSEd Maste } 716435933ddSDimitry Andric } else 717435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 718435933ddSDimitry Andric false, abort_other_plans, bool_stop_other_threads); 719435933ddSDimitry Andric } else if (m_step_type == eStepTypeOver) { 720ac7ddfbfSEd Maste StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); 721ac7ddfbfSEd Maste 722ac7ddfbfSEd Maste if (frame->HasDebugInformation()) 723435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepOverRange( 724435933ddSDimitry Andric abort_other_plans, 7259f2f44ceSEd Maste frame->GetSymbolContext(eSymbolContextEverything).line_entry, 726ac7ddfbfSEd Maste frame->GetSymbolContext(eSymbolContextEverything), 727435933ddSDimitry Andric stop_other_threads, m_options.m_step_out_avoid_no_debug); 728ac7ddfbfSEd Maste else 729435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 730435933ddSDimitry Andric true, abort_other_plans, bool_stop_other_threads); 731435933ddSDimitry Andric } else if (m_step_type == eStepTypeTrace) { 732435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 733435933ddSDimitry Andric false, abort_other_plans, bool_stop_other_threads); 734435933ddSDimitry Andric } else if (m_step_type == eStepTypeTraceOver) { 735435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction( 736435933ddSDimitry Andric true, abort_other_plans, bool_stop_other_threads); 737435933ddSDimitry Andric } else if (m_step_type == eStepTypeOut) { 738435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepOut( 739435933ddSDimitry Andric abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes, 740435933ddSDimitry Andric eVoteNoOpinion, thread->GetSelectedFrameIndex(), 7410127ef0fSEd Maste m_options.m_step_out_avoid_no_debug); 742435933ddSDimitry Andric } else if (m_step_type == eStepTypeScripted) { 743435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepScripted( 744435933ddSDimitry Andric abort_other_plans, m_options.m_class_name.c_str(), 7457aa51b79SEd Maste bool_stop_other_threads); 746435933ddSDimitry Andric } else { 747ac7ddfbfSEd Maste result.AppendError("step type is not supported"); 748ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 749ac7ddfbfSEd Maste return false; 750ac7ddfbfSEd Maste } 751ac7ddfbfSEd Maste 752435933ddSDimitry Andric // If we got a new plan, then set it to be a master plan (User level Plans 753435933ddSDimitry Andric // should be master plans 754ac7ddfbfSEd Maste // so that they can be interruptible). Then resume the process. 755ac7ddfbfSEd Maste 756435933ddSDimitry Andric if (new_plan_sp) { 757ac7ddfbfSEd Maste new_plan_sp->SetIsMasterPlan(true); 758ac7ddfbfSEd Maste new_plan_sp->SetOkayToDiscard(false); 759ac7ddfbfSEd Maste 760435933ddSDimitry Andric if (m_options.m_step_count > 1) { 761302affcbSDimitry Andric if (!new_plan_sp->SetIterationCount(m_options.m_step_count)) { 762435933ddSDimitry Andric result.AppendWarning( 763435933ddSDimitry Andric "step operation does not support iteration count."); 7640127ef0fSEd Maste } 7650127ef0fSEd Maste } 7660127ef0fSEd Maste 767ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(thread->GetID()); 7687aa51b79SEd Maste 7691c3bbb01SEd Maste const uint32_t iohandler_id = process->GetIOHandlerID(); 7701c3bbb01SEd Maste 7717aa51b79SEd Maste StreamString stream; 7725517e702SDimitry Andric Status error; 7737aa51b79SEd Maste if (synchronous_execution) 7747aa51b79SEd Maste error = process->ResumeSynchronous(&stream); 7757aa51b79SEd Maste else 7767aa51b79SEd Maste error = process->Resume(); 777ac7ddfbfSEd Maste 778acac075bSDimitry Andric if (!error.Success()) { 779acac075bSDimitry Andric result.AppendMessage(error.AsCString()); 780acac075bSDimitry Andric result.SetStatus(eReturnStatusFailed); 781acac075bSDimitry Andric return false; 782acac075bSDimitry Andric } 783acac075bSDimitry Andric 784435933ddSDimitry Andric // There is a race condition where this thread will return up the call 785435933ddSDimitry Andric // stack to the main command handler 786435933ddSDimitry Andric // and show an (lldb) prompt before HandlePrivateEvent (from 787435933ddSDimitry Andric // PrivateStateThread) has 7880127ef0fSEd Maste // a chance to call PushProcessIOHandler(). 7891c3bbb01SEd Maste process->SyncIOHandler(iohandler_id, 2000); 790ac7ddfbfSEd Maste 791435933ddSDimitry Andric if (synchronous_execution) { 792435933ddSDimitry Andric // If any state changed events had anything to say, add that to the 793435933ddSDimitry Andric // result 794435933ddSDimitry Andric if (stream.GetSize() > 0) 795435933ddSDimitry Andric result.AppendMessage(stream.GetString()); 796ac7ddfbfSEd Maste 797ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(thread->GetID()); 798ac7ddfbfSEd Maste result.SetDidChangeProcessState(true); 799ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 800435933ddSDimitry Andric } else { 801ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessContinuingNoResult); 802ac7ddfbfSEd Maste } 803435933ddSDimitry Andric } else { 804ac7ddfbfSEd Maste result.AppendError("Couldn't find thread plan to implement step type."); 805ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 806ac7ddfbfSEd Maste } 807ac7ddfbfSEd Maste return result.Succeeded(); 808ac7ddfbfSEd Maste } 809ac7ddfbfSEd Maste 810ac7ddfbfSEd Maste protected: 811ac7ddfbfSEd Maste StepType m_step_type; 812ac7ddfbfSEd Maste StepScope m_step_scope; 813ac7ddfbfSEd Maste CommandOptions m_options; 814ac7ddfbfSEd Maste }; 815ac7ddfbfSEd Maste 816ac7ddfbfSEd Maste //------------------------------------------------------------------------- 817ac7ddfbfSEd Maste // CommandObjectThreadContinue 818ac7ddfbfSEd Maste //------------------------------------------------------------------------- 819ac7ddfbfSEd Maste 820435933ddSDimitry Andric class CommandObjectThreadContinue : public CommandObjectParsed { 821ac7ddfbfSEd Maste public: 8224bb0738eSEd Maste CommandObjectThreadContinue(CommandInterpreter &interpreter) 823435933ddSDimitry Andric : CommandObjectParsed( 824435933ddSDimitry Andric interpreter, "thread continue", 825435933ddSDimitry Andric "Continue execution of the current target process. One " 8264bb0738eSEd Maste "or more threads may be specified, by default all " 8274bb0738eSEd Maste "threads continue.", 828435933ddSDimitry Andric nullptr, 829435933ddSDimitry Andric eCommandRequiresThread | eCommandTryTargetAPILock | 830435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { 831ac7ddfbfSEd Maste CommandArgumentEntry arg; 832ac7ddfbfSEd Maste CommandArgumentData thread_idx_arg; 833ac7ddfbfSEd Maste 834ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 835ac7ddfbfSEd Maste thread_idx_arg.arg_type = eArgTypeThreadIndex; 836ac7ddfbfSEd Maste thread_idx_arg.arg_repetition = eArgRepeatPlus; 837ac7ddfbfSEd Maste 838435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 839435933ddSDimitry Andric // argument entry. 840ac7ddfbfSEd Maste arg.push_back(thread_idx_arg); 841ac7ddfbfSEd Maste 842ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 843ac7ddfbfSEd Maste m_arguments.push_back(arg); 844ac7ddfbfSEd Maste } 845ac7ddfbfSEd Maste 8464bb0738eSEd Maste ~CommandObjectThreadContinue() override = default; 847ac7ddfbfSEd Maste 848435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 849ac7ddfbfSEd Maste bool synchronous_execution = m_interpreter.GetSynchronous(); 850ac7ddfbfSEd Maste 851435933ddSDimitry Andric if (!m_interpreter.GetDebugger().GetSelectedTarget()) { 852435933ddSDimitry Andric result.AppendError("invalid target, create a debug target using the " 853435933ddSDimitry Andric "'target create' command"); 854ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 855ac7ddfbfSEd Maste return false; 856ac7ddfbfSEd Maste } 857ac7ddfbfSEd Maste 858ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 859435933ddSDimitry Andric if (process == nullptr) { 860ac7ddfbfSEd Maste result.AppendError("no process exists. Cannot continue"); 861ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 862ac7ddfbfSEd Maste return false; 863ac7ddfbfSEd Maste } 864ac7ddfbfSEd Maste 865ac7ddfbfSEd Maste StateType state = process->GetState(); 866435933ddSDimitry Andric if ((state == eStateCrashed) || (state == eStateStopped) || 867435933ddSDimitry Andric (state == eStateSuspended)) { 868ac7ddfbfSEd Maste const size_t argc = command.GetArgumentCount(); 869435933ddSDimitry Andric if (argc > 0) { 87035617911SEd Maste // These two lines appear at the beginning of both blocks in 87135617911SEd Maste // this if..else, but that is because we need to release the 87235617911SEd Maste // lock before calling process->Resume below. 873435933ddSDimitry Andric std::lock_guard<std::recursive_mutex> guard( 874435933ddSDimitry Andric process->GetThreadList().GetMutex()); 87535617911SEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 876ac7ddfbfSEd Maste std::vector<Thread *> resume_threads; 877435933ddSDimitry Andric for (auto &entry : command.entries()) { 878435933ddSDimitry Andric uint32_t thread_idx; 879435933ddSDimitry Andric if (entry.ref.getAsInteger(0, thread_idx)) { 880435933ddSDimitry Andric result.AppendErrorWithFormat( 881435933ddSDimitry Andric "invalid thread index argument: \"%s\".\n", entry.c_str()); 882435933ddSDimitry Andric result.SetStatus(eReturnStatusFailed); 883435933ddSDimitry Andric return false; 884435933ddSDimitry Andric } 885435933ddSDimitry Andric Thread *thread = 886435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(thread_idx).get(); 887ac7ddfbfSEd Maste 888435933ddSDimitry Andric if (thread) { 889ac7ddfbfSEd Maste resume_threads.push_back(thread); 890435933ddSDimitry Andric } else { 891435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread index %u.\n", 892435933ddSDimitry Andric thread_idx); 893ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 894ac7ddfbfSEd Maste return false; 895ac7ddfbfSEd Maste } 896ac7ddfbfSEd Maste } 897ac7ddfbfSEd Maste 898435933ddSDimitry Andric if (resume_threads.empty()) { 899ac7ddfbfSEd Maste result.AppendError("no valid thread indexes were specified"); 900ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 901ac7ddfbfSEd Maste return false; 902435933ddSDimitry Andric } else { 903ac7ddfbfSEd Maste if (resume_threads.size() == 1) 904ac7ddfbfSEd Maste result.AppendMessageWithFormat("Resuming thread: "); 905ac7ddfbfSEd Maste else 906ac7ddfbfSEd Maste result.AppendMessageWithFormat("Resuming threads: "); 907ac7ddfbfSEd Maste 908435933ddSDimitry Andric for (uint32_t idx = 0; idx < num_threads; ++idx) { 909435933ddSDimitry Andric Thread *thread = 910435933ddSDimitry Andric process->GetThreadList().GetThreadAtIndex(idx).get(); 911435933ddSDimitry Andric std::vector<Thread *>::iterator this_thread_pos = 912435933ddSDimitry Andric find(resume_threads.begin(), resume_threads.end(), thread); 913ac7ddfbfSEd Maste 914435933ddSDimitry Andric if (this_thread_pos != resume_threads.end()) { 915ac7ddfbfSEd Maste resume_threads.erase(this_thread_pos); 9164bb0738eSEd Maste if (!resume_threads.empty()) 917ac7ddfbfSEd Maste result.AppendMessageWithFormat("%u, ", thread->GetIndexID()); 918ac7ddfbfSEd Maste else 919ac7ddfbfSEd Maste result.AppendMessageWithFormat("%u ", thread->GetIndexID()); 920ac7ddfbfSEd Maste 9210127ef0fSEd Maste const bool override_suspend = true; 9220127ef0fSEd Maste thread->SetResumeState(eStateRunning, override_suspend); 923435933ddSDimitry Andric } else { 924ac7ddfbfSEd Maste thread->SetResumeState(eStateSuspended); 925ac7ddfbfSEd Maste } 926ac7ddfbfSEd Maste } 927435933ddSDimitry Andric result.AppendMessageWithFormat("in process %" PRIu64 "\n", 928435933ddSDimitry Andric process->GetID()); 929ac7ddfbfSEd Maste } 930435933ddSDimitry Andric } else { 93135617911SEd Maste // These two lines appear at the beginning of both blocks in 93235617911SEd Maste // this if..else, but that is because we need to release the 93335617911SEd Maste // lock before calling process->Resume below. 934435933ddSDimitry Andric std::lock_guard<std::recursive_mutex> guard( 935435933ddSDimitry Andric process->GetThreadList().GetMutex()); 93635617911SEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 9374bb0738eSEd Maste Thread *current_thread = GetDefaultThread(); 938435933ddSDimitry Andric if (current_thread == nullptr) { 939ac7ddfbfSEd Maste result.AppendError("the process doesn't have a current thread"); 940ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 941ac7ddfbfSEd Maste return false; 942ac7ddfbfSEd Maste } 943ac7ddfbfSEd Maste // Set the actions that the threads should each take when resuming 944435933ddSDimitry Andric for (uint32_t idx = 0; idx < num_threads; ++idx) { 945ac7ddfbfSEd Maste Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get(); 946435933ddSDimitry Andric if (thread == current_thread) { 947435933ddSDimitry Andric result.AppendMessageWithFormat("Resuming thread 0x%4.4" PRIx64 948435933ddSDimitry Andric " in process %" PRIu64 "\n", 949435933ddSDimitry Andric thread->GetID(), process->GetID()); 9500127ef0fSEd Maste const bool override_suspend = true; 9510127ef0fSEd Maste thread->SetResumeState(eStateRunning, override_suspend); 952435933ddSDimitry Andric } else { 953ac7ddfbfSEd Maste thread->SetResumeState(eStateSuspended); 954ac7ddfbfSEd Maste } 955ac7ddfbfSEd Maste } 956ac7ddfbfSEd Maste } 957ac7ddfbfSEd Maste 9587aa51b79SEd Maste StreamString stream; 9595517e702SDimitry Andric Status error; 9607aa51b79SEd Maste if (synchronous_execution) 9617aa51b79SEd Maste error = process->ResumeSynchronous(&stream); 9627aa51b79SEd Maste else 9637aa51b79SEd Maste error = process->Resume(); 9647aa51b79SEd Maste 96535617911SEd Maste // We should not be holding the thread list lock when we do this. 966435933ddSDimitry Andric if (error.Success()) { 967435933ddSDimitry Andric result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n", 968435933ddSDimitry Andric process->GetID()); 969435933ddSDimitry Andric if (synchronous_execution) { 970435933ddSDimitry Andric // If any state changed events had anything to say, add that to the 971435933ddSDimitry Andric // result 972435933ddSDimitry Andric if (stream.GetSize() > 0) 973435933ddSDimitry Andric result.AppendMessage(stream.GetString()); 974ac7ddfbfSEd Maste 975ac7ddfbfSEd Maste result.SetDidChangeProcessState(true); 976ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 977435933ddSDimitry Andric } else { 978ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessContinuingNoResult); 979ac7ddfbfSEd Maste } 980435933ddSDimitry Andric } else { 981435933ddSDimitry Andric result.AppendErrorWithFormat("Failed to resume process: %s\n", 982435933ddSDimitry Andric error.AsCString()); 983ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 984ac7ddfbfSEd Maste } 985435933ddSDimitry Andric } else { 986435933ddSDimitry Andric result.AppendErrorWithFormat( 987435933ddSDimitry Andric "Process cannot be continued from its current state (%s).\n", 988ac7ddfbfSEd Maste StateAsCString(state)); 989ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 990ac7ddfbfSEd Maste } 991ac7ddfbfSEd Maste 992ac7ddfbfSEd Maste return result.Succeeded(); 993ac7ddfbfSEd Maste } 994ac7ddfbfSEd Maste }; 995ac7ddfbfSEd Maste 996ac7ddfbfSEd Maste //------------------------------------------------------------------------- 997ac7ddfbfSEd Maste // CommandObjectThreadUntil 998ac7ddfbfSEd Maste //------------------------------------------------------------------------- 999ac7ddfbfSEd Maste 1000435933ddSDimitry Andric static OptionDefinition g_thread_until_options[] = { 1001435933ddSDimitry Andric // clang-format off 1002435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "frame", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFrameIndex, "Frame index for until operation - defaults to 0" }, 1003435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "thread", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadIndex, "Thread index for the thread for until operation" }, 1004435933ddSDimitry 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" }, 1005435933ddSDimitry 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." } 1006435933ddSDimitry Andric // clang-format on 1007435933ddSDimitry Andric }; 1008435933ddSDimitry Andric 1009435933ddSDimitry Andric class CommandObjectThreadUntil : public CommandObjectParsed { 1010ac7ddfbfSEd Maste public: 1011435933ddSDimitry Andric class CommandOptions : public Options { 1012ac7ddfbfSEd Maste public: 1013ac7ddfbfSEd Maste uint32_t m_thread_idx; 1014ac7ddfbfSEd Maste uint32_t m_frame_idx; 1015ac7ddfbfSEd Maste 1016435933ddSDimitry Andric CommandOptions() 1017435933ddSDimitry Andric : Options(), m_thread_idx(LLDB_INVALID_THREAD_ID), 1018435933ddSDimitry Andric m_frame_idx(LLDB_INVALID_FRAME_ID) { 1019435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 1020435933ddSDimitry Andric // () 1021435933ddSDimitry Andric OptionParsingStarting(nullptr); 1022ac7ddfbfSEd Maste } 1023ac7ddfbfSEd Maste 10244bb0738eSEd Maste ~CommandOptions() override = default; 1025ac7ddfbfSEd Maste 10265517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1027435933ddSDimitry Andric ExecutionContext *execution_context) override { 10285517e702SDimitry Andric Status error; 1029ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 1030ac7ddfbfSEd Maste 1031435933ddSDimitry Andric switch (short_option) { 1032435933ddSDimitry Andric case 'a': { 1033435933ddSDimitry Andric lldb::addr_t tmp_addr = Args::StringToAddress( 1034435933ddSDimitry Andric execution_context, option_arg, LLDB_INVALID_ADDRESS, &error); 10351c3bbb01SEd Maste if (error.Success()) 10361c3bbb01SEd Maste m_until_addrs.push_back(tmp_addr); 1037435933ddSDimitry Andric } break; 1038ac7ddfbfSEd Maste case 't': 1039435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_thread_idx)) { 1040435933ddSDimitry Andric m_thread_idx = LLDB_INVALID_INDEX32; 1041435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid thread index '%s'", 1042435933ddSDimitry Andric option_arg.str().c_str()); 1043ac7ddfbfSEd Maste } 1044ac7ddfbfSEd Maste break; 1045ac7ddfbfSEd Maste case 'f': 1046435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_frame_idx)) { 1047435933ddSDimitry Andric m_frame_idx = LLDB_INVALID_FRAME_ID; 1048435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid frame index '%s'", 1049435933ddSDimitry Andric option_arg.str().c_str()); 1050ac7ddfbfSEd Maste } 1051ac7ddfbfSEd Maste break; 1052435933ddSDimitry Andric case 'm': { 1053435933ddSDimitry Andric OptionEnumValueElement *enum_values = 1054435933ddSDimitry Andric GetDefinitions()[option_idx].enum_values; 1055435933ddSDimitry Andric lldb::RunMode run_mode = (lldb::RunMode)Args::StringToOptionEnum( 1056435933ddSDimitry Andric option_arg, enum_values, eOnlyDuringStepping, error); 1057ac7ddfbfSEd Maste 1058435933ddSDimitry Andric if (error.Success()) { 1059ac7ddfbfSEd Maste if (run_mode == eAllThreads) 1060ac7ddfbfSEd Maste m_stop_others = false; 1061ac7ddfbfSEd Maste else 1062ac7ddfbfSEd Maste m_stop_others = true; 1063ac7ddfbfSEd Maste } 1064435933ddSDimitry Andric } break; 1065ac7ddfbfSEd Maste default: 1066435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 1067435933ddSDimitry Andric short_option); 1068ac7ddfbfSEd Maste break; 1069ac7ddfbfSEd Maste } 1070ac7ddfbfSEd Maste return error; 1071ac7ddfbfSEd Maste } 1072ac7ddfbfSEd Maste 1073435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 1074ac7ddfbfSEd Maste m_thread_idx = LLDB_INVALID_THREAD_ID; 1075ac7ddfbfSEd Maste m_frame_idx = 0; 1076ac7ddfbfSEd Maste m_stop_others = false; 10771c3bbb01SEd Maste m_until_addrs.clear(); 1078ac7ddfbfSEd Maste } 1079ac7ddfbfSEd Maste 1080435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1081435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_until_options); 1082ac7ddfbfSEd Maste } 1083ac7ddfbfSEd Maste 1084ac7ddfbfSEd Maste uint32_t m_step_thread_idx; 1085ac7ddfbfSEd Maste bool m_stop_others; 10861c3bbb01SEd Maste std::vector<lldb::addr_t> m_until_addrs; 1087ac7ddfbfSEd Maste 1088ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 1089ac7ddfbfSEd Maste }; 1090ac7ddfbfSEd Maste 10914bb0738eSEd Maste CommandObjectThreadUntil(CommandInterpreter &interpreter) 1092435933ddSDimitry Andric : CommandObjectParsed( 1093435933ddSDimitry Andric interpreter, "thread until", 1094435933ddSDimitry Andric "Continue until a line number or address is reached by the " 10954bb0738eSEd Maste "current or specified thread. Stops when returning from " 1096435933ddSDimitry Andric "the current function as a safety measure. " 1097435933ddSDimitry Andric "The target line number(s) are given as arguments, and if more than one" 1098435933ddSDimitry Andric " is provided, stepping will stop when the first one is hit.", 1099435933ddSDimitry Andric nullptr, 1100435933ddSDimitry Andric eCommandRequiresThread | eCommandTryTargetAPILock | 11014bb0738eSEd Maste eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 1102435933ddSDimitry Andric m_options() { 1103ac7ddfbfSEd Maste CommandArgumentEntry arg; 1104ac7ddfbfSEd Maste CommandArgumentData line_num_arg; 1105ac7ddfbfSEd Maste 1106ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 1107ac7ddfbfSEd Maste line_num_arg.arg_type = eArgTypeLineNum; 1108ac7ddfbfSEd Maste line_num_arg.arg_repetition = eArgRepeatPlain; 1109ac7ddfbfSEd Maste 1110435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 1111435933ddSDimitry Andric // argument entry. 1112ac7ddfbfSEd Maste arg.push_back(line_num_arg); 1113ac7ddfbfSEd Maste 1114ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 1115ac7ddfbfSEd Maste m_arguments.push_back(arg); 1116ac7ddfbfSEd Maste } 1117ac7ddfbfSEd Maste 11184bb0738eSEd Maste ~CommandObjectThreadUntil() override = default; 1119ac7ddfbfSEd Maste 1120435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 1121ac7ddfbfSEd Maste 1122ac7ddfbfSEd Maste protected: 1123435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 1124ac7ddfbfSEd Maste bool synchronous_execution = m_interpreter.GetSynchronous(); 1125ac7ddfbfSEd Maste 1126ac7ddfbfSEd Maste Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 1127435933ddSDimitry Andric if (target == nullptr) { 1128435933ddSDimitry Andric result.AppendError("invalid target, create a debug target using the " 1129435933ddSDimitry Andric "'target create' command"); 1130ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1131ac7ddfbfSEd Maste return false; 1132ac7ddfbfSEd Maste } 1133ac7ddfbfSEd Maste 1134ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 1135435933ddSDimitry Andric if (process == nullptr) { 1136ac7ddfbfSEd Maste result.AppendError("need a valid process to step"); 1137ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1138435933ddSDimitry Andric } else { 11394bb0738eSEd Maste Thread *thread = nullptr; 11401c3bbb01SEd Maste std::vector<uint32_t> line_numbers; 1141ac7ddfbfSEd Maste 1142435933ddSDimitry Andric if (command.GetArgumentCount() >= 1) { 11431c3bbb01SEd Maste size_t num_args = command.GetArgumentCount(); 1144435933ddSDimitry Andric for (size_t i = 0; i < num_args; i++) { 11451c3bbb01SEd Maste uint32_t line_number; 1146435933ddSDimitry Andric line_number = StringConvert::ToUInt32(command.GetArgumentAtIndex(i), 1147435933ddSDimitry Andric UINT32_MAX); 1148435933ddSDimitry Andric if (line_number == UINT32_MAX) { 1149435933ddSDimitry Andric result.AppendErrorWithFormat("invalid line number: '%s'.\n", 1150435933ddSDimitry Andric command.GetArgumentAtIndex(i)); 1151ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1152ac7ddfbfSEd Maste return false; 1153435933ddSDimitry Andric } else 11541c3bbb01SEd Maste line_numbers.push_back(line_number); 11551c3bbb01SEd Maste } 1156435933ddSDimitry Andric } else if (m_options.m_until_addrs.empty()) { 1157435933ddSDimitry Andric result.AppendErrorWithFormat("No line number or address provided:\n%s", 1158435933ddSDimitry Andric GetSyntax().str().c_str()); 11591c3bbb01SEd Maste result.SetStatus(eReturnStatusFailed); 11601c3bbb01SEd Maste return false; 11611c3bbb01SEd Maste } 11621c3bbb01SEd Maste 1163435933ddSDimitry Andric if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) { 11644bb0738eSEd Maste thread = GetDefaultThread(); 1165435933ddSDimitry Andric } else { 1166435933ddSDimitry Andric thread = process->GetThreadList() 1167435933ddSDimitry Andric .FindThreadByIndexID(m_options.m_thread_idx) 1168435933ddSDimitry Andric .get(); 1169ac7ddfbfSEd Maste } 1170ac7ddfbfSEd Maste 1171435933ddSDimitry Andric if (thread == nullptr) { 1172ac7ddfbfSEd Maste const uint32_t num_threads = process->GetThreadList().GetSize(); 1173435933ddSDimitry Andric result.AppendErrorWithFormat( 1174435933ddSDimitry Andric "Thread index %u is out of range (valid values are 0 - %u).\n", 1175435933ddSDimitry Andric m_options.m_thread_idx, num_threads); 1176ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1177ac7ddfbfSEd Maste return false; 1178ac7ddfbfSEd Maste } 1179ac7ddfbfSEd Maste 1180ac7ddfbfSEd Maste const bool abort_other_plans = false; 1181ac7ddfbfSEd Maste 1182435933ddSDimitry Andric StackFrame *frame = 1183435933ddSDimitry Andric thread->GetStackFrameAtIndex(m_options.m_frame_idx).get(); 1184435933ddSDimitry Andric if (frame == nullptr) { 1185435933ddSDimitry Andric result.AppendErrorWithFormat( 1186435933ddSDimitry Andric "Frame index %u is out of range for thread %u.\n", 1187435933ddSDimitry Andric m_options.m_frame_idx, m_options.m_thread_idx); 1188ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1189ac7ddfbfSEd Maste return false; 1190ac7ddfbfSEd Maste } 1191ac7ddfbfSEd Maste 1192ac7ddfbfSEd Maste ThreadPlanSP new_plan_sp; 1193ac7ddfbfSEd Maste 1194435933ddSDimitry Andric if (frame->HasDebugInformation()) { 1195435933ddSDimitry Andric // Finally we got here... Translate the given line number to a bunch of 1196435933ddSDimitry Andric // addresses: 1197ac7ddfbfSEd Maste SymbolContext sc(frame->GetSymbolContext(eSymbolContextCompUnit)); 11984bb0738eSEd Maste LineTable *line_table = nullptr; 1199ac7ddfbfSEd Maste if (sc.comp_unit) 1200ac7ddfbfSEd Maste line_table = sc.comp_unit->GetLineTable(); 1201ac7ddfbfSEd Maste 1202435933ddSDimitry Andric if (line_table == nullptr) { 1203435933ddSDimitry Andric result.AppendErrorWithFormat("Failed to resolve the line table for " 1204435933ddSDimitry Andric "frame %u of thread index %u.\n", 1205435933ddSDimitry Andric m_options.m_frame_idx, 1206435933ddSDimitry Andric m_options.m_thread_idx); 1207ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1208ac7ddfbfSEd Maste return false; 1209ac7ddfbfSEd Maste } 1210ac7ddfbfSEd Maste 1211ac7ddfbfSEd Maste LineEntry function_start; 1212ac7ddfbfSEd Maste uint32_t index_ptr = 0, end_ptr; 1213ac7ddfbfSEd Maste std::vector<addr_t> address_list; 1214ac7ddfbfSEd Maste 1215ac7ddfbfSEd Maste // Find the beginning & end index of the 1216ac7ddfbfSEd Maste AddressRange fun_addr_range = sc.function->GetAddressRange(); 1217ac7ddfbfSEd Maste Address fun_start_addr = fun_addr_range.GetBaseAddress(); 1218435933ddSDimitry Andric line_table->FindLineEntryByAddress(fun_start_addr, function_start, 1219435933ddSDimitry Andric &index_ptr); 1220ac7ddfbfSEd Maste 1221ac7ddfbfSEd Maste Address fun_end_addr(fun_start_addr.GetSection(), 1222435933ddSDimitry Andric fun_start_addr.GetOffset() + 1223435933ddSDimitry Andric fun_addr_range.GetByteSize()); 1224ac7ddfbfSEd Maste 1225ac7ddfbfSEd Maste bool all_in_function = true; 1226ac7ddfbfSEd Maste 1227435933ddSDimitry Andric line_table->FindLineEntryByAddress(fun_end_addr, function_start, 1228435933ddSDimitry Andric &end_ptr); 12291c3bbb01SEd Maste 1230435933ddSDimitry Andric for (uint32_t line_number : line_numbers) { 12311c3bbb01SEd Maste uint32_t start_idx_ptr = index_ptr; 1232435933ddSDimitry Andric while (start_idx_ptr <= end_ptr) { 1233ac7ddfbfSEd Maste LineEntry line_entry; 1234ac7ddfbfSEd Maste const bool exact = false; 1235435933ddSDimitry Andric start_idx_ptr = sc.comp_unit->FindLineEntry( 1236435933ddSDimitry Andric start_idx_ptr, line_number, sc.comp_unit, exact, &line_entry); 12371c3bbb01SEd Maste if (start_idx_ptr == UINT32_MAX) 1238ac7ddfbfSEd Maste break; 1239ac7ddfbfSEd Maste 1240435933ddSDimitry Andric addr_t address = 1241435933ddSDimitry Andric line_entry.range.GetBaseAddress().GetLoadAddress(target); 1242435933ddSDimitry Andric if (address != LLDB_INVALID_ADDRESS) { 1243ac7ddfbfSEd Maste if (fun_addr_range.ContainsLoadAddress(address, target)) 1244ac7ddfbfSEd Maste address_list.push_back(address); 1245ac7ddfbfSEd Maste else 1246ac7ddfbfSEd Maste all_in_function = false; 1247ac7ddfbfSEd Maste } 12481c3bbb01SEd Maste start_idx_ptr++; 12491c3bbb01SEd Maste } 12501c3bbb01SEd Maste } 12511c3bbb01SEd Maste 1252435933ddSDimitry Andric for (lldb::addr_t address : m_options.m_until_addrs) { 12531c3bbb01SEd Maste if (fun_addr_range.ContainsLoadAddress(address, target)) 12541c3bbb01SEd Maste address_list.push_back(address); 12551c3bbb01SEd Maste else 12561c3bbb01SEd Maste all_in_function = false; 1257ac7ddfbfSEd Maste } 1258ac7ddfbfSEd Maste 1259435933ddSDimitry Andric if (address_list.empty()) { 1260ac7ddfbfSEd Maste if (all_in_function) 1261435933ddSDimitry Andric result.AppendErrorWithFormat( 1262435933ddSDimitry Andric "No line entries matching until target.\n"); 1263ac7ddfbfSEd Maste else 1264435933ddSDimitry Andric result.AppendErrorWithFormat( 1265435933ddSDimitry Andric "Until target outside of the current function.\n"); 1266ac7ddfbfSEd Maste 1267ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1268ac7ddfbfSEd Maste return false; 1269ac7ddfbfSEd Maste } 1270ac7ddfbfSEd Maste 1271435933ddSDimitry Andric new_plan_sp = thread->QueueThreadPlanForStepUntil( 1272435933ddSDimitry Andric abort_other_plans, &address_list.front(), address_list.size(), 1273435933ddSDimitry Andric m_options.m_stop_others, m_options.m_frame_idx); 1274435933ddSDimitry Andric // User level plans should be master plans so they can be interrupted 1275435933ddSDimitry Andric // (e.g. by hitting a breakpoint) 1276435933ddSDimitry Andric // and other plans executed by the user (stepping around the breakpoint) 1277435933ddSDimitry Andric // and then a "continue" 1278ac7ddfbfSEd Maste // will resume the original plan. 1279ac7ddfbfSEd Maste new_plan_sp->SetIsMasterPlan(true); 1280ac7ddfbfSEd Maste new_plan_sp->SetOkayToDiscard(false); 1281435933ddSDimitry Andric } else { 1282435933ddSDimitry Andric result.AppendErrorWithFormat( 1283435933ddSDimitry Andric "Frame index %u of thread %u has no debug information.\n", 1284435933ddSDimitry Andric m_options.m_frame_idx, m_options.m_thread_idx); 1285ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1286ac7ddfbfSEd Maste return false; 1287ac7ddfbfSEd Maste } 1288ac7ddfbfSEd Maste 1289ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(m_options.m_thread_idx); 12907aa51b79SEd Maste 12917aa51b79SEd Maste StreamString stream; 12925517e702SDimitry Andric Status error; 12937aa51b79SEd Maste if (synchronous_execution) 12947aa51b79SEd Maste error = process->ResumeSynchronous(&stream); 12957aa51b79SEd Maste else 12967aa51b79SEd Maste error = process->Resume(); 12977aa51b79SEd Maste 1298435933ddSDimitry Andric if (error.Success()) { 1299435933ddSDimitry Andric result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n", 1300435933ddSDimitry Andric process->GetID()); 1301435933ddSDimitry Andric if (synchronous_execution) { 1302435933ddSDimitry Andric // If any state changed events had anything to say, add that to the 1303435933ddSDimitry Andric // result 1304435933ddSDimitry Andric if (stream.GetSize() > 0) 1305435933ddSDimitry Andric result.AppendMessage(stream.GetString()); 1306ac7ddfbfSEd Maste 1307ac7ddfbfSEd Maste result.SetDidChangeProcessState(true); 1308ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 1309435933ddSDimitry Andric } else { 1310ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessContinuingNoResult); 1311ac7ddfbfSEd Maste } 1312435933ddSDimitry Andric } else { 1313435933ddSDimitry Andric result.AppendErrorWithFormat("Failed to resume process: %s.\n", 1314435933ddSDimitry Andric error.AsCString()); 1315ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1316ac7ddfbfSEd Maste } 1317ac7ddfbfSEd Maste } 1318ac7ddfbfSEd Maste return result.Succeeded(); 1319ac7ddfbfSEd Maste } 1320ac7ddfbfSEd Maste 1321ac7ddfbfSEd Maste CommandOptions m_options; 1322ac7ddfbfSEd Maste }; 1323ac7ddfbfSEd Maste 1324ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1325ac7ddfbfSEd Maste // CommandObjectThreadSelect 1326ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1327ac7ddfbfSEd Maste 1328435933ddSDimitry Andric class CommandObjectThreadSelect : public CommandObjectParsed { 1329ac7ddfbfSEd Maste public: 13304bb0738eSEd Maste CommandObjectThreadSelect(CommandInterpreter &interpreter) 1331435933ddSDimitry Andric : CommandObjectParsed(interpreter, "thread select", 1332435933ddSDimitry Andric "Change the currently selected thread.", nullptr, 1333435933ddSDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 1334435933ddSDimitry Andric eCommandProcessMustBeLaunched | 1335435933ddSDimitry Andric eCommandProcessMustBePaused) { 1336ac7ddfbfSEd Maste CommandArgumentEntry arg; 1337ac7ddfbfSEd Maste CommandArgumentData thread_idx_arg; 1338ac7ddfbfSEd Maste 1339ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 1340ac7ddfbfSEd Maste thread_idx_arg.arg_type = eArgTypeThreadIndex; 1341ac7ddfbfSEd Maste thread_idx_arg.arg_repetition = eArgRepeatPlain; 1342ac7ddfbfSEd Maste 1343435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 1344435933ddSDimitry Andric // argument entry. 1345ac7ddfbfSEd Maste arg.push_back(thread_idx_arg); 1346ac7ddfbfSEd Maste 1347ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 1348ac7ddfbfSEd Maste m_arguments.push_back(arg); 1349ac7ddfbfSEd Maste } 1350ac7ddfbfSEd Maste 13514bb0738eSEd Maste ~CommandObjectThreadSelect() override = default; 1352ac7ddfbfSEd Maste 1353ac7ddfbfSEd Maste protected: 1354435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 1355ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 1356435933ddSDimitry Andric if (process == nullptr) { 1357ac7ddfbfSEd Maste result.AppendError("no process"); 1358ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1359ac7ddfbfSEd Maste return false; 1360435933ddSDimitry Andric } else if (command.GetArgumentCount() != 1) { 1361435933ddSDimitry Andric result.AppendErrorWithFormat( 1362435933ddSDimitry Andric "'%s' takes exactly one thread index argument:\nUsage: %s\n", 1363435933ddSDimitry Andric m_cmd_name.c_str(), m_cmd_syntax.c_str()); 1364ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1365ac7ddfbfSEd Maste return false; 1366ac7ddfbfSEd Maste } 1367ac7ddfbfSEd Maste 1368435933ddSDimitry Andric uint32_t index_id = 1369435933ddSDimitry Andric StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 1370ac7ddfbfSEd Maste 1371435933ddSDimitry Andric Thread *new_thread = 1372435933ddSDimitry Andric process->GetThreadList().FindThreadByIndexID(index_id).get(); 1373435933ddSDimitry Andric if (new_thread == nullptr) { 1374435933ddSDimitry Andric result.AppendErrorWithFormat("invalid thread #%s.\n", 1375435933ddSDimitry Andric command.GetArgumentAtIndex(0)); 1376ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1377ac7ddfbfSEd Maste return false; 1378ac7ddfbfSEd Maste } 1379ac7ddfbfSEd Maste 1380ac7ddfbfSEd Maste process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true); 1381ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 1382ac7ddfbfSEd Maste 1383ac7ddfbfSEd Maste return result.Succeeded(); 1384ac7ddfbfSEd Maste } 1385ac7ddfbfSEd Maste }; 1386ac7ddfbfSEd Maste 1387ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1388ac7ddfbfSEd Maste // CommandObjectThreadList 1389ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1390ac7ddfbfSEd Maste 1391435933ddSDimitry Andric class CommandObjectThreadList : public CommandObjectParsed { 1392ac7ddfbfSEd Maste public: 13934bb0738eSEd Maste CommandObjectThreadList(CommandInterpreter &interpreter) 1394435933ddSDimitry Andric : CommandObjectParsed( 1395435933ddSDimitry Andric interpreter, "thread list", 1396435933ddSDimitry Andric "Show a summary of each thread in the current target process.", 1397435933ddSDimitry Andric "thread list", 1398435933ddSDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 1399435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 1400ac7ddfbfSEd Maste 14014bb0738eSEd Maste ~CommandObjectThreadList() override = default; 1402ac7ddfbfSEd Maste 1403ac7ddfbfSEd Maste protected: 1404435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override { 1405ac7ddfbfSEd Maste Stream &strm = result.GetOutputStream(); 1406ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 1407ac7ddfbfSEd Maste Process *process = m_exe_ctx.GetProcessPtr(); 1408ac7ddfbfSEd Maste const bool only_threads_with_stop_reason = false; 1409ac7ddfbfSEd Maste const uint32_t start_frame = 0; 1410ac7ddfbfSEd Maste const uint32_t num_frames = 0; 1411ac7ddfbfSEd Maste const uint32_t num_frames_with_source = 0; 1412ac7ddfbfSEd Maste process->GetStatus(strm); 1413435933ddSDimitry Andric process->GetThreadStatus(strm, only_threads_with_stop_reason, start_frame, 1414435933ddSDimitry Andric num_frames, num_frames_with_source, false); 1415ac7ddfbfSEd Maste return result.Succeeded(); 1416ac7ddfbfSEd Maste } 1417ac7ddfbfSEd Maste }; 1418ac7ddfbfSEd Maste 1419ac7ddfbfSEd Maste //------------------------------------------------------------------------- 14200127ef0fSEd Maste // CommandObjectThreadInfo 14210127ef0fSEd Maste //------------------------------------------------------------------------- 14220127ef0fSEd Maste 1423435933ddSDimitry Andric static OptionDefinition g_thread_info_options[] = { 1424435933ddSDimitry Andric // clang-format off 1425435933ddSDimitry Andric { LLDB_OPT_SET_ALL, false, "json", 'j', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display the thread info in JSON format." }, 1426435933ddSDimitry Andric { LLDB_OPT_SET_ALL, false, "stop-info", 's', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display the extended stop info in JSON format." } 1427435933ddSDimitry Andric // clang-format on 1428435933ddSDimitry Andric }; 1429435933ddSDimitry Andric 1430435933ddSDimitry Andric class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { 14310127ef0fSEd Maste public: 1432435933ddSDimitry Andric class CommandOptions : public Options { 14330127ef0fSEd Maste public: 1434435933ddSDimitry Andric CommandOptions() : Options() { OptionParsingStarting(nullptr); } 14350127ef0fSEd Maste 14364bb0738eSEd Maste ~CommandOptions() override = default; 14374bb0738eSEd Maste 1438435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 14397aa51b79SEd Maste m_json_thread = false; 14407aa51b79SEd Maste m_json_stopinfo = false; 14410127ef0fSEd Maste } 14420127ef0fSEd Maste 14435517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1444435933ddSDimitry Andric ExecutionContext *execution_context) override { 14450127ef0fSEd Maste const int short_option = m_getopt_table[option_idx].val; 14465517e702SDimitry Andric Status error; 14470127ef0fSEd Maste 1448435933ddSDimitry Andric switch (short_option) { 14490127ef0fSEd Maste case 'j': 14507aa51b79SEd Maste m_json_thread = true; 14517aa51b79SEd Maste break; 14527aa51b79SEd Maste 14537aa51b79SEd Maste case 's': 14547aa51b79SEd Maste m_json_stopinfo = true; 14550127ef0fSEd Maste break; 14560127ef0fSEd Maste 14570127ef0fSEd Maste default: 14585517e702SDimitry Andric return Status("invalid short option character '%c'", short_option); 14590127ef0fSEd Maste } 14600127ef0fSEd Maste return error; 14610127ef0fSEd Maste } 14620127ef0fSEd Maste 1463435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1464435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_info_options); 14650127ef0fSEd Maste } 14660127ef0fSEd Maste 14677aa51b79SEd Maste bool m_json_thread; 14687aa51b79SEd Maste bool m_json_stopinfo; 14690127ef0fSEd Maste }; 14700127ef0fSEd Maste 14714bb0738eSEd Maste CommandObjectThreadInfo(CommandInterpreter &interpreter) 14724bb0738eSEd Maste : CommandObjectIterateOverThreads( 1473435933ddSDimitry Andric interpreter, "thread info", "Show an extended summary of one or " 1474435933ddSDimitry Andric "more threads. Defaults to the " 1475435933ddSDimitry Andric "current thread.", 1476435933ddSDimitry Andric "thread info", 1477435933ddSDimitry Andric eCommandRequiresProcess | eCommandTryTargetAPILock | 1478435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 1479435933ddSDimitry Andric m_options() { 14804bb0738eSEd Maste m_add_return = false; 14814bb0738eSEd Maste } 14824bb0738eSEd Maste 14834bb0738eSEd Maste ~CommandObjectThreadInfo() override = default; 14844bb0738eSEd Maste 1485435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 14860127ef0fSEd Maste 1487435933ddSDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 1488435933ddSDimitry Andric ThreadSP thread_sp = 1489435933ddSDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 1490435933ddSDimitry Andric if (!thread_sp) { 1491435933ddSDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", 1492435933ddSDimitry Andric tid); 14934bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 14944bb0738eSEd Maste return false; 14950127ef0fSEd Maste } 14960127ef0fSEd Maste 14974bb0738eSEd Maste Thread *thread = thread_sp.get(); 14984bb0738eSEd Maste 14990127ef0fSEd Maste Stream &strm = result.GetOutputStream(); 1500435933ddSDimitry Andric if (!thread->GetDescription(strm, eDescriptionLevelFull, 1501435933ddSDimitry Andric m_options.m_json_thread, 1502435933ddSDimitry Andric m_options.m_json_stopinfo)) { 1503435933ddSDimitry Andric result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n", 1504435933ddSDimitry Andric thread->GetIndexID()); 15050127ef0fSEd Maste result.SetStatus(eReturnStatusFailed); 15060127ef0fSEd Maste return false; 15070127ef0fSEd Maste } 15087aa51b79SEd Maste return true; 15090127ef0fSEd Maste } 15100127ef0fSEd Maste 15110127ef0fSEd Maste CommandOptions m_options; 15120127ef0fSEd Maste }; 15130127ef0fSEd Maste 15140127ef0fSEd Maste //------------------------------------------------------------------------- 1515ac7ddfbfSEd Maste // CommandObjectThreadReturn 1516ac7ddfbfSEd Maste //------------------------------------------------------------------------- 1517ac7ddfbfSEd Maste 1518435933ddSDimitry Andric static OptionDefinition g_thread_return_options[] = { 1519435933ddSDimitry Andric // clang-format off 1520435933ddSDimitry Andric { LLDB_OPT_SET_ALL, false, "from-expression", 'x', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Return from the innermost expression evaluation." } 1521435933ddSDimitry Andric // clang-format on 1522435933ddSDimitry Andric }; 1523435933ddSDimitry Andric 1524435933ddSDimitry Andric class CommandObjectThreadReturn : public CommandObjectRaw { 1525ac7ddfbfSEd Maste public: 1526435933ddSDimitry Andric class CommandOptions : public Options { 1527ac7ddfbfSEd Maste public: 1528435933ddSDimitry Andric CommandOptions() : Options(), m_from_expression(false) { 1529435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 1530435933ddSDimitry Andric // () 1531435933ddSDimitry Andric OptionParsingStarting(nullptr); 1532ac7ddfbfSEd Maste } 1533ac7ddfbfSEd Maste 15344bb0738eSEd Maste ~CommandOptions() override = default; 1535ac7ddfbfSEd Maste 15365517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1537435933ddSDimitry Andric ExecutionContext *execution_context) override { 15385517e702SDimitry Andric Status error; 1539ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val; 1540ac7ddfbfSEd Maste 1541435933ddSDimitry Andric switch (short_option) { 1542435933ddSDimitry Andric case 'x': { 1543ac7ddfbfSEd Maste bool success; 1544ac7ddfbfSEd Maste bool tmp_value = Args::StringToBoolean(option_arg, false, &success); 1545ac7ddfbfSEd Maste if (success) 1546ac7ddfbfSEd Maste m_from_expression = tmp_value; 1547435933ddSDimitry Andric else { 1548435933ddSDimitry Andric error.SetErrorStringWithFormat( 1549435933ddSDimitry Andric "invalid boolean value '%s' for 'x' option", 1550435933ddSDimitry Andric option_arg.str().c_str()); 1551ac7ddfbfSEd Maste } 1552435933ddSDimitry Andric } break; 1553ac7ddfbfSEd Maste default: 1554435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 1555435933ddSDimitry Andric short_option); 1556ac7ddfbfSEd Maste break; 1557ac7ddfbfSEd Maste } 1558ac7ddfbfSEd Maste return error; 1559ac7ddfbfSEd Maste } 1560ac7ddfbfSEd Maste 1561435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 1562ac7ddfbfSEd Maste m_from_expression = false; 1563ac7ddfbfSEd Maste } 1564ac7ddfbfSEd Maste 1565435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1566435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_return_options); 1567ac7ddfbfSEd Maste } 1568ac7ddfbfSEd Maste 1569ac7ddfbfSEd Maste bool m_from_expression; 1570ac7ddfbfSEd Maste 1571ac7ddfbfSEd Maste // Instance variables to hold the values for command options. 1572ac7ddfbfSEd Maste }; 1573ac7ddfbfSEd Maste 15744bb0738eSEd Maste CommandObjectThreadReturn(CommandInterpreter &interpreter) 15754bb0738eSEd Maste : CommandObjectRaw(interpreter, "thread return", 1576435933ddSDimitry Andric "Prematurely return from a stack frame, " 1577435933ddSDimitry Andric "short-circuiting execution of newer frames " 1578435933ddSDimitry Andric "and optionally yielding a specified value. Defaults " 1579435933ddSDimitry Andric "to the exiting the current stack " 15804bb0738eSEd Maste "frame.", 1581435933ddSDimitry Andric "thread return", 1582435933ddSDimitry Andric eCommandRequiresFrame | eCommandTryTargetAPILock | 1583435933ddSDimitry Andric eCommandProcessMustBeLaunched | 1584435933ddSDimitry Andric eCommandProcessMustBePaused), 1585435933ddSDimitry Andric m_options() { 1586ac7ddfbfSEd Maste CommandArgumentEntry arg; 1587ac7ddfbfSEd Maste CommandArgumentData expression_arg; 1588ac7ddfbfSEd Maste 1589ac7ddfbfSEd Maste // Define the first (and only) variant of this arg. 1590ac7ddfbfSEd Maste expression_arg.arg_type = eArgTypeExpression; 1591ac7ddfbfSEd Maste expression_arg.arg_repetition = eArgRepeatOptional; 1592ac7ddfbfSEd Maste 1593435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 1594435933ddSDimitry Andric // argument entry. 1595ac7ddfbfSEd Maste arg.push_back(expression_arg); 1596ac7ddfbfSEd Maste 1597ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector. 1598ac7ddfbfSEd Maste m_arguments.push_back(arg); 1599ac7ddfbfSEd Maste } 1600ac7ddfbfSEd Maste 16014bb0738eSEd Maste ~CommandObjectThreadReturn() override = default; 16024bb0738eSEd Maste 1603435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 1604ac7ddfbfSEd Maste 1605ac7ddfbfSEd Maste protected: 1606435933ddSDimitry Andric bool DoExecute(const char *command, CommandReturnObject &result) override { 1607435933ddSDimitry Andric // I am going to handle this by hand, because I don't want you to have to 1608435933ddSDimitry Andric // say: 1609ac7ddfbfSEd Maste // "thread return -- -5". 1610435933ddSDimitry Andric if (command[0] == '-' && command[1] == 'x') { 1611ac7ddfbfSEd Maste if (command && command[2] != '\0') 1612435933ddSDimitry Andric result.AppendWarning("Return values ignored when returning from user " 1613435933ddSDimitry Andric "called expressions"); 1614ac7ddfbfSEd Maste 1615ac7ddfbfSEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 16165517e702SDimitry Andric Status error; 1617ac7ddfbfSEd Maste error = thread->UnwindInnermostExpression(); 1618435933ddSDimitry Andric if (!error.Success()) { 1619435933ddSDimitry Andric result.AppendErrorWithFormat("Unwinding expression failed - %s.", 1620435933ddSDimitry Andric error.AsCString()); 1621ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1622435933ddSDimitry Andric } else { 1623435933ddSDimitry Andric bool success = 1624435933ddSDimitry Andric thread->SetSelectedFrameByIndexNoisily(0, result.GetOutputStream()); 1625435933ddSDimitry Andric if (success) { 1626ac7ddfbfSEd Maste m_exe_ctx.SetFrameSP(thread->GetSelectedFrame()); 1627ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult); 1628435933ddSDimitry Andric } else { 1629435933ddSDimitry Andric result.AppendErrorWithFormat( 1630435933ddSDimitry Andric "Could not select 0th frame after unwinding expression."); 1631ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1632ac7ddfbfSEd Maste } 1633ac7ddfbfSEd Maste } 1634ac7ddfbfSEd Maste return result.Succeeded(); 1635ac7ddfbfSEd Maste } 1636ac7ddfbfSEd Maste 1637ac7ddfbfSEd Maste ValueObjectSP return_valobj_sp; 1638ac7ddfbfSEd Maste 1639ac7ddfbfSEd Maste StackFrameSP frame_sp = m_exe_ctx.GetFrameSP(); 1640ac7ddfbfSEd Maste uint32_t frame_idx = frame_sp->GetFrameIndex(); 1641ac7ddfbfSEd Maste 1642435933ddSDimitry Andric if (frame_sp->IsInlined()) { 1643ac7ddfbfSEd Maste result.AppendError("Don't know how to return from inlined frames."); 1644ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1645ac7ddfbfSEd Maste return false; 1646ac7ddfbfSEd Maste } 1647ac7ddfbfSEd Maste 1648435933ddSDimitry Andric if (command && command[0] != '\0') { 1649ac7ddfbfSEd Maste Target *target = m_exe_ctx.GetTargetPtr(); 1650ac7ddfbfSEd Maste EvaluateExpressionOptions options; 1651ac7ddfbfSEd Maste 1652ac7ddfbfSEd Maste options.SetUnwindOnError(true); 1653ac7ddfbfSEd Maste options.SetUseDynamic(eNoDynamicValues); 1654ac7ddfbfSEd Maste 16550127ef0fSEd Maste ExpressionResults exe_results = eExpressionSetupError; 1656435933ddSDimitry Andric exe_results = target->EvaluateExpression(command, frame_sp.get(), 1657435933ddSDimitry Andric return_valobj_sp, options); 1658435933ddSDimitry Andric if (exe_results != eExpressionCompleted) { 1659ac7ddfbfSEd Maste if (return_valobj_sp) 1660435933ddSDimitry Andric result.AppendErrorWithFormat( 1661435933ddSDimitry Andric "Error evaluating result expression: %s", 1662435933ddSDimitry Andric return_valobj_sp->GetError().AsCString()); 1663ac7ddfbfSEd Maste else 1664435933ddSDimitry Andric result.AppendErrorWithFormat( 1665435933ddSDimitry Andric "Unknown error evaluating result expression."); 1666ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1667ac7ddfbfSEd Maste return false; 1668ac7ddfbfSEd Maste } 1669ac7ddfbfSEd Maste } 1670ac7ddfbfSEd Maste 16715517e702SDimitry Andric Status error; 1672ac7ddfbfSEd Maste ThreadSP thread_sp = m_exe_ctx.GetThreadSP(); 1673ac7ddfbfSEd Maste const bool broadcast = true; 1674ac7ddfbfSEd Maste error = thread_sp->ReturnFromFrame(frame_sp, return_valobj_sp, broadcast); 1675435933ddSDimitry Andric if (!error.Success()) { 1676435933ddSDimitry Andric result.AppendErrorWithFormat( 1677435933ddSDimitry Andric "Error returning from frame %d of thread %d: %s.", frame_idx, 1678435933ddSDimitry Andric thread_sp->GetIndexID(), error.AsCString()); 1679ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed); 1680ac7ddfbfSEd Maste return false; 1681ac7ddfbfSEd Maste } 1682ac7ddfbfSEd Maste 1683ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult); 1684ac7ddfbfSEd Maste return true; 1685ac7ddfbfSEd Maste } 1686ac7ddfbfSEd Maste 1687ac7ddfbfSEd Maste CommandOptions m_options; 1688ac7ddfbfSEd Maste }; 16894bb0738eSEd Maste 169035617911SEd Maste //------------------------------------------------------------------------- 169135617911SEd Maste // CommandObjectThreadJump 169235617911SEd Maste //------------------------------------------------------------------------- 169335617911SEd Maste 1694435933ddSDimitry Andric static OptionDefinition g_thread_jump_options[] = { 1695435933ddSDimitry Andric // clang-format off 1696435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specifies the source file to jump to." }, 1697435933ddSDimitry Andric { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, "Specifies the line number to jump to." }, 1698435933ddSDimitry Andric { LLDB_OPT_SET_2, true, "by", 'b', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "Jumps by a relative line offset from the current line." }, 1699435933ddSDimitry Andric { LLDB_OPT_SET_3, true, "address", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddressOrExpression, "Jumps to a specific address." }, 1700435933ddSDimitry 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." } 1701435933ddSDimitry Andric // clang-format on 1702435933ddSDimitry Andric }; 1703435933ddSDimitry Andric 1704435933ddSDimitry Andric class CommandObjectThreadJump : public CommandObjectParsed { 170535617911SEd Maste public: 1706435933ddSDimitry Andric class CommandOptions : public Options { 170735617911SEd Maste public: 1708435933ddSDimitry Andric CommandOptions() : Options() { OptionParsingStarting(nullptr); } 170935617911SEd Maste 17104bb0738eSEd Maste ~CommandOptions() override = default; 17114bb0738eSEd Maste 1712435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 171335617911SEd Maste m_filenames.Clear(); 171435617911SEd Maste m_line_num = 0; 171535617911SEd Maste m_line_offset = 0; 171635617911SEd Maste m_load_addr = LLDB_INVALID_ADDRESS; 171735617911SEd Maste m_force = false; 171835617911SEd Maste } 171935617911SEd Maste 17205517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1721435933ddSDimitry Andric ExecutionContext *execution_context) override { 172235617911SEd Maste const int short_option = m_getopt_table[option_idx].val; 17235517e702SDimitry Andric Status error; 172435617911SEd Maste 1725435933ddSDimitry Andric switch (short_option) { 172635617911SEd Maste case 'f': 172735617911SEd Maste m_filenames.AppendIfUnique(FileSpec(option_arg, false)); 172835617911SEd Maste if (m_filenames.GetSize() > 1) 17295517e702SDimitry Andric return Status("only one source file expected."); 173035617911SEd Maste break; 173135617911SEd Maste case 'l': 1732435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_line_num)) 17335517e702SDimitry Andric return Status("invalid line number: '%s'.", option_arg.str().c_str()); 173435617911SEd Maste break; 173535617911SEd Maste case 'b': 1736435933ddSDimitry Andric if (option_arg.getAsInteger(0, m_line_offset)) 17375517e702SDimitry Andric return Status("invalid line offset: '%s'.", option_arg.str().c_str()); 173835617911SEd Maste break; 173935617911SEd Maste case 'a': 1740435933ddSDimitry Andric m_load_addr = Args::StringToAddress(execution_context, option_arg, 1741435933ddSDimitry Andric LLDB_INVALID_ADDRESS, &error); 174235617911SEd Maste break; 174335617911SEd Maste case 'r': 174435617911SEd Maste m_force = true; 174535617911SEd Maste break; 174635617911SEd Maste default: 17475517e702SDimitry Andric return Status("invalid short option character '%c'", short_option); 174835617911SEd Maste } 174935617911SEd Maste return error; 175035617911SEd Maste } 175135617911SEd Maste 1752435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1753435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_jump_options); 175435617911SEd Maste } 175535617911SEd Maste 175635617911SEd Maste FileSpecList m_filenames; 175735617911SEd Maste uint32_t m_line_num; 175835617911SEd Maste int32_t m_line_offset; 175935617911SEd Maste lldb::addr_t m_load_addr; 176035617911SEd Maste bool m_force; 176135617911SEd Maste }; 176235617911SEd Maste 1763435933ddSDimitry Andric CommandObjectThreadJump(CommandInterpreter &interpreter) 1764435933ddSDimitry Andric : CommandObjectParsed( 1765435933ddSDimitry Andric interpreter, "thread jump", 1766435933ddSDimitry Andric "Sets the program counter to a new address.", "thread jump", 1767435933ddSDimitry Andric eCommandRequiresFrame | eCommandTryTargetAPILock | 1768435933ddSDimitry Andric eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 1769435933ddSDimitry Andric m_options() {} 177035617911SEd Maste 17714bb0738eSEd Maste ~CommandObjectThreadJump() override = default; 17724bb0738eSEd Maste 1773435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 177435617911SEd Maste 177535617911SEd Maste protected: 1776435933ddSDimitry Andric bool DoExecute(Args &args, CommandReturnObject &result) override { 177735617911SEd Maste RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext(); 177835617911SEd Maste StackFrame *frame = m_exe_ctx.GetFramePtr(); 177935617911SEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 178035617911SEd Maste Target *target = m_exe_ctx.GetTargetPtr(); 1781435933ddSDimitry Andric const SymbolContext &sym_ctx = 1782435933ddSDimitry Andric frame->GetSymbolContext(eSymbolContextLineEntry); 178335617911SEd Maste 1784435933ddSDimitry Andric if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) { 178535617911SEd Maste // Use this address directly. 178635617911SEd Maste Address dest = Address(m_options.m_load_addr); 178735617911SEd Maste 178835617911SEd Maste lldb::addr_t callAddr = dest.GetCallableLoadAddress(target); 1789435933ddSDimitry Andric if (callAddr == LLDB_INVALID_ADDRESS) { 179035617911SEd Maste result.AppendErrorWithFormat("Invalid destination address."); 179135617911SEd Maste result.SetStatus(eReturnStatusFailed); 179235617911SEd Maste return false; 179335617911SEd Maste } 179435617911SEd Maste 1795435933ddSDimitry Andric if (!reg_ctx->SetPC(callAddr)) { 1796435933ddSDimitry Andric result.AppendErrorWithFormat("Error changing PC value for thread %d.", 1797435933ddSDimitry Andric thread->GetIndexID()); 179835617911SEd Maste result.SetStatus(eReturnStatusFailed); 179935617911SEd Maste return false; 180035617911SEd Maste } 1801435933ddSDimitry Andric } else { 180235617911SEd Maste // Pick either the absolute line, or work out a relative one. 180335617911SEd Maste int32_t line = (int32_t)m_options.m_line_num; 180435617911SEd Maste if (line == 0) 180535617911SEd Maste line = sym_ctx.line_entry.line + m_options.m_line_offset; 180635617911SEd Maste 180735617911SEd Maste // Try the current file, but override if asked. 180835617911SEd Maste FileSpec file = sym_ctx.line_entry.file; 180935617911SEd Maste if (m_options.m_filenames.GetSize() == 1) 181035617911SEd Maste file = m_options.m_filenames.GetFileSpecAtIndex(0); 181135617911SEd Maste 1812435933ddSDimitry Andric if (!file) { 1813435933ddSDimitry Andric result.AppendErrorWithFormat( 1814435933ddSDimitry Andric "No source file available for the current location."); 181535617911SEd Maste result.SetStatus(eReturnStatusFailed); 181635617911SEd Maste return false; 181735617911SEd Maste } 181835617911SEd Maste 181935617911SEd Maste std::string warnings; 18205517e702SDimitry Andric Status err = thread->JumpToLine(file, line, m_options.m_force, &warnings); 182135617911SEd Maste 1822435933ddSDimitry Andric if (err.Fail()) { 182335617911SEd Maste result.SetError(err); 182435617911SEd Maste return false; 182535617911SEd Maste } 182635617911SEd Maste 182735617911SEd Maste if (!warnings.empty()) 182835617911SEd Maste result.AppendWarning(warnings.c_str()); 182935617911SEd Maste } 183035617911SEd Maste 183135617911SEd Maste result.SetStatus(eReturnStatusSuccessFinishResult); 183235617911SEd Maste return true; 183335617911SEd Maste } 183435617911SEd Maste 183535617911SEd Maste CommandOptions m_options; 183635617911SEd Maste }; 18374bb0738eSEd Maste 1838ac7ddfbfSEd Maste //------------------------------------------------------------------------- 18397aa51b79SEd Maste // Next are the subcommands of CommandObjectMultiwordThreadPlan 18407aa51b79SEd Maste //------------------------------------------------------------------------- 18417aa51b79SEd Maste 18427aa51b79SEd Maste //------------------------------------------------------------------------- 18437aa51b79SEd Maste // CommandObjectThreadPlanList 18447aa51b79SEd Maste //------------------------------------------------------------------------- 18454bb0738eSEd Maste 1846435933ddSDimitry Andric static OptionDefinition g_thread_plan_list_options[] = { 1847435933ddSDimitry Andric // clang-format off 1848435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display more information about the thread plans" }, 1849435933ddSDimitry Andric { LLDB_OPT_SET_1, false, "internal", 'i', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Display internal as well as user thread plans" } 1850435933ddSDimitry Andric // clang-format on 1851435933ddSDimitry Andric }; 1852435933ddSDimitry Andric 1853435933ddSDimitry Andric class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads { 18547aa51b79SEd Maste public: 1855435933ddSDimitry Andric class CommandOptions : public Options { 18567aa51b79SEd Maste public: 1857435933ddSDimitry Andric CommandOptions() : Options() { 1858435933ddSDimitry Andric // Keep default values of all options in one place: OptionParsingStarting 1859435933ddSDimitry Andric // () 1860435933ddSDimitry Andric OptionParsingStarting(nullptr); 18617aa51b79SEd Maste } 18627aa51b79SEd Maste 18634bb0738eSEd Maste ~CommandOptions() override = default; 18647aa51b79SEd Maste 18655517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1866435933ddSDimitry Andric ExecutionContext *execution_context) override { 18675517e702SDimitry Andric Status error; 18687aa51b79SEd Maste const int short_option = m_getopt_table[option_idx].val; 18697aa51b79SEd Maste 1870435933ddSDimitry Andric switch (short_option) { 18717aa51b79SEd Maste case 'i': 18727aa51b79SEd Maste m_internal = true; 18737aa51b79SEd Maste break; 18747aa51b79SEd Maste case 'v': 18757aa51b79SEd Maste m_verbose = true; 18767aa51b79SEd Maste break; 18777aa51b79SEd Maste default: 1878435933ddSDimitry Andric error.SetErrorStringWithFormat("invalid short option character '%c'", 1879435933ddSDimitry Andric short_option); 18807aa51b79SEd Maste break; 18817aa51b79SEd Maste } 18827aa51b79SEd Maste return error; 18837aa51b79SEd Maste } 18847aa51b79SEd Maste 1885435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override { 18867aa51b79SEd Maste m_verbose = false; 18877aa51b79SEd Maste m_internal = false; 18887aa51b79SEd Maste } 18897aa51b79SEd Maste 1890435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1891435933ddSDimitry Andric return llvm::makeArrayRef(g_thread_plan_list_options); 18927aa51b79SEd Maste } 18937aa51b79SEd Maste 18947aa51b79SEd Maste // Instance variables to hold the values for command options. 18957aa51b79SEd Maste bool m_verbose; 18967aa51b79SEd Maste bool m_internal; 18977aa51b79SEd Maste }; 18987aa51b79SEd Maste 18994bb0738eSEd Maste CommandObjectThreadPlanList(CommandInterpreter &interpreter) 19004bb0738eSEd Maste : CommandObjectIterateOverThreads( 19014bb0738eSEd Maste interpreter, "thread plan list", 1902435933ddSDimitry Andric "Show thread plans for one or more threads. If no threads are " 1903435933ddSDimitry Andric "specified, show the " 19044bb0738eSEd Maste "current thread. Use the thread-index \"all\" to see all threads.", 1905435933ddSDimitry Andric nullptr, 1906435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 1907435933ddSDimitry Andric eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 1908435933ddSDimitry Andric eCommandProcessMustBePaused), 1909435933ddSDimitry Andric m_options() {} 19107aa51b79SEd Maste 19114bb0738eSEd Maste ~CommandObjectThreadPlanList() override = default; 19127aa51b79SEd Maste 1913435933ddSDimitry Andric Options *GetOptions() override { return &m_options; } 19147aa51b79SEd Maste 19157aa51b79SEd Maste protected: 1916435933ddSDimitry Andric bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { 1917435933ddSDimitry Andric ThreadSP thread_sp = 1918435933ddSDimitry Andric m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); 1919435933ddSDimitry Andric if (!thread_sp) { 1920435933ddSDimitry Andric result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", 1921435933ddSDimitry Andric tid); 19224bb0738eSEd Maste result.SetStatus(eReturnStatusFailed); 19234bb0738eSEd Maste return false; 19244bb0738eSEd Maste } 19254bb0738eSEd Maste 19264bb0738eSEd Maste Thread *thread = thread_sp.get(); 19274bb0738eSEd Maste 19287aa51b79SEd Maste Stream &strm = result.GetOutputStream(); 19297aa51b79SEd Maste DescriptionLevel desc_level = eDescriptionLevelFull; 19307aa51b79SEd Maste if (m_options.m_verbose) 19317aa51b79SEd Maste desc_level = eDescriptionLevelVerbose; 19327aa51b79SEd Maste 19334bb0738eSEd Maste thread->DumpThreadPlans(&strm, desc_level, m_options.m_internal, true); 19347aa51b79SEd Maste return true; 19357aa51b79SEd Maste } 19364bb0738eSEd Maste 19377aa51b79SEd Maste CommandOptions m_options; 19387aa51b79SEd Maste }; 19397aa51b79SEd Maste 1940435933ddSDimitry Andric class CommandObjectThreadPlanDiscard : public CommandObjectParsed { 19417aa51b79SEd Maste public: 19424bb0738eSEd Maste CommandObjectThreadPlanDiscard(CommandInterpreter &interpreter) 1943435933ddSDimitry Andric : CommandObjectParsed(interpreter, "thread plan discard", 1944435933ddSDimitry Andric "Discards thread plans up to and including the " 1945435933ddSDimitry Andric "specified index (see 'thread plan list'.) " 19464bb0738eSEd Maste "Only user visible plans can be discarded.", 1947435933ddSDimitry Andric nullptr, 1948435933ddSDimitry Andric eCommandRequiresProcess | eCommandRequiresThread | 1949435933ddSDimitry Andric eCommandTryTargetAPILock | 1950435933ddSDimitry Andric eCommandProcessMustBeLaunched | 1951435933ddSDimitry Andric eCommandProcessMustBePaused) { 19527aa51b79SEd Maste CommandArgumentEntry arg; 19537aa51b79SEd Maste CommandArgumentData plan_index_arg; 19547aa51b79SEd Maste 19557aa51b79SEd Maste // Define the first (and only) variant of this arg. 19567aa51b79SEd Maste plan_index_arg.arg_type = eArgTypeUnsignedInteger; 19577aa51b79SEd Maste plan_index_arg.arg_repetition = eArgRepeatPlain; 19587aa51b79SEd Maste 1959435933ddSDimitry Andric // There is only one variant this argument could be; put it into the 1960435933ddSDimitry Andric // argument entry. 19617aa51b79SEd Maste arg.push_back(plan_index_arg); 19627aa51b79SEd Maste 19637aa51b79SEd Maste // Push the data for the first argument into the m_arguments vector. 19647aa51b79SEd Maste m_arguments.push_back(arg); 19657aa51b79SEd Maste } 19667aa51b79SEd Maste 19674bb0738eSEd Maste ~CommandObjectThreadPlanDiscard() override = default; 19687aa51b79SEd Maste 1969435933ddSDimitry Andric bool DoExecute(Args &args, CommandReturnObject &result) override { 19707aa51b79SEd Maste Thread *thread = m_exe_ctx.GetThreadPtr(); 1971435933ddSDimitry Andric if (args.GetArgumentCount() != 1) { 1972435933ddSDimitry Andric result.AppendErrorWithFormat("Too many arguments, expected one - the " 1973435933ddSDimitry Andric "thread plan index - but got %zu.", 19747aa51b79SEd Maste args.GetArgumentCount()); 19757aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 19767aa51b79SEd Maste return false; 19777aa51b79SEd Maste } 19787aa51b79SEd Maste 19797aa51b79SEd Maste bool success; 1980435933ddSDimitry Andric uint32_t thread_plan_idx = 1981435933ddSDimitry Andric StringConvert::ToUInt32(args.GetArgumentAtIndex(0), 0, 0, &success); 1982435933ddSDimitry Andric if (!success) { 1983435933ddSDimitry Andric result.AppendErrorWithFormat( 1984435933ddSDimitry Andric "Invalid thread index: \"%s\" - should be unsigned int.", 19857aa51b79SEd Maste args.GetArgumentAtIndex(0)); 19867aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 19877aa51b79SEd Maste return false; 19887aa51b79SEd Maste } 19897aa51b79SEd Maste 1990435933ddSDimitry Andric if (thread_plan_idx == 0) { 1991435933ddSDimitry Andric result.AppendErrorWithFormat( 1992435933ddSDimitry Andric "You wouldn't really want me to discard the base thread plan."); 19937aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 19947aa51b79SEd Maste return false; 19957aa51b79SEd Maste } 19967aa51b79SEd Maste 1997435933ddSDimitry Andric if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) { 19987aa51b79SEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult); 19997aa51b79SEd Maste return true; 2000435933ddSDimitry Andric } else { 2001435933ddSDimitry Andric result.AppendErrorWithFormat( 2002435933ddSDimitry Andric "Could not find User thread plan with index %s.", 20037aa51b79SEd Maste args.GetArgumentAtIndex(0)); 20047aa51b79SEd Maste result.SetStatus(eReturnStatusFailed); 20057aa51b79SEd Maste return false; 20067aa51b79SEd Maste } 20077aa51b79SEd Maste } 20087aa51b79SEd Maste }; 20097aa51b79SEd Maste 20107aa51b79SEd Maste //------------------------------------------------------------------------- 20117aa51b79SEd Maste // CommandObjectMultiwordThreadPlan 20127aa51b79SEd Maste //------------------------------------------------------------------------- 20137aa51b79SEd Maste 2014435933ddSDimitry Andric class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword { 20157aa51b79SEd Maste public: 20164bb0738eSEd Maste CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter) 2017435933ddSDimitry Andric : CommandObjectMultiword( 2018435933ddSDimitry Andric interpreter, "plan", 2019435933ddSDimitry Andric "Commands for managing thread plans that control execution.", 2020435933ddSDimitry Andric "thread plan <subcommand> [<subcommand objects]") { 2021435933ddSDimitry Andric LoadSubCommand( 2022435933ddSDimitry Andric "list", CommandObjectSP(new CommandObjectThreadPlanList(interpreter))); 2023435933ddSDimitry Andric LoadSubCommand( 2024435933ddSDimitry Andric "discard", 2025435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadPlanDiscard(interpreter))); 20267aa51b79SEd Maste } 20277aa51b79SEd Maste 20284bb0738eSEd Maste ~CommandObjectMultiwordThreadPlan() override = default; 20297aa51b79SEd Maste }; 20307aa51b79SEd Maste 20317aa51b79SEd Maste //------------------------------------------------------------------------- 2032ac7ddfbfSEd Maste // CommandObjectMultiwordThread 2033ac7ddfbfSEd Maste //------------------------------------------------------------------------- 2034ac7ddfbfSEd Maste 2035435933ddSDimitry Andric CommandObjectMultiwordThread::CommandObjectMultiwordThread( 2036435933ddSDimitry Andric CommandInterpreter &interpreter) 2037435933ddSDimitry Andric : CommandObjectMultiword(interpreter, "thread", "Commands for operating on " 2038435933ddSDimitry Andric "one or more threads in " 2039435933ddSDimitry Andric "the current process.", 2040435933ddSDimitry Andric "thread <subcommand> [<subcommand-options>]") { 2041435933ddSDimitry Andric LoadSubCommand("backtrace", CommandObjectSP(new CommandObjectThreadBacktrace( 2042435933ddSDimitry Andric interpreter))); 2043435933ddSDimitry Andric LoadSubCommand("continue", 2044435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadContinue(interpreter))); 2045435933ddSDimitry Andric LoadSubCommand("list", 2046435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadList(interpreter))); 2047435933ddSDimitry Andric LoadSubCommand("return", 2048435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadReturn(interpreter))); 2049435933ddSDimitry Andric LoadSubCommand("jump", 2050435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadJump(interpreter))); 2051435933ddSDimitry Andric LoadSubCommand("select", 2052435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadSelect(interpreter))); 2053435933ddSDimitry Andric LoadSubCommand("until", 2054435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadUntil(interpreter))); 2055435933ddSDimitry Andric LoadSubCommand("info", 2056435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadInfo(interpreter))); 20574bb0738eSEd Maste LoadSubCommand("step-in", 20584bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 20594bb0738eSEd Maste interpreter, "thread step-in", 2060435933ddSDimitry Andric "Source level single step, stepping into calls. Defaults " 2061435933ddSDimitry Andric "to current thread unless specified.", 20624bb0738eSEd Maste nullptr, eStepTypeInto, eStepScopeSource))); 2063ac7ddfbfSEd Maste 20644bb0738eSEd Maste LoadSubCommand("step-out", 20654bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 2066435933ddSDimitry Andric interpreter, "thread step-out", 2067435933ddSDimitry Andric "Finish executing the current stack frame and stop after " 20684bb0738eSEd Maste "returning. Defaults to current thread unless specified.", 20694bb0738eSEd Maste nullptr, eStepTypeOut, eStepScopeSource))); 2070ac7ddfbfSEd Maste 20714bb0738eSEd Maste LoadSubCommand("step-over", 20724bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 20734bb0738eSEd Maste interpreter, "thread step-over", 2074435933ddSDimitry Andric "Source level single step, stepping over calls. Defaults " 2075435933ddSDimitry Andric "to current thread unless specified.", 20764bb0738eSEd Maste nullptr, eStepTypeOver, eStepScopeSource))); 2077ac7ddfbfSEd Maste 2078435933ddSDimitry Andric LoadSubCommand("step-inst", 20794bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 20804bb0738eSEd Maste interpreter, "thread step-inst", 2081435933ddSDimitry Andric "Instruction level single step, stepping into calls. " 2082435933ddSDimitry Andric "Defaults to current thread unless specified.", 20834bb0738eSEd Maste nullptr, eStepTypeTrace, eStepScopeInstruction))); 2084ac7ddfbfSEd Maste 2085435933ddSDimitry Andric LoadSubCommand("step-inst-over", 20864bb0738eSEd Maste CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 20874bb0738eSEd Maste interpreter, "thread step-inst-over", 2088435933ddSDimitry Andric "Instruction level single step, stepping over calls. " 2089435933ddSDimitry Andric "Defaults to current thread unless specified.", 20904bb0738eSEd Maste nullptr, eStepTypeTraceOver, eStepScopeInstruction))); 20917aa51b79SEd Maste 2092435933ddSDimitry Andric LoadSubCommand( 2093435933ddSDimitry Andric "step-scripted", 2094435933ddSDimitry Andric CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope( 2095435933ddSDimitry Andric interpreter, "thread step-scripted", 20967aa51b79SEd Maste "Step as instructed by the script class passed in the -C option.", 2097435933ddSDimitry Andric nullptr, eStepTypeScripted, eStepScopeSource))); 20987aa51b79SEd Maste 2099435933ddSDimitry Andric LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan( 2100435933ddSDimitry Andric interpreter))); 2101ac7ddfbfSEd Maste } 2102ac7ddfbfSEd Maste 21034bb0738eSEd Maste CommandObjectMultiwordThread::~CommandObjectMultiwordThread() = default; 2104