2625 lines · cpp
1//===-- CommandObjectThread.cpp -------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "CommandObjectThread.h"10 11#include <memory>12#include <optional>13#include <sstream>14 15#include "CommandObjectThreadUtil.h"16#include "CommandObjectTrace.h"17#include "lldb/Core/PluginManager.h"18#include "lldb/Host/OptionParser.h"19#include "lldb/Interpreter/CommandInterpreter.h"20#include "lldb/Interpreter/CommandOptionArgumentTable.h"21#include "lldb/Interpreter/CommandReturnObject.h"22#include "lldb/Interpreter/OptionArgParser.h"23#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"24#include "lldb/Interpreter/Options.h"25#include "lldb/Symbol/CompileUnit.h"26#include "lldb/Symbol/Function.h"27#include "lldb/Symbol/LineEntry.h"28#include "lldb/Symbol/LineTable.h"29#include "lldb/Target/Process.h"30#include "lldb/Target/RegisterContext.h"31#include "lldb/Target/SystemRuntime.h"32#include "lldb/Target/Target.h"33#include "lldb/Target/Thread.h"34#include "lldb/Target/ThreadPlan.h"35#include "lldb/Target/ThreadPlanStepInRange.h"36#include "lldb/Target/Trace.h"37#include "lldb/Target/TraceDumper.h"38#include "lldb/Utility/State.h"39#include "lldb/ValueObject/ValueObject.h"40 41using namespace lldb;42using namespace lldb_private;43 44// CommandObjectThreadBacktrace45#define LLDB_OPTIONS_thread_backtrace46#include "CommandOptions.inc"47 48class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads {49public:50 class CommandOptions : public Options {51 public:52 CommandOptions() {53 // Keep default values of all options in one place: OptionParsingStarting54 // ()55 OptionParsingStarting(nullptr);56 }57 58 ~CommandOptions() override = default;59 60 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,61 ExecutionContext *execution_context) override {62 Status error;63 const int short_option = m_getopt_table[option_idx].val;64 65 switch (short_option) {66 case 'c':67 if (option_arg.getAsInteger(0, m_count)) {68 m_count = UINT32_MAX;69 error = Status::FromErrorStringWithFormat(70 "invalid integer value for option '%c': %s", short_option,71 option_arg.data());72 }73 // A count of 0 means all frames.74 if (m_count == 0)75 m_count = UINT32_MAX;76 break;77 case 's':78 if (option_arg.getAsInteger(0, m_start))79 error = Status::FromErrorStringWithFormat(80 "invalid integer value for option '%c': %s", short_option,81 option_arg.data());82 break;83 case 'e': {84 bool success;85 m_extended_backtrace =86 OptionArgParser::ToBoolean(option_arg, false, &success);87 if (!success)88 error = Status::FromErrorStringWithFormat(89 "invalid boolean value for option '%c': %s", short_option,90 option_arg.data());91 } break;92 case 'u':93 m_filtered_backtrace = false;94 break;95 default:96 llvm_unreachable("Unimplemented option");97 }98 return error;99 }100 101 void OptionParsingStarting(ExecutionContext *execution_context) override {102 m_count = UINT32_MAX;103 m_start = 0;104 m_extended_backtrace = false;105 m_filtered_backtrace = true;106 }107 108 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {109 return llvm::ArrayRef(g_thread_backtrace_options);110 }111 112 // Instance variables to hold the values for command options.113 uint32_t m_count;114 uint32_t m_start;115 bool m_extended_backtrace;116 bool m_filtered_backtrace;117 };118 119 CommandObjectThreadBacktrace(CommandInterpreter &interpreter)120 : CommandObjectIterateOverThreads(121 interpreter, "thread backtrace",122 "Show backtraces of thread call stacks. Defaults to the current "123 "thread, thread indexes can be specified as arguments.\n"124 "Use the thread-index \"all\" to see all threads.\n"125 "Use the thread-index \"unique\" to see threads grouped by unique "126 "call stacks.\n"127 "Use 'settings set frame-format' to customize the printing of "128 "frames in the backtrace and 'settings set thread-format' to "129 "customize the thread header.\n"130 "Customizable frame recognizers may filter out less interesting "131 "frames, which results in gaps in the numbering. "132 "Use '-u' to see all frames.",133 nullptr,134 eCommandRequiresProcess | eCommandRequiresThread |135 eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |136 eCommandProcessMustBePaused) {}137 138 ~CommandObjectThreadBacktrace() override = default;139 140 Options *GetOptions() override { return &m_options; }141 142 std::optional<std::string> GetRepeatCommand(Args ¤t_args,143 uint32_t index) override {144 llvm::StringRef count_opt("--count");145 llvm::StringRef start_opt("--start");146 147 // If no "count" was provided, we are dumping the entire backtrace, so148 // there isn't a repeat command. So we search for the count option in149 // the args, and if we find it, we make a copy and insert or modify the150 // start option's value to start count indices greater.151 152 Args copy_args(current_args);153 size_t num_entries = copy_args.GetArgumentCount();154 // These two point at the index of the option value if found.155 size_t count_idx = 0;156 size_t start_idx = 0;157 size_t count_val = 0;158 size_t start_val = 0;159 160 for (size_t idx = 0; idx < num_entries; idx++) {161 llvm::StringRef arg_string = copy_args[idx].ref();162 if (arg_string == "-c" || count_opt.starts_with(arg_string)) {163 idx++;164 if (idx == num_entries)165 return std::nullopt;166 count_idx = idx;167 if (copy_args[idx].ref().getAsInteger(0, count_val))168 return std::nullopt;169 } else if (arg_string == "-s" || start_opt.starts_with(arg_string)) {170 idx++;171 if (idx == num_entries)172 return std::nullopt;173 start_idx = idx;174 if (copy_args[idx].ref().getAsInteger(0, start_val))175 return std::nullopt;176 }177 }178 if (count_idx == 0)179 return std::nullopt;180 181 std::string new_start_val = llvm::formatv("{0}", start_val + count_val);182 if (start_idx == 0) {183 copy_args.AppendArgument(start_opt);184 copy_args.AppendArgument(new_start_val);185 } else {186 copy_args.ReplaceArgumentAtIndex(start_idx, new_start_val);187 }188 std::string repeat_command;189 if (!copy_args.GetQuotedCommandString(repeat_command))190 return std::nullopt;191 return repeat_command;192 }193 194protected:195 void DoExtendedBacktrace(Thread *thread, CommandReturnObject &result) {196 SystemRuntime *runtime = thread->GetProcess()->GetSystemRuntime();197 if (runtime) {198 Stream &strm = result.GetOutputStream();199 const std::vector<ConstString> &types =200 runtime->GetExtendedBacktraceTypes();201 for (auto type : types) {202 ThreadSP ext_thread_sp = runtime->GetExtendedBacktraceThread(203 thread->shared_from_this(), type);204 if (ext_thread_sp && ext_thread_sp->IsValid()) {205 const uint32_t num_frames_with_source = 0;206 const bool stop_format = false;207 strm.PutChar('\n');208 if (ext_thread_sp->GetStatus(strm, m_options.m_start,209 m_options.m_count,210 num_frames_with_source, stop_format,211 !m_options.m_filtered_backtrace)) {212 DoExtendedBacktrace(ext_thread_sp.get(), result);213 }214 }215 }216 }217 }218 219 bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {220 ThreadSP thread_sp =221 m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);222 if (!thread_sp) {223 result.AppendErrorWithFormat(224 "thread disappeared while computing backtraces: 0x%" PRIx64 "\n",225 tid);226 return false;227 }228 229 Thread *thread = thread_sp.get();230 231 Stream &strm = result.GetOutputStream();232 233 // Only dump stack info if we processing unique stacks.234 const bool only_stacks = m_unique_stacks;235 236 // Don't show source context when doing backtraces.237 const uint32_t num_frames_with_source = 0;238 const bool stop_format = true;239 if (!thread->GetStatus(strm, m_options.m_start, m_options.m_count,240 num_frames_with_source, stop_format,241 !m_options.m_filtered_backtrace, only_stacks)) {242 result.AppendErrorWithFormat(243 "error displaying backtrace for thread: \"0x%4.4x\"\n",244 thread->GetIndexID());245 return false;246 }247 if (m_options.m_extended_backtrace) {248 if (!INTERRUPT_REQUESTED(GetDebugger(),249 "Interrupt skipped extended backtrace")) {250 DoExtendedBacktrace(thread, result);251 }252 }253 254 return true;255 }256 257 CommandOptions m_options;258};259 260#define LLDB_OPTIONS_thread_step_scope261#include "CommandOptions.inc"262 263class ThreadStepScopeOptionGroup : public OptionGroup {264public:265 ThreadStepScopeOptionGroup() {266 // Keep default values of all options in one place: OptionParsingStarting267 // ()268 OptionParsingStarting(nullptr);269 }270 271 ~ThreadStepScopeOptionGroup() override = default;272 273 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {274 return llvm::ArrayRef(g_thread_step_scope_options);275 }276 277 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,278 ExecutionContext *execution_context) override {279 Status error;280 const int short_option =281 g_thread_step_scope_options[option_idx].short_option;282 283 switch (short_option) {284 case 'a': {285 bool success;286 bool avoid_no_debug =287 OptionArgParser::ToBoolean(option_arg, true, &success);288 if (!success)289 error = Status::FromErrorStringWithFormat(290 "invalid boolean value for option '%c': %s", short_option,291 option_arg.data());292 else {293 m_step_in_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;294 }295 } break;296 297 case 'A': {298 bool success;299 bool avoid_no_debug =300 OptionArgParser::ToBoolean(option_arg, true, &success);301 if (!success)302 error = Status::FromErrorStringWithFormat(303 "invalid boolean value for option '%c': %s", short_option,304 option_arg.data());305 else {306 m_step_out_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo;307 }308 } break;309 310 case 'c':311 if (option_arg.getAsInteger(0, m_step_count))312 error = Status::FromErrorStringWithFormat(313 "invalid integer value for option '%c': %s", short_option,314 option_arg.data());315 break;316 317 case 'm': {318 auto enum_values = GetDefinitions()[option_idx].enum_values;319 m_run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(320 option_arg, enum_values, eOnlyDuringStepping, error);321 } break;322 323 case 'e':324 if (option_arg == "block") {325 m_end_line_is_block_end = true;326 break;327 }328 if (option_arg.getAsInteger(0, m_end_line))329 error = Status::FromErrorStringWithFormat(330 "invalid end line number '%s'", option_arg.str().c_str());331 break;332 333 case 'r':334 m_avoid_regexp.clear();335 m_avoid_regexp.assign(std::string(option_arg));336 break;337 338 case 't':339 m_step_in_target.clear();340 m_step_in_target.assign(std::string(option_arg));341 break;342 343 default:344 llvm_unreachable("Unimplemented option");345 }346 return error;347 }348 349 void OptionParsingStarting(ExecutionContext *execution_context) override {350 m_step_in_avoid_no_debug = eLazyBoolCalculate;351 m_step_out_avoid_no_debug = eLazyBoolCalculate;352 m_run_mode = eOnlyDuringStepping;353 354 // Check if we are in Non-Stop mode355 TargetSP target_sp =356 execution_context ? execution_context->GetTargetSP() : TargetSP();357 ProcessSP process_sp =358 execution_context ? execution_context->GetProcessSP() : ProcessSP();359 if (process_sp && process_sp->GetSteppingRunsAllThreads())360 m_run_mode = eAllThreads;361 362 m_avoid_regexp.clear();363 m_step_in_target.clear();364 m_step_count = 1;365 m_end_line = LLDB_INVALID_LINE_NUMBER;366 m_end_line_is_block_end = false;367 }368 369 // Instance variables to hold the values for command options.370 LazyBool m_step_in_avoid_no_debug;371 LazyBool m_step_out_avoid_no_debug;372 RunMode m_run_mode;373 std::string m_avoid_regexp;374 std::string m_step_in_target;375 uint32_t m_step_count;376 uint32_t m_end_line;377 bool m_end_line_is_block_end;378};379 380class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed {381public:382 CommandObjectThreadStepWithTypeAndScope(CommandInterpreter &interpreter,383 const char *name, const char *help,384 const char *syntax,385 StepType step_type)386 : CommandObjectParsed(interpreter, name, help, syntax,387 eCommandRequiresProcess | eCommandRequiresThread |388 eCommandTryTargetAPILock |389 eCommandProcessMustBeLaunched |390 eCommandProcessMustBePaused),391 m_step_type(step_type), m_class_options("scripted step") {392 AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatOptional);393 394 if (step_type == eStepTypeScripted) {395 m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,396 LLDB_OPT_SET_1);397 }398 m_all_options.Append(&m_options);399 m_all_options.Finalize();400 }401 402 ~CommandObjectThreadStepWithTypeAndScope() override = default;403 404 void405 HandleArgumentCompletion(CompletionRequest &request,406 OptionElementVector &opt_element_vector) override {407 if (request.GetCursorIndex())408 return;409 CommandObject::HandleArgumentCompletion(request, opt_element_vector);410 }411 412 Options *GetOptions() override { return &m_all_options; }413 414protected:415 void DoExecute(Args &command, CommandReturnObject &result) override {416 Process *process = m_exe_ctx.GetProcessPtr();417 bool synchronous_execution = m_interpreter.GetSynchronous();418 419 const uint32_t num_threads = process->GetThreadList().GetSize();420 Thread *thread = nullptr;421 422 if (command.GetArgumentCount() == 0) {423 thread = GetDefaultThread();424 425 if (thread == nullptr) {426 result.AppendError("no selected thread in process");427 return;428 }429 } else {430 const char *thread_idx_cstr = command.GetArgumentAtIndex(0);431 uint32_t step_thread_idx;432 433 if (!llvm::to_integer(thread_idx_cstr, step_thread_idx)) {434 result.AppendErrorWithFormat("invalid thread index '%s'.\n",435 thread_idx_cstr);436 return;437 }438 thread =439 process->GetThreadList().FindThreadByIndexID(step_thread_idx).get();440 if (thread == nullptr) {441 result.AppendErrorWithFormat(442 "Thread index %u is out of range (valid values are 0 - %u).\n",443 step_thread_idx, num_threads);444 return;445 }446 }447 448 if (m_step_type == eStepTypeScripted) {449 if (m_class_options.GetName().empty()) {450 result.AppendErrorWithFormat("empty class name for scripted step.");451 return;452 } else if (!GetDebugger().GetScriptInterpreter()->CheckObjectExists(453 m_class_options.GetName().c_str())) {454 result.AppendErrorWithFormat(455 "class for scripted step: \"%s\" does not exist.",456 m_class_options.GetName().c_str());457 return;458 }459 }460 461 if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER &&462 m_step_type != eStepTypeInto) {463 result.AppendErrorWithFormat(464 "end line option is only valid for step into");465 return;466 }467 468 const bool abort_other_plans = false;469 const lldb::RunMode stop_other_threads = m_options.m_run_mode;470 471 // This is a bit unfortunate, but not all the commands in this command472 // object support only while stepping, so I use the bool for them.473 bool bool_stop_other_threads;474 if (m_options.m_run_mode == eAllThreads)475 bool_stop_other_threads = false;476 else if (m_options.m_run_mode == eOnlyDuringStepping)477 bool_stop_other_threads = (m_step_type != eStepTypeOut);478 else479 bool_stop_other_threads = true;480 481 ThreadPlanSP new_plan_sp;482 Status new_plan_status;483 484 if (m_step_type == eStepTypeInto) {485 StackFrame *frame = thread->GetStackFrameAtIndex(0).get();486 assert(frame != nullptr);487 488 if (frame->HasDebugInformation()) {489 AddressRange range;490 SymbolContext sc = frame->GetSymbolContext(eSymbolContextEverything);491 if (m_options.m_end_line != LLDB_INVALID_LINE_NUMBER) {492 llvm::Error err =493 sc.GetAddressRangeFromHereToEndLine(m_options.m_end_line, range);494 if (err) {495 result.AppendErrorWithFormatv("invalid end-line option: {0}.",496 llvm::toString(std::move(err)));497 return;498 }499 } else if (m_options.m_end_line_is_block_end) {500 Status error;501 Block *block = frame->GetSymbolContext(eSymbolContextBlock).block;502 if (!block) {503 result.AppendErrorWithFormat("Could not find the current block.");504 return;505 }506 507 AddressRange block_range;508 Address pc_address = frame->GetFrameCodeAddress();509 block->GetRangeContainingAddress(pc_address, block_range);510 if (!block_range.GetBaseAddress().IsValid()) {511 result.AppendErrorWithFormat(512 "Could not find the current block address.");513 return;514 }515 lldb::addr_t pc_offset_in_block =516 pc_address.GetFileAddress() -517 block_range.GetBaseAddress().GetFileAddress();518 lldb::addr_t range_length =519 block_range.GetByteSize() - pc_offset_in_block;520 range = AddressRange(pc_address, range_length);521 } else {522 range = sc.line_entry.range;523 }524 525 new_plan_sp = thread->QueueThreadPlanForStepInRange(526 abort_other_plans, range,527 frame->GetSymbolContext(eSymbolContextEverything),528 m_options.m_step_in_target.c_str(), stop_other_threads,529 new_plan_status, m_options.m_step_in_avoid_no_debug,530 m_options.m_step_out_avoid_no_debug);531 532 if (new_plan_sp && !m_options.m_avoid_regexp.empty()) {533 ThreadPlanStepInRange *step_in_range_plan =534 static_cast<ThreadPlanStepInRange *>(new_plan_sp.get());535 step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str());536 }537 } else538 new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(539 false, abort_other_plans, bool_stop_other_threads, new_plan_status);540 } else if (m_step_type == eStepTypeOver) {541 StackFrame *frame = thread->GetStackFrameAtIndex(0).get();542 543 if (frame->HasDebugInformation())544 new_plan_sp = thread->QueueThreadPlanForStepOverRange(545 abort_other_plans,546 frame->GetSymbolContext(eSymbolContextEverything).line_entry,547 frame->GetSymbolContext(eSymbolContextEverything),548 stop_other_threads, new_plan_status,549 m_options.m_step_out_avoid_no_debug);550 else551 new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(552 true, abort_other_plans, bool_stop_other_threads, new_plan_status);553 } else if (m_step_type == eStepTypeTrace) {554 new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(555 false, abort_other_plans, bool_stop_other_threads, new_plan_status);556 } else if (m_step_type == eStepTypeTraceOver) {557 new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction(558 true, abort_other_plans, bool_stop_other_threads, new_plan_status);559 } else if (m_step_type == eStepTypeOut) {560 new_plan_sp = thread->QueueThreadPlanForStepOut(561 abort_other_plans, nullptr, false, bool_stop_other_threads, eVoteYes,562 eVoteNoOpinion,563 thread->GetSelectedFrameIndex(DoNoSelectMostRelevantFrame),564 new_plan_status, m_options.m_step_out_avoid_no_debug);565 } else if (m_step_type == eStepTypeScripted) {566 new_plan_sp = thread->QueueThreadPlanForStepScripted(567 abort_other_plans, m_class_options.GetName().c_str(),568 m_class_options.GetStructuredData(), bool_stop_other_threads,569 new_plan_status);570 } else {571 result.AppendError("step type is not supported");572 return;573 }574 575 // If we got a new plan, then set it to be a controlling plan (User level576 // Plans should be controlling plans so that they can be interruptible).577 // Then resume the process.578 579 if (new_plan_sp) {580 new_plan_sp->SetIsControllingPlan(true);581 new_plan_sp->SetOkayToDiscard(false);582 583 if (m_options.m_step_count > 1) {584 if (!new_plan_sp->SetIterationCount(m_options.m_step_count)) {585 result.AppendWarning(586 "step operation does not support iteration count.");587 }588 }589 590 process->GetThreadList().SetSelectedThreadByID(thread->GetID());591 592 const uint32_t iohandler_id = process->GetIOHandlerID();593 594 StreamString stream;595 Status error;596 if (synchronous_execution)597 error = process->ResumeSynchronous(&stream);598 else599 error = process->Resume();600 601 if (!error.Success()) {602 result.AppendMessage(error.AsCString());603 return;604 }605 606 // There is a race condition where this thread will return up the call607 // stack to the main command handler and show an (lldb) prompt before608 // HandlePrivateEvent (from PrivateStateThread) has a chance to call609 // PushProcessIOHandler().610 process->SyncIOHandler(iohandler_id, std::chrono::seconds(2));611 612 if (synchronous_execution) {613 // If any state changed events had anything to say, add that to the614 // result615 if (stream.GetSize() > 0)616 result.AppendMessage(stream.GetString());617 618 process->GetThreadList().SetSelectedThreadByID(thread->GetID());619 result.SetDidChangeProcessState(true);620 result.SetStatus(eReturnStatusSuccessFinishNoResult);621 } else {622 result.SetStatus(eReturnStatusSuccessContinuingNoResult);623 }624 } else {625 result.SetError(std::move(new_plan_status));626 }627 }628 629 StepType m_step_type;630 ThreadStepScopeOptionGroup m_options;631 OptionGroupPythonClassWithDict m_class_options;632 OptionGroupOptions m_all_options;633};634 635// CommandObjectThreadContinue636 637class CommandObjectThreadContinue : public CommandObjectParsed {638public:639 CommandObjectThreadContinue(CommandInterpreter &interpreter)640 : CommandObjectParsed(641 interpreter, "thread continue",642 "Continue execution of the current target process. One "643 "or more threads may be specified, by default all "644 "threads continue.",645 nullptr,646 eCommandRequiresThread | eCommandTryTargetAPILock |647 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {648 AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatPlus);649 }650 651 ~CommandObjectThreadContinue() override = default;652 653 void DoExecute(Args &command, CommandReturnObject &result) override {654 bool synchronous_execution = m_interpreter.GetSynchronous();655 656 Process *process = m_exe_ctx.GetProcessPtr();657 if (process == nullptr) {658 result.AppendError("no process exists. Cannot continue");659 return;660 }661 662 StateType state = process->GetState();663 if ((state == eStateCrashed) || (state == eStateStopped) ||664 (state == eStateSuspended)) {665 const size_t argc = command.GetArgumentCount();666 if (argc > 0) {667 // These two lines appear at the beginning of both blocks in this668 // if..else, but that is because we need to release the lock before669 // calling process->Resume below.670 std::lock_guard<std::recursive_mutex> guard(671 process->GetThreadList().GetMutex());672 const uint32_t num_threads = process->GetThreadList().GetSize();673 std::vector<Thread *> resume_threads;674 for (auto &entry : command.entries()) {675 uint32_t thread_idx;676 if (entry.ref().getAsInteger(0, thread_idx)) {677 result.AppendErrorWithFormat(678 "invalid thread index argument: \"%s\".\n", entry.c_str());679 return;680 }681 Thread *thread =682 process->GetThreadList().FindThreadByIndexID(thread_idx).get();683 684 if (thread) {685 resume_threads.push_back(thread);686 } else {687 result.AppendErrorWithFormat("invalid thread index %u.\n",688 thread_idx);689 return;690 }691 }692 693 if (resume_threads.empty()) {694 result.AppendError("no valid thread indexes were specified");695 return;696 } else {697 if (resume_threads.size() == 1)698 result.AppendMessageWithFormat("Resuming thread: ");699 else700 result.AppendMessageWithFormat("Resuming threads: ");701 702 for (uint32_t idx = 0; idx < num_threads; ++idx) {703 Thread *thread =704 process->GetThreadList().GetThreadAtIndex(idx).get();705 std::vector<Thread *>::iterator this_thread_pos =706 find(resume_threads.begin(), resume_threads.end(), thread);707 708 if (this_thread_pos != resume_threads.end()) {709 resume_threads.erase(this_thread_pos);710 if (!resume_threads.empty())711 result.AppendMessageWithFormat("%u, ", thread->GetIndexID());712 else713 result.AppendMessageWithFormat("%u ", thread->GetIndexID());714 715 const bool override_suspend = true;716 thread->SetResumeState(eStateRunning, override_suspend);717 } else {718 thread->SetResumeState(eStateSuspended);719 }720 }721 result.AppendMessageWithFormat("in process %" PRIu64 "\n",722 process->GetID());723 }724 } else {725 // These two lines appear at the beginning of both blocks in this726 // if..else, but that is because we need to release the lock before727 // calling process->Resume below.728 std::lock_guard<std::recursive_mutex> guard(729 process->GetThreadList().GetMutex());730 const uint32_t num_threads = process->GetThreadList().GetSize();731 Thread *current_thread = GetDefaultThread();732 if (current_thread == nullptr) {733 result.AppendError("the process doesn't have a current thread");734 return;735 }736 // Set the actions that the threads should each take when resuming737 for (uint32_t idx = 0; idx < num_threads; ++idx) {738 Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();739 if (thread == current_thread) {740 result.AppendMessageWithFormat("Resuming thread 0x%4.4" PRIx64741 " in process %" PRIu64 "\n",742 thread->GetID(), process->GetID());743 const bool override_suspend = true;744 thread->SetResumeState(eStateRunning, override_suspend);745 } else {746 thread->SetResumeState(eStateSuspended);747 }748 }749 }750 751 StreamString stream;752 Status error;753 if (synchronous_execution)754 error = process->ResumeSynchronous(&stream);755 else756 error = process->Resume();757 758 // We should not be holding the thread list lock when we do this.759 if (error.Success()) {760 result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",761 process->GetID());762 if (synchronous_execution) {763 // If any state changed events had anything to say, add that to the764 // result765 if (stream.GetSize() > 0)766 result.AppendMessage(stream.GetString());767 768 result.SetDidChangeProcessState(true);769 result.SetStatus(eReturnStatusSuccessFinishNoResult);770 } else {771 result.SetStatus(eReturnStatusSuccessContinuingNoResult);772 }773 } else {774 result.AppendErrorWithFormat("Failed to resume process: %s\n",775 error.AsCString());776 }777 } else {778 result.AppendErrorWithFormat(779 "Process cannot be continued from its current state (%s).\n",780 StateAsCString(state));781 }782 }783};784 785// CommandObjectThreadUntil786 787#define LLDB_OPTIONS_thread_until788#include "CommandOptions.inc"789 790class CommandObjectThreadUntil : public CommandObjectParsed {791public:792 class CommandOptions : public Options {793 public:794 uint32_t m_thread_idx = LLDB_INVALID_THREAD_ID;795 uint32_t m_frame_idx = LLDB_INVALID_FRAME_ID;796 797 CommandOptions() {798 // Keep default values of all options in one place: OptionParsingStarting799 // ()800 OptionParsingStarting(nullptr);801 }802 803 ~CommandOptions() override = default;804 805 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,806 ExecutionContext *execution_context) override {807 Status error;808 const int short_option = m_getopt_table[option_idx].val;809 810 switch (short_option) {811 case 'a': {812 lldb::addr_t tmp_addr = OptionArgParser::ToAddress(813 execution_context, option_arg, LLDB_INVALID_ADDRESS, &error);814 if (error.Success())815 m_until_addrs.push_back(tmp_addr);816 } break;817 case 't':818 if (option_arg.getAsInteger(0, m_thread_idx)) {819 m_thread_idx = LLDB_INVALID_INDEX32;820 error = Status::FromErrorStringWithFormat("invalid thread index '%s'",821 option_arg.str().c_str());822 }823 break;824 case 'f':825 if (option_arg.getAsInteger(0, m_frame_idx)) {826 m_frame_idx = LLDB_INVALID_FRAME_ID;827 error = Status::FromErrorStringWithFormat("invalid frame index '%s'",828 option_arg.str().c_str());829 }830 break;831 case 'm': {832 auto enum_values = GetDefinitions()[option_idx].enum_values;833 lldb::RunMode run_mode = (lldb::RunMode)OptionArgParser::ToOptionEnum(834 option_arg, enum_values, eOnlyDuringStepping, error);835 836 if (error.Success()) {837 if (run_mode == eAllThreads)838 m_stop_others = false;839 else840 m_stop_others = true;841 }842 } break;843 default:844 llvm_unreachable("Unimplemented option");845 }846 return error;847 }848 849 void OptionParsingStarting(ExecutionContext *execution_context) override {850 m_thread_idx = LLDB_INVALID_THREAD_ID;851 m_frame_idx = 0;852 m_stop_others = false;853 m_until_addrs.clear();854 }855 856 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {857 return llvm::ArrayRef(g_thread_until_options);858 }859 860 uint32_t m_step_thread_idx = LLDB_INVALID_THREAD_ID;861 bool m_stop_others = false;862 std::vector<lldb::addr_t> m_until_addrs;863 864 // Instance variables to hold the values for command options.865 };866 867 CommandObjectThreadUntil(CommandInterpreter &interpreter)868 : CommandObjectParsed(869 interpreter, "thread until",870 "Continue until a line number or address is reached by the "871 "current or specified thread. Stops when returning from "872 "the current function as a safety measure. "873 "The target line number(s) are given as arguments, and if more "874 "than one"875 " is provided, stepping will stop when the first one is hit.",876 nullptr,877 eCommandRequiresThread | eCommandTryTargetAPILock |878 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {879 AddSimpleArgumentList(eArgTypeLineNum);880 }881 882 ~CommandObjectThreadUntil() override = default;883 884 Options *GetOptions() override { return &m_options; }885 886protected:887 void DoExecute(Args &command, CommandReturnObject &result) override {888 bool synchronous_execution = m_interpreter.GetSynchronous();889 890 Target *target = &GetTarget();891 892 Process *process = m_exe_ctx.GetProcessPtr();893 if (process == nullptr) {894 result.AppendError("need a valid process to step");895 } else {896 Thread *thread = nullptr;897 std::vector<uint32_t> line_numbers;898 899 if (command.GetArgumentCount() >= 1) {900 size_t num_args = command.GetArgumentCount();901 for (size_t i = 0; i < num_args; i++) {902 uint32_t line_number;903 if (!llvm::to_integer(command.GetArgumentAtIndex(i), line_number)) {904 result.AppendErrorWithFormat("invalid line number: '%s'.\n",905 command.GetArgumentAtIndex(i));906 return;907 } else908 line_numbers.push_back(line_number);909 }910 } else if (m_options.m_until_addrs.empty()) {911 result.AppendErrorWithFormat("No line number or address provided:\n%s",912 GetSyntax().str().c_str());913 return;914 }915 916 if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) {917 thread = GetDefaultThread();918 } else {919 thread = process->GetThreadList()920 .FindThreadByIndexID(m_options.m_thread_idx)921 .get();922 }923 924 if (thread == nullptr) {925 const uint32_t num_threads = process->GetThreadList().GetSize();926 result.AppendErrorWithFormat(927 "Thread index %u is out of range (valid values are 0 - %u).\n",928 m_options.m_thread_idx, num_threads);929 return;930 }931 932 const bool abort_other_plans = false;933 934 StackFrame *frame =935 thread->GetStackFrameAtIndex(m_options.m_frame_idx).get();936 if (frame == nullptr) {937 result.AppendErrorWithFormat(938 "Frame index %u is out of range for thread id %" PRIu64 ".\n",939 m_options.m_frame_idx, thread->GetID());940 return;941 }942 943 ThreadPlanSP new_plan_sp;944 Status new_plan_status;945 946 if (frame->HasDebugInformation()) {947 // Finally we got here... Translate the given line number to a bunch948 // of addresses:949 SymbolContext sc(frame->GetSymbolContext(eSymbolContextCompUnit));950 LineTable *line_table = nullptr;951 if (sc.comp_unit)952 line_table = sc.comp_unit->GetLineTable();953 954 if (line_table == nullptr) {955 result.AppendErrorWithFormat("Failed to resolve the line table for "956 "frame %u of thread id %" PRIu64 ".\n",957 m_options.m_frame_idx, thread->GetID());958 return;959 }960 961 LineEntry function_start;962 std::vector<addr_t> address_list;963 964 // Find the beginning & end index of the function, but first make965 // sure it is valid:966 if (!sc.function) {967 result.AppendErrorWithFormat("Have debug information but no "968 "function info - can't get until range.");969 return;970 }971 972 RangeVector<uint32_t, uint32_t> line_idx_ranges;973 for (const AddressRange &range : sc.function->GetAddressRanges()) {974 auto [begin, end] = line_table->GetLineEntryIndexRange(range);975 line_idx_ranges.Append(begin, end - begin);976 }977 line_idx_ranges.Sort();978 979 bool found_something = false;980 981 // Since not all source lines will contribute code, check if we are982 // setting the breakpoint on the exact line number or the nearest983 // subsequent line number and set breakpoints at all the line table984 // entries of the chosen line number (exact or nearest subsequent).985 for (uint32_t line_number : line_numbers) {986 LineEntry line_entry;987 bool exact = false;988 if (sc.comp_unit->FindLineEntry(0, line_number, nullptr, exact,989 &line_entry) == UINT32_MAX)990 continue;991 992 found_something = true;993 line_number = line_entry.line;994 exact = true;995 uint32_t end_func_idx = line_idx_ranges.GetMaxRangeEnd(0);996 uint32_t idx = sc.comp_unit->FindLineEntry(997 line_idx_ranges.GetMinRangeBase(UINT32_MAX), line_number, nullptr,998 exact, &line_entry);999 while (idx < end_func_idx) {1000 if (line_idx_ranges.FindEntryIndexThatContains(idx) != UINT32_MAX) {1001 addr_t address =1002 line_entry.range.GetBaseAddress().GetLoadAddress(target);1003 if (address != LLDB_INVALID_ADDRESS)1004 address_list.push_back(address);1005 }1006 idx = sc.comp_unit->FindLineEntry(idx + 1, line_number, nullptr,1007 exact, &line_entry);1008 }1009 }1010 1011 for (lldb::addr_t address : m_options.m_until_addrs) {1012 AddressRange unused;1013 if (sc.function->GetRangeContainingLoadAddress(address, *target,1014 unused))1015 address_list.push_back(address);1016 }1017 1018 if (address_list.empty()) {1019 if (found_something)1020 result.AppendErrorWithFormat(1021 "Until target outside of the current function.\n");1022 else1023 result.AppendErrorWithFormat(1024 "No line entries matching until target.\n");1025 1026 return;1027 }1028 1029 new_plan_sp = thread->QueueThreadPlanForStepUntil(1030 abort_other_plans, &address_list.front(), address_list.size(),1031 m_options.m_stop_others, m_options.m_frame_idx, new_plan_status);1032 if (new_plan_sp) {1033 // User level plans should be controlling plans so they can be1034 // interrupted1035 // (e.g. by hitting a breakpoint) and other plans executed by the1036 // user (stepping around the breakpoint) and then a "continue" will1037 // resume the original plan.1038 new_plan_sp->SetIsControllingPlan(true);1039 new_plan_sp->SetOkayToDiscard(false);1040 } else {1041 result.SetError(std::move(new_plan_status));1042 return;1043 }1044 } else {1045 result.AppendErrorWithFormat("Frame index %u of thread id %" PRIu641046 " has no debug information.\n",1047 m_options.m_frame_idx, thread->GetID());1048 return;1049 }1050 1051 if (!process->GetThreadList().SetSelectedThreadByID(thread->GetID())) {1052 result.AppendErrorWithFormat(1053 "Failed to set the selected thread to thread id %" PRIu64 ".\n",1054 thread->GetID());1055 return;1056 }1057 1058 StreamString stream;1059 Status error;1060 if (synchronous_execution)1061 error = process->ResumeSynchronous(&stream);1062 else1063 error = process->Resume();1064 1065 if (error.Success()) {1066 result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",1067 process->GetID());1068 if (synchronous_execution) {1069 // If any state changed events had anything to say, add that to the1070 // result1071 if (stream.GetSize() > 0)1072 result.AppendMessage(stream.GetString());1073 1074 result.SetDidChangeProcessState(true);1075 result.SetStatus(eReturnStatusSuccessFinishNoResult);1076 } else {1077 result.SetStatus(eReturnStatusSuccessContinuingNoResult);1078 }1079 } else {1080 result.AppendErrorWithFormat("Failed to resume process: %s.\n",1081 error.AsCString());1082 }1083 }1084 }1085 1086 CommandOptions m_options;1087};1088 1089// CommandObjectThreadSelect1090 1091#define LLDB_OPTIONS_thread_select1092#include "CommandOptions.inc"1093 1094class CommandObjectThreadSelect : public CommandObjectParsed {1095public:1096 class OptionGroupThreadSelect : public OptionGroup {1097 public:1098 OptionGroupThreadSelect() { OptionParsingStarting(nullptr); }1099 1100 ~OptionGroupThreadSelect() override = default;1101 1102 void OptionParsingStarting(ExecutionContext *execution_context) override {1103 m_thread_id = LLDB_INVALID_THREAD_ID;1104 }1105 1106 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1107 ExecutionContext *execution_context) override {1108 const int short_option = g_thread_select_options[option_idx].short_option;1109 switch (short_option) {1110 case 't': {1111 if (option_arg.getAsInteger(0, m_thread_id)) {1112 m_thread_id = LLDB_INVALID_THREAD_ID;1113 return Status::FromErrorStringWithFormat("Invalid thread ID: '%s'.",1114 option_arg.str().c_str());1115 }1116 break;1117 }1118 1119 default:1120 llvm_unreachable("Unimplemented option");1121 }1122 1123 return {};1124 }1125 1126 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1127 return llvm::ArrayRef(g_thread_select_options);1128 }1129 1130 lldb::tid_t m_thread_id;1131 };1132 1133 CommandObjectThreadSelect(CommandInterpreter &interpreter)1134 : CommandObjectParsed(interpreter, "thread select",1135 "Change the currently selected thread.",1136 "thread select <thread-index> (or -t <thread-id>)",1137 eCommandRequiresProcess | eCommandTryTargetAPILock |1138 eCommandProcessMustBeLaunched |1139 eCommandProcessMustBePaused) {1140 CommandArgumentEntry arg;1141 CommandArgumentData thread_idx_arg;1142 1143 // Define the first (and only) variant of this arg.1144 thread_idx_arg.arg_type = eArgTypeThreadIndex;1145 thread_idx_arg.arg_repetition = eArgRepeatPlain;1146 thread_idx_arg.arg_opt_set_association = LLDB_OPT_SET_1;1147 1148 // There is only one variant this argument could be; put it into the1149 // argument entry.1150 arg.push_back(thread_idx_arg);1151 1152 // Push the data for the first argument into the m_arguments vector.1153 m_arguments.push_back(arg);1154 1155 m_option_group.Append(&m_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);1156 m_option_group.Finalize();1157 }1158 1159 ~CommandObjectThreadSelect() override = default;1160 1161 void1162 HandleArgumentCompletion(CompletionRequest &request,1163 OptionElementVector &opt_element_vector) override {1164 if (request.GetCursorIndex())1165 return;1166 1167 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1168 GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,1169 nullptr);1170 }1171 1172 Options *GetOptions() override { return &m_option_group; }1173 1174protected:1175 void DoExecute(Args &command, CommandReturnObject &result) override {1176 Process *process = m_exe_ctx.GetProcessPtr();1177 if (process == nullptr) {1178 result.AppendError("no process");1179 return;1180 } else if (m_options.m_thread_id == LLDB_INVALID_THREAD_ID &&1181 command.GetArgumentCount() != 1) {1182 result.AppendErrorWithFormat(1183 "'%s' takes exactly one thread index argument, or a thread ID "1184 "option:\nUsage: %s\n",1185 m_cmd_name.c_str(), m_cmd_syntax.c_str());1186 return;1187 } else if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID &&1188 command.GetArgumentCount() != 0) {1189 result.AppendErrorWithFormat("'%s' cannot take both a thread ID option "1190 "and a thread index argument:\nUsage: %s\n",1191 m_cmd_name.c_str(), m_cmd_syntax.c_str());1192 return;1193 }1194 1195 Thread *new_thread = nullptr;1196 if (command.GetArgumentCount() == 1) {1197 uint32_t index_id;1198 if (!llvm::to_integer(command.GetArgumentAtIndex(0), index_id)) {1199 result.AppendErrorWithFormat("Invalid thread index '%s'",1200 command.GetArgumentAtIndex(0));1201 return;1202 }1203 new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get();1204 if (new_thread == nullptr) {1205 result.AppendErrorWithFormat("Invalid thread index #%s.\n",1206 command.GetArgumentAtIndex(0));1207 return;1208 }1209 } else {1210 new_thread =1211 process->GetThreadList().FindThreadByID(m_options.m_thread_id).get();1212 if (new_thread == nullptr) {1213 result.AppendErrorWithFormat("Invalid thread ID %" PRIu64 ".\n",1214 m_options.m_thread_id);1215 return;1216 }1217 }1218 1219 process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true);1220 result.SetStatus(eReturnStatusSuccessFinishNoResult);1221 }1222 1223 OptionGroupThreadSelect m_options;1224 OptionGroupOptions m_option_group;1225};1226 1227// CommandObjectThreadList1228 1229class CommandObjectThreadList : public CommandObjectParsed {1230public:1231 CommandObjectThreadList(CommandInterpreter &interpreter)1232 : CommandObjectParsed(1233 interpreter, "thread list",1234 "Show a summary of each thread in the current target process. "1235 "Use 'settings set thread-format' to customize the individual "1236 "thread listings.",1237 "thread list",1238 eCommandRequiresProcess | eCommandTryTargetAPILock |1239 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}1240 1241 ~CommandObjectThreadList() override = default;1242 1243protected:1244 void DoExecute(Args &command, CommandReturnObject &result) override {1245 Stream &strm = result.GetOutputStream();1246 result.SetStatus(eReturnStatusSuccessFinishNoResult);1247 Process *process = m_exe_ctx.GetProcessPtr();1248 const bool only_threads_with_stop_reason = false;1249 const uint32_t start_frame = 0;1250 const uint32_t num_frames = 0;1251 const uint32_t num_frames_with_source = 0;1252 process->GetStatus(strm);1253 process->GetThreadStatus(strm, only_threads_with_stop_reason, start_frame,1254 num_frames, num_frames_with_source, false);1255 }1256};1257 1258// CommandObjectThreadInfo1259#define LLDB_OPTIONS_thread_info1260#include "CommandOptions.inc"1261 1262class CommandObjectThreadInfo : public CommandObjectIterateOverThreads {1263public:1264 class CommandOptions : public Options {1265 public:1266 CommandOptions() { OptionParsingStarting(nullptr); }1267 1268 ~CommandOptions() override = default;1269 1270 void OptionParsingStarting(ExecutionContext *execution_context) override {1271 m_json_thread = false;1272 m_json_stopinfo = false;1273 m_backing_thread = false;1274 }1275 1276 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1277 ExecutionContext *execution_context) override {1278 const int short_option = m_getopt_table[option_idx].val;1279 Status error;1280 1281 switch (short_option) {1282 case 'j':1283 m_json_thread = true;1284 break;1285 1286 case 's':1287 m_json_stopinfo = true;1288 break;1289 1290 case 'b':1291 m_backing_thread = true;1292 break;1293 1294 default:1295 llvm_unreachable("Unimplemented option");1296 }1297 return error;1298 }1299 1300 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1301 return llvm::ArrayRef(g_thread_info_options);1302 }1303 1304 bool m_json_thread;1305 bool m_json_stopinfo;1306 bool m_backing_thread;1307 };1308 1309 CommandObjectThreadInfo(CommandInterpreter &interpreter)1310 : CommandObjectIterateOverThreads(1311 interpreter, "thread info",1312 "Show an extended summary of one or "1313 "more threads. Defaults to the "1314 "current thread.",1315 "thread info",1316 eCommandRequiresProcess | eCommandTryTargetAPILock |1317 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {1318 m_add_return = false;1319 }1320 1321 ~CommandObjectThreadInfo() override = default;1322 1323 void1324 HandleArgumentCompletion(CompletionRequest &request,1325 OptionElementVector &opt_element_vector) override {1326 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1327 GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,1328 nullptr);1329 }1330 1331 Options *GetOptions() override { return &m_options; }1332 1333 bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {1334 ThreadSP thread_sp =1335 m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);1336 if (!thread_sp) {1337 result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",1338 tid);1339 return false;1340 }1341 1342 Thread *thread = thread_sp.get();1343 if (m_options.m_backing_thread && thread->GetBackingThread())1344 thread = thread->GetBackingThread().get();1345 1346 Stream &strm = result.GetOutputStream();1347 if (!thread->GetDescription(strm, eDescriptionLevelFull,1348 m_options.m_json_thread,1349 m_options.m_json_stopinfo)) {1350 result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n",1351 thread->GetIndexID());1352 return false;1353 }1354 return true;1355 }1356 1357 CommandOptions m_options;1358};1359 1360// CommandObjectThreadException1361 1362class CommandObjectThreadException : public CommandObjectIterateOverThreads {1363public:1364 CommandObjectThreadException(CommandInterpreter &interpreter)1365 : CommandObjectIterateOverThreads(1366 interpreter, "thread exception",1367 "Display the current exception object for a thread. Defaults to "1368 "the current thread.",1369 "thread exception",1370 eCommandRequiresProcess | eCommandTryTargetAPILock |1371 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}1372 1373 ~CommandObjectThreadException() override = default;1374 1375 void1376 HandleArgumentCompletion(CompletionRequest &request,1377 OptionElementVector &opt_element_vector) override {1378 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1379 GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,1380 nullptr);1381 }1382 1383 bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {1384 ThreadSP thread_sp =1385 m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);1386 if (!thread_sp) {1387 result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",1388 tid);1389 return false;1390 }1391 1392 Stream &strm = result.GetOutputStream();1393 ValueObjectSP exception_object_sp = thread_sp->GetCurrentException();1394 if (exception_object_sp) {1395 if (llvm::Error error = exception_object_sp->Dump(strm)) {1396 result.AppendError(toString(std::move(error)));1397 return false;1398 }1399 }1400 1401 ThreadSP exception_thread_sp = thread_sp->GetCurrentExceptionBacktrace();1402 if (exception_thread_sp && exception_thread_sp->IsValid()) {1403 const uint32_t num_frames_with_source = 0;1404 const bool stop_format = false;1405 exception_thread_sp->GetStatus(strm, 0, UINT32_MAX,1406 num_frames_with_source, stop_format,1407 /*filtered*/ false);1408 }1409 1410 return true;1411 }1412};1413 1414class CommandObjectThreadSiginfo : public CommandObjectIterateOverThreads {1415public:1416 CommandObjectThreadSiginfo(CommandInterpreter &interpreter)1417 : CommandObjectIterateOverThreads(1418 interpreter, "thread siginfo",1419 "Display the current siginfo object for a thread. Defaults to "1420 "the current thread.",1421 "thread siginfo",1422 eCommandRequiresProcess | eCommandTryTargetAPILock |1423 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}1424 1425 ~CommandObjectThreadSiginfo() override = default;1426 1427 void1428 HandleArgumentCompletion(CompletionRequest &request,1429 OptionElementVector &opt_element_vector) override {1430 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1431 GetCommandInterpreter(), lldb::eThreadIndexCompletion, request,1432 nullptr);1433 }1434 1435 bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {1436 ThreadSP thread_sp =1437 m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);1438 if (!thread_sp) {1439 result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n",1440 tid);1441 return false;1442 }1443 1444 Stream &strm = result.GetOutputStream();1445 if (!thread_sp->GetDescription(strm, eDescriptionLevelFull, false, false)) {1446 result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n",1447 thread_sp->GetIndexID());1448 return false;1449 }1450 ValueObjectSP exception_object_sp = thread_sp->GetSiginfoValue();1451 if (exception_object_sp) {1452 if (llvm::Error error = exception_object_sp->Dump(strm)) {1453 result.AppendError(toString(std::move(error)));1454 return false;1455 }1456 } else1457 strm.Printf("(no siginfo)\n");1458 strm.PutChar('\n');1459 1460 return true;1461 }1462};1463 1464// CommandObjectThreadReturn1465#define LLDB_OPTIONS_thread_return1466#include "CommandOptions.inc"1467 1468class CommandObjectThreadReturn : public CommandObjectRaw {1469public:1470 class CommandOptions : public Options {1471 public:1472 CommandOptions() {1473 // Keep default values of all options in one place: OptionParsingStarting1474 // ()1475 OptionParsingStarting(nullptr);1476 }1477 1478 ~CommandOptions() override = default;1479 1480 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1481 ExecutionContext *execution_context) override {1482 Status error;1483 const int short_option = m_getopt_table[option_idx].val;1484 1485 switch (short_option) {1486 case 'x': {1487 bool success;1488 bool tmp_value =1489 OptionArgParser::ToBoolean(option_arg, false, &success);1490 if (success)1491 m_from_expression = tmp_value;1492 else {1493 error = Status::FromErrorStringWithFormat(1494 "invalid boolean value '%s' for 'x' option",1495 option_arg.str().c_str());1496 }1497 } break;1498 default:1499 llvm_unreachable("Unimplemented option");1500 }1501 return error;1502 }1503 1504 void OptionParsingStarting(ExecutionContext *execution_context) override {1505 m_from_expression = false;1506 }1507 1508 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1509 return llvm::ArrayRef(g_thread_return_options);1510 }1511 1512 bool m_from_expression = false;1513 1514 // Instance variables to hold the values for command options.1515 };1516 1517 CommandObjectThreadReturn(CommandInterpreter &interpreter)1518 : CommandObjectRaw(interpreter, "thread return",1519 "Prematurely return from a stack frame, "1520 "short-circuiting execution of newer frames "1521 "and optionally yielding a specified value. Defaults "1522 "to the exiting the current stack "1523 "frame.",1524 "thread return",1525 eCommandRequiresFrame | eCommandTryTargetAPILock |1526 eCommandProcessMustBeLaunched |1527 eCommandProcessMustBePaused) {1528 AddSimpleArgumentList(eArgTypeExpression, eArgRepeatOptional);1529 }1530 1531 ~CommandObjectThreadReturn() override = default;1532 1533 Options *GetOptions() override { return &m_options; }1534 1535protected:1536 void DoExecute(llvm::StringRef command,1537 CommandReturnObject &result) override {1538 // I am going to handle this by hand, because I don't want you to have to1539 // say:1540 // "thread return -- -5".1541 if (command.starts_with("-x")) {1542 if (command.size() != 2U)1543 result.AppendWarning("Return values ignored when returning from user "1544 "called expressions");1545 1546 Thread *thread = m_exe_ctx.GetThreadPtr();1547 Status error;1548 error = thread->UnwindInnermostExpression();1549 if (!error.Success()) {1550 result.AppendErrorWithFormat("Unwinding expression failed - %s.",1551 error.AsCString());1552 } else {1553 bool success =1554 thread->SetSelectedFrameByIndexNoisily(0, result.GetOutputStream());1555 if (success) {1556 m_exe_ctx.SetFrameSP(1557 thread->GetSelectedFrame(DoNoSelectMostRelevantFrame));1558 result.SetStatus(eReturnStatusSuccessFinishResult);1559 } else {1560 result.AppendErrorWithFormat(1561 "Could not select 0th frame after unwinding expression.");1562 }1563 }1564 return;1565 }1566 1567 ValueObjectSP return_valobj_sp;1568 1569 StackFrameSP frame_sp = m_exe_ctx.GetFrameSP();1570 uint32_t frame_idx = frame_sp->GetFrameIndex();1571 1572 if (frame_sp->IsInlined()) {1573 result.AppendError("don't know how to return from inlined frames");1574 return;1575 }1576 1577 if (!command.empty()) {1578 Target *target = m_exe_ctx.GetTargetPtr();1579 EvaluateExpressionOptions options;1580 1581 options.SetUnwindOnError(true);1582 options.SetUseDynamic(eNoDynamicValues);1583 1584 ExpressionResults exe_results = eExpressionSetupError;1585 exe_results = target->EvaluateExpression(command, frame_sp.get(),1586 return_valobj_sp, options);1587 if (exe_results != eExpressionCompleted) {1588 if (return_valobj_sp)1589 result.AppendErrorWithFormat(1590 "Error evaluating result expression: %s",1591 return_valobj_sp->GetError().AsCString());1592 else1593 result.AppendErrorWithFormat(1594 "Unknown error evaluating result expression.");1595 return;1596 }1597 }1598 1599 Status error;1600 ThreadSP thread_sp = m_exe_ctx.GetThreadSP();1601 const bool broadcast = true;1602 error = thread_sp->ReturnFromFrame(frame_sp, return_valobj_sp, broadcast);1603 if (!error.Success()) {1604 result.AppendErrorWithFormat(1605 "Error returning from frame %d of thread %d: %s.", frame_idx,1606 thread_sp->GetIndexID(), error.AsCString());1607 return;1608 }1609 1610 result.SetStatus(eReturnStatusSuccessFinishResult);1611 }1612 1613 CommandOptions m_options;1614};1615 1616// CommandObjectThreadJump1617#define LLDB_OPTIONS_thread_jump1618#include "CommandOptions.inc"1619 1620class CommandObjectThreadJump : public CommandObjectParsed {1621public:1622 class CommandOptions : public Options {1623 public:1624 CommandOptions() { OptionParsingStarting(nullptr); }1625 1626 ~CommandOptions() override = default;1627 1628 void OptionParsingStarting(ExecutionContext *execution_context) override {1629 m_filenames.Clear();1630 m_line_num = 0;1631 m_line_offset = 0;1632 m_load_addr = LLDB_INVALID_ADDRESS;1633 m_force = false;1634 }1635 1636 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1637 ExecutionContext *execution_context) override {1638 const int short_option = m_getopt_table[option_idx].val;1639 Status error;1640 1641 switch (short_option) {1642 case 'f':1643 m_filenames.AppendIfUnique(FileSpec(option_arg));1644 if (m_filenames.GetSize() > 1)1645 return Status::FromErrorString("only one source file expected.");1646 break;1647 case 'l':1648 if (option_arg.getAsInteger(0, m_line_num))1649 return Status::FromErrorStringWithFormat("invalid line number: '%s'.",1650 option_arg.str().c_str());1651 break;1652 case 'b': {1653 option_arg.consume_front("+");1654 1655 if (option_arg.getAsInteger(0, m_line_offset))1656 return Status::FromErrorStringWithFormat("invalid line offset: '%s'.",1657 option_arg.str().c_str());1658 break;1659 }1660 case 'a':1661 m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg,1662 LLDB_INVALID_ADDRESS, &error);1663 break;1664 case 'r':1665 m_force = true;1666 break;1667 default:1668 llvm_unreachable("Unimplemented option");1669 }1670 return error;1671 }1672 1673 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1674 return llvm::ArrayRef(g_thread_jump_options);1675 }1676 1677 FileSpecList m_filenames;1678 uint32_t m_line_num;1679 int32_t m_line_offset;1680 lldb::addr_t m_load_addr;1681 bool m_force;1682 };1683 1684 CommandObjectThreadJump(CommandInterpreter &interpreter)1685 : CommandObjectParsed(1686 interpreter, "thread jump",1687 "Sets the program counter to a new address.", "thread jump",1688 eCommandRequiresFrame | eCommandTryTargetAPILock |1689 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}1690 1691 ~CommandObjectThreadJump() override = default;1692 1693 Options *GetOptions() override { return &m_options; }1694 1695protected:1696 void DoExecute(Args &args, CommandReturnObject &result) override {1697 RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();1698 StackFrame *frame = m_exe_ctx.GetFramePtr();1699 Thread *thread = m_exe_ctx.GetThreadPtr();1700 Target *target = m_exe_ctx.GetTargetPtr();1701 const SymbolContext &sym_ctx =1702 frame->GetSymbolContext(eSymbolContextLineEntry);1703 1704 if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) {1705 // Use this address directly.1706 Address dest = Address(m_options.m_load_addr);1707 1708 lldb::addr_t callAddr = dest.GetCallableLoadAddress(target);1709 if (callAddr == LLDB_INVALID_ADDRESS) {1710 result.AppendErrorWithFormat("Invalid destination address.");1711 return;1712 }1713 1714 if (!reg_ctx->SetPC(callAddr)) {1715 result.AppendErrorWithFormat("Error changing PC value for thread %d.",1716 thread->GetIndexID());1717 return;1718 }1719 } else {1720 // Pick either the absolute line, or work out a relative one.1721 int32_t line = (int32_t)m_options.m_line_num;1722 if (line == 0)1723 line = sym_ctx.line_entry.line + m_options.m_line_offset;1724 1725 // Try the current file, but override if asked.1726 FileSpec file = sym_ctx.line_entry.GetFile();1727 if (m_options.m_filenames.GetSize() == 1)1728 file = m_options.m_filenames.GetFileSpecAtIndex(0);1729 1730 if (!file) {1731 result.AppendErrorWithFormat(1732 "No source file available for the current location.");1733 return;1734 }1735 1736 std::string warnings;1737 Status err = thread->JumpToLine(file, line, m_options.m_force, &warnings);1738 1739 if (err.Fail()) {1740 result.SetError(std::move(err));1741 return;1742 }1743 1744 if (!warnings.empty())1745 result.AppendWarning(warnings.c_str());1746 }1747 1748 result.SetStatus(eReturnStatusSuccessFinishResult);1749 }1750 1751 CommandOptions m_options;1752};1753 1754// Next are the subcommands of CommandObjectMultiwordThreadPlan1755 1756// CommandObjectThreadPlanList1757#define LLDB_OPTIONS_thread_plan_list1758#include "CommandOptions.inc"1759 1760class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads {1761public:1762 class CommandOptions : public Options {1763 public:1764 CommandOptions() {1765 // Keep default values of all options in one place: OptionParsingStarting1766 // ()1767 OptionParsingStarting(nullptr);1768 }1769 1770 ~CommandOptions() override = default;1771 1772 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1773 ExecutionContext *execution_context) override {1774 const int short_option = m_getopt_table[option_idx].val;1775 1776 switch (short_option) {1777 case 'i':1778 m_internal = true;1779 break;1780 case 't':1781 lldb::tid_t tid;1782 if (option_arg.getAsInteger(0, tid))1783 return Status::FromErrorStringWithFormat("invalid tid: '%s'.",1784 option_arg.str().c_str());1785 m_tids.push_back(tid);1786 break;1787 case 'u':1788 m_unreported = false;1789 break;1790 case 'v':1791 m_verbose = true;1792 break;1793 default:1794 llvm_unreachable("Unimplemented option");1795 }1796 return {};1797 }1798 1799 void OptionParsingStarting(ExecutionContext *execution_context) override {1800 m_verbose = false;1801 m_internal = false;1802 m_unreported = true; // The variable is "skip unreported" and we want to1803 // skip unreported by default.1804 m_tids.clear();1805 }1806 1807 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1808 return llvm::ArrayRef(g_thread_plan_list_options);1809 }1810 1811 // Instance variables to hold the values for command options.1812 bool m_verbose;1813 bool m_internal;1814 bool m_unreported;1815 std::vector<lldb::tid_t> m_tids;1816 };1817 1818 CommandObjectThreadPlanList(CommandInterpreter &interpreter)1819 : CommandObjectIterateOverThreads(1820 interpreter, "thread plan list",1821 "Show thread plans for one or more threads. If no threads are "1822 "specified, show the "1823 "current thread. Use the thread-index \"all\" to see all threads.",1824 nullptr,1825 eCommandRequiresProcess | eCommandRequiresThread |1826 eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |1827 eCommandProcessMustBePaused) {}1828 1829 ~CommandObjectThreadPlanList() override = default;1830 1831 Options *GetOptions() override { return &m_options; }1832 1833 void DoExecute(Args &command, CommandReturnObject &result) override {1834 // If we are reporting all threads, dispatch to the Process to do that:1835 if (command.GetArgumentCount() == 0 && m_options.m_tids.empty()) {1836 Stream &strm = result.GetOutputStream();1837 DescriptionLevel desc_level = m_options.m_verbose1838 ? eDescriptionLevelVerbose1839 : eDescriptionLevelFull;1840 m_exe_ctx.GetProcessPtr()->DumpThreadPlans(1841 strm, desc_level, m_options.m_internal, true, m_options.m_unreported);1842 result.SetStatus(eReturnStatusSuccessFinishResult);1843 return;1844 } else {1845 // Do any TID's that the user may have specified as TID, then do any1846 // Thread Indexes...1847 if (!m_options.m_tids.empty()) {1848 Process *process = m_exe_ctx.GetProcessPtr();1849 StreamString tmp_strm;1850 for (lldb::tid_t tid : m_options.m_tids) {1851 bool success = process->DumpThreadPlansForTID(1852 tmp_strm, tid, eDescriptionLevelFull, m_options.m_internal,1853 true /* condense_trivial */, m_options.m_unreported);1854 // If we didn't find a TID, stop here and return an error.1855 if (!success) {1856 result.AppendError("Error dumping plans:");1857 result.AppendError(tmp_strm.GetString());1858 return;1859 }1860 // Otherwise, add our data to the output:1861 result.GetOutputStream() << tmp_strm.GetString();1862 }1863 }1864 return CommandObjectIterateOverThreads::DoExecute(command, result);1865 }1866 }1867 1868protected:1869 bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {1870 // If we have already handled this from a -t option, skip it here.1871 if (llvm::is_contained(m_options.m_tids, tid))1872 return true;1873 1874 Process *process = m_exe_ctx.GetProcessPtr();1875 1876 Stream &strm = result.GetOutputStream();1877 DescriptionLevel desc_level = eDescriptionLevelFull;1878 if (m_options.m_verbose)1879 desc_level = eDescriptionLevelVerbose;1880 1881 process->DumpThreadPlansForTID(strm, tid, desc_level, m_options.m_internal,1882 true /* condense_trivial */,1883 m_options.m_unreported);1884 return true;1885 }1886 1887 CommandOptions m_options;1888};1889 1890class CommandObjectThreadPlanDiscard : public CommandObjectParsed {1891public:1892 CommandObjectThreadPlanDiscard(CommandInterpreter &interpreter)1893 : CommandObjectParsed(interpreter, "thread plan discard",1894 "Discards thread plans up to and including the "1895 "specified index (see 'thread plan list'.) "1896 "Only user visible plans can be discarded.",1897 nullptr,1898 eCommandRequiresProcess | eCommandRequiresThread |1899 eCommandTryTargetAPILock |1900 eCommandProcessMustBeLaunched |1901 eCommandProcessMustBePaused) {1902 AddSimpleArgumentList(eArgTypeUnsignedInteger);1903 }1904 1905 ~CommandObjectThreadPlanDiscard() override = default;1906 1907 void1908 HandleArgumentCompletion(CompletionRequest &request,1909 OptionElementVector &opt_element_vector) override {1910 if (!m_exe_ctx.HasThreadScope() || request.GetCursorIndex())1911 return;1912 1913 m_exe_ctx.GetThreadPtr()->AutoCompleteThreadPlans(request);1914 }1915 1916 void DoExecute(Args &args, CommandReturnObject &result) override {1917 Thread *thread = m_exe_ctx.GetThreadPtr();1918 if (args.GetArgumentCount() != 1) {1919 result.AppendErrorWithFormat("Too many arguments, expected one - the "1920 "thread plan index - but got %zu.",1921 args.GetArgumentCount());1922 return;1923 }1924 1925 uint32_t thread_plan_idx;1926 if (!llvm::to_integer(args.GetArgumentAtIndex(0), thread_plan_idx)) {1927 result.AppendErrorWithFormat(1928 "Invalid thread index: \"%s\" - should be unsigned int.",1929 args.GetArgumentAtIndex(0));1930 return;1931 }1932 1933 if (thread_plan_idx == 0) {1934 result.AppendErrorWithFormat(1935 "You wouldn't really want me to discard the base thread plan.");1936 return;1937 }1938 1939 if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) {1940 result.SetStatus(eReturnStatusSuccessFinishNoResult);1941 } else {1942 result.AppendErrorWithFormat(1943 "Could not find User thread plan with index %s.",1944 args.GetArgumentAtIndex(0));1945 }1946 }1947};1948 1949class CommandObjectThreadPlanPrune : public CommandObjectParsed {1950public:1951 CommandObjectThreadPlanPrune(CommandInterpreter &interpreter)1952 : CommandObjectParsed(interpreter, "thread plan prune",1953 "Removes any thread plans associated with "1954 "currently unreported threads. "1955 "Specify one or more TID's to remove, or if no "1956 "TID's are provides, remove threads for all "1957 "unreported threads",1958 nullptr,1959 eCommandRequiresProcess |1960 eCommandTryTargetAPILock |1961 eCommandProcessMustBeLaunched |1962 eCommandProcessMustBePaused) {1963 AddSimpleArgumentList(eArgTypeThreadID, eArgRepeatStar);1964 }1965 1966 ~CommandObjectThreadPlanPrune() override = default;1967 1968 void DoExecute(Args &args, CommandReturnObject &result) override {1969 Process *process = m_exe_ctx.GetProcessPtr();1970 1971 if (args.GetArgumentCount() == 0) {1972 process->PruneThreadPlans();1973 result.SetStatus(eReturnStatusSuccessFinishNoResult);1974 return;1975 }1976 1977 const size_t num_args = args.GetArgumentCount();1978 1979 std::lock_guard<std::recursive_mutex> guard(1980 process->GetThreadList().GetMutex());1981 1982 for (size_t i = 0; i < num_args; i++) {1983 lldb::tid_t tid;1984 if (!llvm::to_integer(args.GetArgumentAtIndex(i), tid)) {1985 result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n",1986 args.GetArgumentAtIndex(i));1987 return;1988 }1989 if (!process->PruneThreadPlansForTID(tid)) {1990 result.AppendErrorWithFormat("Could not find unreported tid: \"%s\"\n",1991 args.GetArgumentAtIndex(i));1992 return;1993 }1994 }1995 result.SetStatus(eReturnStatusSuccessFinishNoResult);1996 }1997};1998 1999// CommandObjectMultiwordThreadPlan2000 2001class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword {2002public:2003 CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter)2004 : CommandObjectMultiword(2005 interpreter, "plan",2006 "Commands for managing thread plans that control execution.",2007 "thread plan <subcommand> [<subcommand objects]") {2008 LoadSubCommand(2009 "list", CommandObjectSP(new CommandObjectThreadPlanList(interpreter)));2010 LoadSubCommand(2011 "discard",2012 CommandObjectSP(new CommandObjectThreadPlanDiscard(interpreter)));2013 LoadSubCommand(2014 "prune",2015 CommandObjectSP(new CommandObjectThreadPlanPrune(interpreter)));2016 }2017 2018 ~CommandObjectMultiwordThreadPlan() override = default;2019};2020 2021// Next are the subcommands of CommandObjectMultiwordTrace2022 2023// CommandObjectTraceExport2024 2025class CommandObjectTraceExport : public CommandObjectMultiword {2026public:2027 CommandObjectTraceExport(CommandInterpreter &interpreter)2028 : CommandObjectMultiword(2029 interpreter, "trace thread export",2030 "Commands for exporting traces of the threads in the current "2031 "process to different formats.",2032 "thread trace export <export-plugin> [<subcommand objects>]") {2033 2034 unsigned i = 0;2035 for (llvm::StringRef plugin_name =2036 PluginManager::GetTraceExporterPluginNameAtIndex(i);2037 !plugin_name.empty();2038 plugin_name = PluginManager::GetTraceExporterPluginNameAtIndex(i++)) {2039 if (ThreadTraceExportCommandCreator command_creator =2040 PluginManager::GetThreadTraceExportCommandCreatorAtIndex(i)) {2041 LoadSubCommand(plugin_name, command_creator(interpreter));2042 }2043 }2044 }2045};2046 2047// CommandObjectTraceStart2048 2049class CommandObjectTraceStart : public CommandObjectTraceProxy {2050public:2051 CommandObjectTraceStart(CommandInterpreter &interpreter)2052 : CommandObjectTraceProxy(2053 /*live_debug_session_only=*/true, interpreter, "thread trace start",2054 "Start tracing threads with the corresponding trace "2055 "plug-in for the current process.",2056 "thread trace start [<trace-options>]") {}2057 2058protected:2059 lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override {2060 return trace.GetThreadTraceStartCommand(m_interpreter);2061 }2062};2063 2064// CommandObjectTraceStop2065 2066class CommandObjectTraceStop : public CommandObjectMultipleThreads {2067public:2068 CommandObjectTraceStop(CommandInterpreter &interpreter)2069 : CommandObjectMultipleThreads(2070 interpreter, "thread trace stop",2071 "Stop tracing threads, including the ones traced with the "2072 "\"process trace start\" command."2073 "Defaults to the current thread. Thread indices can be "2074 "specified as arguments.\n Use the thread-index \"all\" to stop "2075 "tracing "2076 "for all existing threads.",2077 "thread trace stop [<thread-index> <thread-index> ...]",2078 eCommandRequiresProcess | eCommandTryTargetAPILock |2079 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |2080 eCommandProcessMustBeTraced) {}2081 2082 ~CommandObjectTraceStop() override = default;2083 2084 bool DoExecuteOnThreads(Args &command, CommandReturnObject &result,2085 llvm::ArrayRef<lldb::tid_t> tids) override {2086 ProcessSP process_sp = m_exe_ctx.GetProcessSP();2087 2088 TraceSP trace_sp = process_sp->GetTarget().GetTrace();2089 2090 if (llvm::Error err = trace_sp->Stop(tids))2091 result.AppendError(toString(std::move(err)));2092 else2093 result.SetStatus(eReturnStatusSuccessFinishResult);2094 2095 return result.Succeeded();2096 }2097};2098 2099static ThreadSP GetSingleThreadFromArgs(ExecutionContext &exe_ctx, Args &args,2100 CommandReturnObject &result) {2101 if (args.GetArgumentCount() == 0)2102 return exe_ctx.GetThreadSP();2103 2104 const char *arg = args.GetArgumentAtIndex(0);2105 uint32_t thread_idx;2106 2107 if (!llvm::to_integer(arg, thread_idx)) {2108 result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", arg);2109 return nullptr;2110 }2111 ThreadSP thread_sp =2112 exe_ctx.GetProcessRef().GetThreadList().FindThreadByIndexID(thread_idx);2113 if (!thread_sp)2114 result.AppendErrorWithFormat("no thread with index: \"%s\"\n", arg);2115 return thread_sp;2116}2117 2118// CommandObjectTraceDumpFunctionCalls2119#define LLDB_OPTIONS_thread_trace_dump_function_calls2120#include "CommandOptions.inc"2121 2122class CommandObjectTraceDumpFunctionCalls : public CommandObjectParsed {2123public:2124 class CommandOptions : public Options {2125 public:2126 CommandOptions() { OptionParsingStarting(nullptr); }2127 2128 ~CommandOptions() override = default;2129 2130 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,2131 ExecutionContext *execution_context) override {2132 Status error;2133 const int short_option = m_getopt_table[option_idx].val;2134 2135 switch (short_option) {2136 case 'j': {2137 m_dumper_options.json = true;2138 break;2139 }2140 case 'J': {2141 m_dumper_options.json = true;2142 m_dumper_options.pretty_print_json = true;2143 break;2144 }2145 case 'F': {2146 m_output_file.emplace(option_arg);2147 break;2148 }2149 default:2150 llvm_unreachable("Unimplemented option");2151 }2152 return error;2153 }2154 2155 void OptionParsingStarting(ExecutionContext *execution_context) override {2156 m_dumper_options = {};2157 m_output_file = std::nullopt;2158 }2159 2160 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {2161 return llvm::ArrayRef(g_thread_trace_dump_function_calls_options);2162 }2163 2164 static const size_t kDefaultCount = 20;2165 2166 // Instance variables to hold the values for command options.2167 TraceDumperOptions m_dumper_options;2168 std::optional<FileSpec> m_output_file;2169 };2170 2171 CommandObjectTraceDumpFunctionCalls(CommandInterpreter &interpreter)2172 : CommandObjectParsed(2173 interpreter, "thread trace dump function-calls",2174 "Dump the traced function-calls for one thread. If no "2175 "thread is specified, the current thread is used.",2176 nullptr,2177 eCommandRequiresProcess | eCommandRequiresThread |2178 eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |2179 eCommandProcessMustBePaused | eCommandProcessMustBeTraced) {2180 AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatOptional);2181 }2182 2183 ~CommandObjectTraceDumpFunctionCalls() override = default;2184 2185 Options *GetOptions() override { return &m_options; }2186 2187protected:2188 void DoExecute(Args &args, CommandReturnObject &result) override {2189 ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);2190 if (!thread_sp) {2191 result.AppendError("invalid thread\n");2192 return;2193 }2194 2195 llvm::Expected<TraceCursorSP> cursor_or_error =2196 m_exe_ctx.GetTargetSP()->GetTrace()->CreateNewCursor(*thread_sp);2197 2198 if (!cursor_or_error) {2199 result.AppendError(llvm::toString(cursor_or_error.takeError()));2200 return;2201 }2202 TraceCursorSP &cursor_sp = *cursor_or_error;2203 2204 std::optional<StreamFile> out_file;2205 if (m_options.m_output_file) {2206 out_file.emplace(m_options.m_output_file->GetPath().c_str(),2207 File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |2208 File::eOpenOptionTruncate);2209 }2210 2211 m_options.m_dumper_options.forwards = true;2212 2213 TraceDumper dumper(std::move(cursor_sp),2214 out_file ? *out_file : result.GetOutputStream(),2215 m_options.m_dumper_options);2216 2217 dumper.DumpFunctionCalls();2218 }2219 2220 CommandOptions m_options;2221};2222 2223// CommandObjectTraceDumpInstructions2224#define LLDB_OPTIONS_thread_trace_dump_instructions2225#include "CommandOptions.inc"2226 2227class CommandObjectTraceDumpInstructions : public CommandObjectParsed {2228public:2229 class CommandOptions : public Options {2230 public:2231 CommandOptions() { OptionParsingStarting(nullptr); }2232 2233 ~CommandOptions() override = default;2234 2235 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,2236 ExecutionContext *execution_context) override {2237 Status error;2238 const int short_option = m_getopt_table[option_idx].val;2239 2240 switch (short_option) {2241 case 'c': {2242 int32_t count;2243 if (option_arg.empty() || option_arg.getAsInteger(0, count) ||2244 count < 0)2245 error = Status::FromErrorStringWithFormat(2246 "invalid integer value for option '%s'",2247 option_arg.str().c_str());2248 else2249 m_count = count;2250 break;2251 }2252 case 'a': {2253 m_count = std::numeric_limits<decltype(m_count)>::max();2254 break;2255 }2256 case 's': {2257 int32_t skip;2258 if (option_arg.empty() || option_arg.getAsInteger(0, skip) || skip < 0)2259 error = Status::FromErrorStringWithFormat(2260 "invalid integer value for option '%s'",2261 option_arg.str().c_str());2262 else2263 m_dumper_options.skip = skip;2264 break;2265 }2266 case 'i': {2267 uint64_t id;2268 if (option_arg.empty() || option_arg.getAsInteger(0, id))2269 error = Status::FromErrorStringWithFormat(2270 "invalid integer value for option '%s'",2271 option_arg.str().c_str());2272 else2273 m_dumper_options.id = id;2274 break;2275 }2276 case 'F': {2277 m_output_file.emplace(option_arg);2278 break;2279 }2280 case 'r': {2281 m_dumper_options.raw = true;2282 break;2283 }2284 case 'f': {2285 m_dumper_options.forwards = true;2286 break;2287 }2288 case 'k': {2289 m_dumper_options.show_control_flow_kind = true;2290 break;2291 }2292 case 't': {2293 m_dumper_options.show_timestamps = true;2294 break;2295 }2296 case 'e': {2297 m_dumper_options.show_events = true;2298 break;2299 }2300 case 'j': {2301 m_dumper_options.json = true;2302 break;2303 }2304 case 'J': {2305 m_dumper_options.pretty_print_json = true;2306 m_dumper_options.json = true;2307 break;2308 }2309 case 'E': {2310 m_dumper_options.only_events = true;2311 m_dumper_options.show_events = true;2312 break;2313 }2314 case 'C': {2315 m_continue = true;2316 break;2317 }2318 default:2319 llvm_unreachable("Unimplemented option");2320 }2321 return error;2322 }2323 2324 void OptionParsingStarting(ExecutionContext *execution_context) override {2325 m_count = kDefaultCount;2326 m_continue = false;2327 m_output_file = std::nullopt;2328 m_dumper_options = {};2329 }2330 2331 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {2332 return llvm::ArrayRef(g_thread_trace_dump_instructions_options);2333 }2334 2335 static const size_t kDefaultCount = 20;2336 2337 // Instance variables to hold the values for command options.2338 size_t m_count;2339 size_t m_continue;2340 std::optional<FileSpec> m_output_file;2341 TraceDumperOptions m_dumper_options;2342 };2343 2344 CommandObjectTraceDumpInstructions(CommandInterpreter &interpreter)2345 : CommandObjectParsed(2346 interpreter, "thread trace dump instructions",2347 "Dump the traced instructions for one thread. If no "2348 "thread is specified, show the current thread.",2349 nullptr,2350 eCommandRequiresProcess | eCommandRequiresThread |2351 eCommandTryTargetAPILock | eCommandProcessMustBeLaunched |2352 eCommandProcessMustBePaused | eCommandProcessMustBeTraced) {2353 AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatOptional);2354 }2355 2356 ~CommandObjectTraceDumpInstructions() override = default;2357 2358 Options *GetOptions() override { return &m_options; }2359 2360 std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,2361 uint32_t index) override {2362 std::string cmd;2363 current_command_args.GetCommandString(cmd);2364 if (cmd.find(" --continue") == std::string::npos)2365 cmd += " --continue";2366 return cmd;2367 }2368 2369protected:2370 void DoExecute(Args &args, CommandReturnObject &result) override {2371 ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);2372 if (!thread_sp) {2373 result.AppendError("invalid thread\n");2374 return;2375 }2376 2377 if (m_options.m_continue && m_last_id) {2378 // We set up the options to continue one instruction past where2379 // the previous iteration stopped.2380 m_options.m_dumper_options.skip = 1;2381 m_options.m_dumper_options.id = m_last_id;2382 }2383 2384 llvm::Expected<TraceCursorSP> cursor_or_error =2385 m_exe_ctx.GetTargetSP()->GetTrace()->CreateNewCursor(*thread_sp);2386 2387 if (!cursor_or_error) {2388 result.AppendError(llvm::toString(cursor_or_error.takeError()));2389 return;2390 }2391 TraceCursorSP &cursor_sp = *cursor_or_error;2392 2393 if (m_options.m_dumper_options.id &&2394 !cursor_sp->HasId(*m_options.m_dumper_options.id)) {2395 result.AppendError("invalid instruction id\n");2396 return;2397 }2398 2399 std::optional<StreamFile> out_file;2400 if (m_options.m_output_file) {2401 out_file.emplace(m_options.m_output_file->GetPath().c_str(),2402 File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate |2403 File::eOpenOptionTruncate);2404 }2405 2406 if (m_options.m_continue && !m_last_id) {2407 // We need to stop processing data when we already ran out of instructions2408 // in a previous command. We can fake this by setting the cursor past the2409 // end of the trace.2410 cursor_sp->Seek(1, lldb::eTraceCursorSeekTypeEnd);2411 }2412 2413 TraceDumper dumper(std::move(cursor_sp),2414 out_file ? *out_file : result.GetOutputStream(),2415 m_options.m_dumper_options);2416 2417 m_last_id = dumper.DumpInstructions(m_options.m_count);2418 }2419 2420 CommandOptions m_options;2421 // Last traversed id used to continue a repeat command. std::nullopt means2422 // that all the trace has been consumed.2423 std::optional<lldb::user_id_t> m_last_id;2424};2425 2426// CommandObjectTraceDumpInfo2427#define LLDB_OPTIONS_thread_trace_dump_info2428#include "CommandOptions.inc"2429 2430class CommandObjectTraceDumpInfo : public CommandObjectIterateOverThreads {2431public:2432 class CommandOptions : public Options {2433 public:2434 CommandOptions() { OptionParsingStarting(nullptr); }2435 2436 ~CommandOptions() override = default;2437 2438 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,2439 ExecutionContext *execution_context) override {2440 Status error;2441 const int short_option = m_getopt_table[option_idx].val;2442 2443 switch (short_option) {2444 case 'v': {2445 m_verbose = true;2446 break;2447 }2448 case 'j': {2449 m_json = true;2450 break;2451 }2452 default:2453 llvm_unreachable("Unimplemented option");2454 }2455 return error;2456 }2457 2458 void OptionParsingStarting(ExecutionContext *execution_context) override {2459 m_verbose = false;2460 m_json = false;2461 }2462 2463 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {2464 return llvm::ArrayRef(g_thread_trace_dump_info_options);2465 }2466 2467 // Instance variables to hold the values for command options.2468 bool m_verbose;2469 bool m_json;2470 };2471 2472 CommandObjectTraceDumpInfo(CommandInterpreter &interpreter)2473 : CommandObjectIterateOverThreads(2474 interpreter, "thread trace dump info",2475 "Dump the traced information for one or more threads. If no "2476 "threads are specified, show the current thread. Use the "2477 "thread-index \"all\" to see all threads.",2478 nullptr,2479 eCommandRequiresProcess | eCommandTryTargetAPILock |2480 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |2481 eCommandProcessMustBeTraced) {}2482 2483 ~CommandObjectTraceDumpInfo() override = default;2484 2485 Options *GetOptions() override { return &m_options; }2486 2487protected:2488 bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override {2489 const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace();2490 ThreadSP thread_sp =2491 m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);2492 trace_sp->DumpTraceInfo(*thread_sp, result.GetOutputStream(),2493 m_options.m_verbose, m_options.m_json);2494 return true;2495 }2496 2497 CommandOptions m_options;2498};2499 2500// CommandObjectMultiwordTraceDump2501class CommandObjectMultiwordTraceDump : public CommandObjectMultiword {2502public:2503 CommandObjectMultiwordTraceDump(CommandInterpreter &interpreter)2504 : CommandObjectMultiword(2505 interpreter, "dump",2506 "Commands for displaying trace information of the threads "2507 "in the current process.",2508 "thread trace dump <subcommand> [<subcommand objects>]") {2509 LoadSubCommand(2510 "instructions",2511 CommandObjectSP(new CommandObjectTraceDumpInstructions(interpreter)));2512 LoadSubCommand(2513 "function-calls",2514 CommandObjectSP(new CommandObjectTraceDumpFunctionCalls(interpreter)));2515 LoadSubCommand(2516 "info", CommandObjectSP(new CommandObjectTraceDumpInfo(interpreter)));2517 }2518 ~CommandObjectMultiwordTraceDump() override = default;2519};2520 2521// CommandObjectMultiwordTrace2522class CommandObjectMultiwordTrace : public CommandObjectMultiword {2523public:2524 CommandObjectMultiwordTrace(CommandInterpreter &interpreter)2525 : CommandObjectMultiword(2526 interpreter, "trace",2527 "Commands for operating on traces of the threads in the current "2528 "process.",2529 "thread trace <subcommand> [<subcommand objects>]") {2530 LoadSubCommand("dump", CommandObjectSP(new CommandObjectMultiwordTraceDump(2531 interpreter)));2532 LoadSubCommand("start",2533 CommandObjectSP(new CommandObjectTraceStart(interpreter)));2534 LoadSubCommand("stop",2535 CommandObjectSP(new CommandObjectTraceStop(interpreter)));2536 LoadSubCommand("export",2537 CommandObjectSP(new CommandObjectTraceExport(interpreter)));2538 }2539 2540 ~CommandObjectMultiwordTrace() override = default;2541};2542 2543// CommandObjectMultiwordThread2544 2545CommandObjectMultiwordThread::CommandObjectMultiwordThread(2546 CommandInterpreter &interpreter)2547 : CommandObjectMultiword(interpreter, "thread",2548 "Commands for operating on "2549 "one or more threads in "2550 "the current process.",2551 "thread <subcommand> [<subcommand-options>]") {2552 LoadSubCommand("backtrace", CommandObjectSP(new CommandObjectThreadBacktrace(2553 interpreter)));2554 LoadSubCommand("continue",2555 CommandObjectSP(new CommandObjectThreadContinue(interpreter)));2556 LoadSubCommand("list",2557 CommandObjectSP(new CommandObjectThreadList(interpreter)));2558 LoadSubCommand("return",2559 CommandObjectSP(new CommandObjectThreadReturn(interpreter)));2560 LoadSubCommand("jump",2561 CommandObjectSP(new CommandObjectThreadJump(interpreter)));2562 LoadSubCommand("select",2563 CommandObjectSP(new CommandObjectThreadSelect(interpreter)));2564 LoadSubCommand("until",2565 CommandObjectSP(new CommandObjectThreadUntil(interpreter)));2566 LoadSubCommand("info",2567 CommandObjectSP(new CommandObjectThreadInfo(interpreter)));2568 LoadSubCommand("exception", CommandObjectSP(new CommandObjectThreadException(2569 interpreter)));2570 LoadSubCommand("siginfo",2571 CommandObjectSP(new CommandObjectThreadSiginfo(interpreter)));2572 LoadSubCommand("step-in",2573 CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(2574 interpreter, "thread step-in",2575 "Source level single step, stepping into calls. Defaults "2576 "to current thread unless specified.",2577 nullptr, eStepTypeInto)));2578 2579 LoadSubCommand("step-out",2580 CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(2581 interpreter, "thread step-out",2582 "Finish executing the current stack frame and stop after "2583 "returning. Defaults to current thread unless specified.",2584 nullptr, eStepTypeOut)));2585 2586 LoadSubCommand("step-over",2587 CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(2588 interpreter, "thread step-over",2589 "Source level single step, stepping over calls. Defaults "2590 "to current thread unless specified.",2591 nullptr, eStepTypeOver)));2592 2593 LoadSubCommand("step-inst",2594 CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(2595 interpreter, "thread step-inst",2596 "Instruction level single step, stepping into calls. "2597 "Defaults to current thread unless specified.",2598 nullptr, eStepTypeTrace)));2599 2600 LoadSubCommand("step-inst-over",2601 CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(2602 interpreter, "thread step-inst-over",2603 "Instruction level single step, stepping over calls. "2604 "Defaults to current thread unless specified.",2605 nullptr, eStepTypeTraceOver)));2606 2607 LoadSubCommand(2608 "step-scripted",2609 CommandObjectSP(new CommandObjectThreadStepWithTypeAndScope(2610 interpreter, "thread step-scripted",2611 "Step as instructed by the script class passed in the -C option. "2612 "You can also specify a dictionary of key (-k) and value (-v) pairs "2613 "that will be used to populate an SBStructuredData Dictionary, which "2614 "will be passed to the constructor of the class implementing the "2615 "scripted step. See the Python Reference for more details.",2616 nullptr, eStepTypeScripted)));2617 2618 LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan(2619 interpreter)));2620 LoadSubCommand("trace",2621 CommandObjectSP(new CommandObjectMultiwordTrace(interpreter)));2622}2623 2624CommandObjectMultiwordThread::~CommandObjectMultiwordThread() = default;2625