1 //===-- CommandObjectFrame.cpp ----------------------------------*- C++ -*-===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 #include "CommandObjectFrame.h" 9 #include "lldb/Core/Debugger.h" 10 #include "lldb/Core/Module.h" 11 #include "lldb/Core/StreamFile.h" 12 #include "lldb/Core/Value.h" 13 #include "lldb/Core/ValueObject.h" 14 #include "lldb/Core/ValueObjectVariable.h" 15 #include "lldb/DataFormatters/DataVisualization.h" 16 #include "lldb/DataFormatters/ValueObjectPrinter.h" 17 #include "lldb/Host/Host.h" 18 #include "lldb/Host/OptionParser.h" 19 #include "lldb/Host/StringConvert.h" 20 #include "lldb/Interpreter/CommandInterpreter.h" 21 #include "lldb/Interpreter/CommandReturnObject.h" 22 #include "lldb/Interpreter/OptionGroupFormat.h" 23 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" 24 #include "lldb/Interpreter/OptionGroupVariable.h" 25 #include "lldb/Interpreter/Options.h" 26 #include "lldb/Symbol/CompilerType.h" 27 #include "lldb/Symbol/Function.h" 28 #include "lldb/Symbol/ObjectFile.h" 29 #include "lldb/Symbol/SymbolContext.h" 30 #include "lldb/Symbol/Type.h" 31 #include "lldb/Symbol/Variable.h" 32 #include "lldb/Symbol/VariableList.h" 33 #include "lldb/Target/Process.h" 34 #include "lldb/Target/StackFrame.h" 35 #include "lldb/Target/StackFrameRecognizer.h" 36 #include "lldb/Target/StopInfo.h" 37 #include "lldb/Target/Target.h" 38 #include "lldb/Target/Thread.h" 39 #include "lldb/Utility/Args.h" 40 #include "lldb/Utility/LLDBAssert.h" 41 #include "lldb/Utility/StreamString.h" 42 #include "lldb/Utility/Timer.h" 43 44 #include <memory> 45 #include <string> 46 47 using namespace lldb; 48 using namespace lldb_private; 49 50 #pragma mark CommandObjectFrameDiagnose 51 52 // CommandObjectFrameInfo 53 54 // CommandObjectFrameDiagnose 55 56 static constexpr OptionDefinition g_frame_diag_options[] = { 57 // clang-format off 58 { LLDB_OPT_SET_1, false, "register", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeRegisterName, "A register to diagnose." }, 59 { LLDB_OPT_SET_1, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddress, "An address to diagnose." }, 60 { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset, "An optional offset. Requires --register." } 61 // clang-format on 62 }; 63 64 class CommandObjectFrameDiagnose : public CommandObjectParsed { 65 public: 66 class CommandOptions : public Options { 67 public: 68 CommandOptions() : Options() { OptionParsingStarting(nullptr); } 69 70 ~CommandOptions() override = default; 71 72 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 73 ExecutionContext *execution_context) override { 74 Status error; 75 const int short_option = m_getopt_table[option_idx].val; 76 switch (short_option) { 77 case 'r': 78 reg = ConstString(option_arg); 79 break; 80 81 case 'a': { 82 address.emplace(); 83 if (option_arg.getAsInteger(0, *address)) { 84 address.reset(); 85 error.SetErrorStringWithFormat("invalid address argument '%s'", 86 option_arg.str().c_str()); 87 } 88 } break; 89 90 case 'o': { 91 offset.emplace(); 92 if (option_arg.getAsInteger(0, *offset)) { 93 offset.reset(); 94 error.SetErrorStringWithFormat("invalid offset argument '%s'", 95 option_arg.str().c_str()); 96 } 97 } break; 98 99 default: 100 error.SetErrorStringWithFormat("invalid short option character '%c'", 101 short_option); 102 break; 103 } 104 105 return error; 106 } 107 108 void OptionParsingStarting(ExecutionContext *execution_context) override { 109 address.reset(); 110 reg.reset(); 111 offset.reset(); 112 } 113 114 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 115 return llvm::makeArrayRef(g_frame_diag_options); 116 } 117 118 // Options. 119 llvm::Optional<lldb::addr_t> address; 120 llvm::Optional<ConstString> reg; 121 llvm::Optional<int64_t> offset; 122 }; 123 124 CommandObjectFrameDiagnose(CommandInterpreter &interpreter) 125 : CommandObjectParsed(interpreter, "frame diagnose", 126 "Try to determine what path path the current stop " 127 "location used to get to a register or address", 128 nullptr, 129 eCommandRequiresThread | eCommandTryTargetAPILock | 130 eCommandProcessMustBeLaunched | 131 eCommandProcessMustBePaused), 132 m_options() { 133 CommandArgumentEntry arg; 134 CommandArgumentData index_arg; 135 136 // Define the first (and only) variant of this arg. 137 index_arg.arg_type = eArgTypeFrameIndex; 138 index_arg.arg_repetition = eArgRepeatOptional; 139 140 // There is only one variant this argument could be; put it into the 141 // argument entry. 142 arg.push_back(index_arg); 143 144 // Push the data for the first argument into the m_arguments vector. 145 m_arguments.push_back(arg); 146 } 147 148 ~CommandObjectFrameDiagnose() override = default; 149 150 Options *GetOptions() override { return &m_options; } 151 152 protected: 153 bool DoExecute(Args &command, CommandReturnObject &result) override { 154 Thread *thread = m_exe_ctx.GetThreadPtr(); 155 StackFrameSP frame_sp = thread->GetSelectedFrame(); 156 157 ValueObjectSP valobj_sp; 158 159 if (m_options.address.hasValue()) { 160 if (m_options.reg.hasValue() || m_options.offset.hasValue()) { 161 result.AppendError( 162 "`frame diagnose --address` is incompatible with other arguments."); 163 result.SetStatus(eReturnStatusFailed); 164 return false; 165 } 166 valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue()); 167 } else if (m_options.reg.hasValue()) { 168 valobj_sp = frame_sp->GuessValueForRegisterAndOffset( 169 m_options.reg.getValue(), m_options.offset.getValueOr(0)); 170 } else { 171 StopInfoSP stop_info_sp = thread->GetStopInfo(); 172 if (!stop_info_sp) { 173 result.AppendError("No arguments provided, and no stop info."); 174 result.SetStatus(eReturnStatusFailed); 175 return false; 176 } 177 178 valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp); 179 } 180 181 if (!valobj_sp) { 182 result.AppendError("No diagnosis available."); 183 result.SetStatus(eReturnStatusFailed); 184 return false; 185 } 186 187 188 DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp]( 189 ConstString type, ConstString var, const DumpValueObjectOptions &opts, 190 Stream &stream) -> bool { 191 const ValueObject::GetExpressionPathFormat format = ValueObject:: 192 GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers; 193 const bool qualify_cxx_base_classes = false; 194 valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format); 195 stream.PutCString(" ="); 196 return true; 197 }; 198 199 DumpValueObjectOptions options; 200 options.SetDeclPrintingHelper(helper); 201 ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), 202 options); 203 printer.PrintValueObject(); 204 205 return true; 206 } 207 208 protected: 209 CommandOptions m_options; 210 }; 211 212 #pragma mark CommandObjectFrameInfo 213 214 // CommandObjectFrameInfo 215 216 class CommandObjectFrameInfo : public CommandObjectParsed { 217 public: 218 CommandObjectFrameInfo(CommandInterpreter &interpreter) 219 : CommandObjectParsed( 220 interpreter, "frame info", "List information about the current " 221 "stack frame in the current thread.", 222 "frame info", 223 eCommandRequiresFrame | eCommandTryTargetAPILock | 224 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 225 226 ~CommandObjectFrameInfo() override = default; 227 228 protected: 229 bool DoExecute(Args &command, CommandReturnObject &result) override { 230 m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream()); 231 result.SetStatus(eReturnStatusSuccessFinishResult); 232 return result.Succeeded(); 233 } 234 }; 235 236 #pragma mark CommandObjectFrameSelect 237 238 // CommandObjectFrameSelect 239 240 static OptionDefinition g_frame_select_options[] = { 241 // clang-format off 242 { LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset, "A relative frame index offset from the current frame index." }, 243 // clang-format on 244 }; 245 246 class CommandObjectFrameSelect : public CommandObjectParsed { 247 public: 248 class CommandOptions : public Options { 249 public: 250 CommandOptions() : Options() { OptionParsingStarting(nullptr); } 251 252 ~CommandOptions() override = default; 253 254 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 255 ExecutionContext *execution_context) override { 256 Status error; 257 const int short_option = m_getopt_table[option_idx].val; 258 switch (short_option) { 259 case 'r': 260 if (option_arg.getAsInteger(0, relative_frame_offset)) { 261 relative_frame_offset = INT32_MIN; 262 error.SetErrorStringWithFormat("invalid frame offset argument '%s'", 263 option_arg.str().c_str()); 264 } 265 break; 266 267 default: 268 error.SetErrorStringWithFormat("invalid short option character '%c'", 269 short_option); 270 break; 271 } 272 273 return error; 274 } 275 276 void OptionParsingStarting(ExecutionContext *execution_context) override { 277 relative_frame_offset = INT32_MIN; 278 } 279 280 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 281 return llvm::makeArrayRef(g_frame_select_options); 282 } 283 284 int32_t relative_frame_offset; 285 }; 286 287 CommandObjectFrameSelect(CommandInterpreter &interpreter) 288 : CommandObjectParsed( 289 interpreter, "frame select", "Select the current stack frame by " 290 "index from within the current thread " 291 "(see 'thread backtrace'.)", 292 nullptr, 293 eCommandRequiresThread | eCommandTryTargetAPILock | 294 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 295 m_options() { 296 CommandArgumentEntry arg; 297 CommandArgumentData index_arg; 298 299 // Define the first (and only) variant of this arg. 300 index_arg.arg_type = eArgTypeFrameIndex; 301 index_arg.arg_repetition = eArgRepeatOptional; 302 303 // There is only one variant this argument could be; put it into the 304 // argument entry. 305 arg.push_back(index_arg); 306 307 // Push the data for the first argument into the m_arguments vector. 308 m_arguments.push_back(arg); 309 } 310 311 ~CommandObjectFrameSelect() override = default; 312 313 Options *GetOptions() override { return &m_options; } 314 315 protected: 316 bool DoExecute(Args &command, CommandReturnObject &result) override { 317 // No need to check "thread" for validity as eCommandRequiresThread ensures 318 // it is valid 319 Thread *thread = m_exe_ctx.GetThreadPtr(); 320 321 uint32_t frame_idx = UINT32_MAX; 322 if (m_options.relative_frame_offset != INT32_MIN) { 323 // The one and only argument is a signed relative frame index 324 frame_idx = thread->GetSelectedFrameIndex(); 325 if (frame_idx == UINT32_MAX) 326 frame_idx = 0; 327 328 if (m_options.relative_frame_offset < 0) { 329 if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset) 330 frame_idx += m_options.relative_frame_offset; 331 else { 332 if (frame_idx == 0) { 333 // If you are already at the bottom of the stack, then just warn 334 // and don't reset the frame. 335 result.AppendError("Already at the bottom of the stack."); 336 result.SetStatus(eReturnStatusFailed); 337 return false; 338 } else 339 frame_idx = 0; 340 } 341 } else if (m_options.relative_frame_offset > 0) { 342 // I don't want "up 20" where "20" takes you past the top of the stack 343 // to produce 344 // an error, but rather to just go to the top. So I have to count the 345 // stack here... 346 const uint32_t num_frames = thread->GetStackFrameCount(); 347 if (static_cast<int32_t>(num_frames - frame_idx) > 348 m_options.relative_frame_offset) 349 frame_idx += m_options.relative_frame_offset; 350 else { 351 if (frame_idx == num_frames - 1) { 352 // If we are already at the top of the stack, just warn and don't 353 // reset the frame. 354 result.AppendError("Already at the top of the stack."); 355 result.SetStatus(eReturnStatusFailed); 356 return false; 357 } else 358 frame_idx = num_frames - 1; 359 } 360 } 361 } else { 362 if (command.GetArgumentCount() > 1) { 363 result.AppendErrorWithFormat( 364 "too many arguments; expected frame-index, saw '%s'.\n", 365 command[0].c_str()); 366 m_options.GenerateOptionUsage( 367 result.GetErrorStream(), this, 368 GetCommandInterpreter().GetDebugger().GetTerminalWidth()); 369 return false; 370 } 371 372 if (command.GetArgumentCount() == 1) { 373 if (command[0].ref.getAsInteger(0, frame_idx)) { 374 result.AppendErrorWithFormat("invalid frame index argument '%s'.", 375 command[0].c_str()); 376 result.SetStatus(eReturnStatusFailed); 377 return false; 378 } 379 } else if (command.GetArgumentCount() == 0) { 380 frame_idx = thread->GetSelectedFrameIndex(); 381 if (frame_idx == UINT32_MAX) { 382 frame_idx = 0; 383 } 384 } 385 } 386 387 bool success = thread->SetSelectedFrameByIndexNoisily( 388 frame_idx, result.GetOutputStream()); 389 if (success) { 390 m_exe_ctx.SetFrameSP(thread->GetSelectedFrame()); 391 result.SetStatus(eReturnStatusSuccessFinishResult); 392 } else { 393 result.AppendErrorWithFormat("Frame index (%u) out of range.\n", 394 frame_idx); 395 result.SetStatus(eReturnStatusFailed); 396 } 397 398 return result.Succeeded(); 399 } 400 401 protected: 402 CommandOptions m_options; 403 }; 404 405 #pragma mark CommandObjectFrameVariable 406 // List images with associated information 407 class CommandObjectFrameVariable : public CommandObjectParsed { 408 public: 409 CommandObjectFrameVariable(CommandInterpreter &interpreter) 410 : CommandObjectParsed( 411 interpreter, "frame variable", 412 "Show variables for the current stack frame. Defaults to all " 413 "arguments and local variables in scope. Names of argument, " 414 "local, file static and file global variables can be specified. " 415 "Children of aggregate variables can be specified such as " 416 "'var->child.x'. The -> and [] operators in 'frame variable' do " 417 "not invoke operator overloads if they exist, but directly access " 418 "the specified element. If you want to trigger operator overloads " 419 "use the expression command to print the variable instead." 420 "\nIt is worth noting that except for overloaded " 421 "operators, when printing local variables 'expr local_var' and " 422 "'frame var local_var' produce the same " 423 "results. However, 'frame variable' is more efficient, since it " 424 "uses debug information and memory reads directly, rather than " 425 "parsing and evaluating an expression, which may even involve " 426 "JITing and running code in the target program.", 427 nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock | 428 eCommandProcessMustBeLaunched | 429 eCommandProcessMustBePaused | eCommandRequiresProcess), 430 m_option_group(), 431 m_option_variable( 432 true), // Include the frame specific options by passing "true" 433 m_option_format(eFormatDefault), 434 m_varobj_options() { 435 CommandArgumentEntry arg; 436 CommandArgumentData var_name_arg; 437 438 // Define the first (and only) variant of this arg. 439 var_name_arg.arg_type = eArgTypeVarName; 440 var_name_arg.arg_repetition = eArgRepeatStar; 441 442 // There is only one variant this argument could be; put it into the 443 // argument entry. 444 arg.push_back(var_name_arg); 445 446 // Push the data for the first argument into the m_arguments vector. 447 m_arguments.push_back(arg); 448 449 m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 450 m_option_group.Append(&m_option_format, 451 OptionGroupFormat::OPTION_GROUP_FORMAT | 452 OptionGroupFormat::OPTION_GROUP_GDB_FMT, 453 LLDB_OPT_SET_1); 454 m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 455 m_option_group.Finalize(); 456 } 457 458 ~CommandObjectFrameVariable() override = default; 459 460 Options *GetOptions() override { return &m_option_group; } 461 462 int HandleArgumentCompletion( 463 CompletionRequest &request, 464 OptionElementVector &opt_element_vector) override { 465 // Arguments are the standard source file completer. 466 CommandCompletions::InvokeCommonCompletionCallbacks( 467 GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, 468 request, nullptr); 469 return request.GetNumberOfMatches(); 470 } 471 472 protected: 473 llvm::StringRef GetScopeString(VariableSP var_sp) { 474 if (!var_sp) 475 return llvm::StringRef::withNullAsEmpty(nullptr); 476 477 switch (var_sp->GetScope()) { 478 case eValueTypeVariableGlobal: 479 return "GLOBAL: "; 480 case eValueTypeVariableStatic: 481 return "STATIC: "; 482 case eValueTypeVariableArgument: 483 return "ARG: "; 484 case eValueTypeVariableLocal: 485 return "LOCAL: "; 486 case eValueTypeVariableThreadLocal: 487 return "THREAD: "; 488 default: 489 break; 490 } 491 492 return llvm::StringRef::withNullAsEmpty(nullptr); 493 } 494 495 bool DoExecute(Args &command, CommandReturnObject &result) override { 496 // No need to check "frame" for validity as eCommandRequiresFrame ensures 497 // it is valid 498 StackFrame *frame = m_exe_ctx.GetFramePtr(); 499 500 Stream &s = result.GetOutputStream(); 501 502 // Be careful about the stack frame, if any summary formatter runs code, it 503 // might clear the StackFrameList for the thread. So hold onto a shared 504 // pointer to the frame so it stays alive. 505 506 VariableList *variable_list = 507 frame->GetVariableList(m_option_variable.show_globals); 508 509 VariableSP var_sp; 510 ValueObjectSP valobj_sp; 511 512 TypeSummaryImplSP summary_format_sp; 513 if (!m_option_variable.summary.IsCurrentValueEmpty()) 514 DataVisualization::NamedSummaryFormats::GetSummaryFormat( 515 ConstString(m_option_variable.summary.GetCurrentValue()), 516 summary_format_sp); 517 else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 518 summary_format_sp = std::make_shared<StringSummaryFormat>( 519 TypeSummaryImpl::Flags(), 520 m_option_variable.summary_string.GetCurrentValue()); 521 522 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( 523 eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault, 524 summary_format_sp)); 525 526 const SymbolContext &sym_ctx = 527 frame->GetSymbolContext(eSymbolContextFunction); 528 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 529 m_option_variable.show_globals = true; 530 531 if (variable_list) { 532 const Format format = m_option_format.GetFormat(); 533 options.SetFormat(format); 534 535 if (!command.empty()) { 536 VariableList regex_var_list; 537 538 // If we have any args to the variable command, we will make variable 539 // objects from them... 540 for (auto &entry : command) { 541 if (m_option_variable.use_regex) { 542 const size_t regex_start_index = regex_var_list.GetSize(); 543 llvm::StringRef name_str = entry.ref; 544 RegularExpression regex(name_str); 545 if (regex.Compile(name_str)) { 546 size_t num_matches = 0; 547 const size_t num_new_regex_vars = 548 variable_list->AppendVariablesIfUnique(regex, regex_var_list, 549 num_matches); 550 if (num_new_regex_vars > 0) { 551 for (size_t regex_idx = regex_start_index, 552 end_index = regex_var_list.GetSize(); 553 regex_idx < end_index; ++regex_idx) { 554 var_sp = regex_var_list.GetVariableAtIndex(regex_idx); 555 if (var_sp) { 556 valobj_sp = frame->GetValueObjectForFrameVariable( 557 var_sp, m_varobj_options.use_dynamic); 558 if (valobj_sp) { 559 std::string scope_string; 560 if (m_option_variable.show_scope) 561 scope_string = GetScopeString(var_sp).str(); 562 563 if (!scope_string.empty()) 564 s.PutCString(scope_string); 565 566 if (m_option_variable.show_decl && 567 var_sp->GetDeclaration().GetFile()) { 568 bool show_fullpaths = false; 569 bool show_module = true; 570 if (var_sp->DumpDeclaration(&s, show_fullpaths, 571 show_module)) 572 s.PutCString(": "); 573 } 574 valobj_sp->Dump(result.GetOutputStream(), options); 575 } 576 } 577 } 578 } else if (num_matches == 0) { 579 result.GetErrorStream().Printf("error: no variables matched " 580 "the regular expression '%s'.\n", 581 entry.c_str()); 582 } 583 } else { 584 char regex_error[1024]; 585 if (regex.GetErrorAsCString(regex_error, sizeof(regex_error))) 586 result.GetErrorStream().Printf("error: %s\n", regex_error); 587 else 588 result.GetErrorStream().Printf( 589 "error: unknown regex error when compiling '%s'\n", 590 entry.c_str()); 591 } 592 } else // No regex, either exact variable names or variable 593 // expressions. 594 { 595 Status error; 596 uint32_t expr_path_options = 597 StackFrame::eExpressionPathOptionCheckPtrVsMember | 598 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 599 StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 600 lldb::VariableSP var_sp; 601 valobj_sp = frame->GetValueForVariableExpressionPath( 602 entry.ref, m_varobj_options.use_dynamic, expr_path_options, 603 var_sp, error); 604 if (valobj_sp) { 605 std::string scope_string; 606 if (m_option_variable.show_scope) 607 scope_string = GetScopeString(var_sp).str(); 608 609 if (!scope_string.empty()) 610 s.PutCString(scope_string); 611 if (m_option_variable.show_decl && var_sp && 612 var_sp->GetDeclaration().GetFile()) { 613 var_sp->GetDeclaration().DumpStopContext(&s, false); 614 s.PutCString(": "); 615 } 616 617 options.SetFormat(format); 618 options.SetVariableFormatDisplayLanguage( 619 valobj_sp->GetPreferredDisplayLanguage()); 620 621 Stream &output_stream = result.GetOutputStream(); 622 options.SetRootValueObjectName( 623 valobj_sp->GetParent() ? entry.c_str() : nullptr); 624 valobj_sp->Dump(output_stream, options); 625 } else { 626 const char *error_cstr = error.AsCString(nullptr); 627 if (error_cstr) 628 result.GetErrorStream().Printf("error: %s\n", error_cstr); 629 else 630 result.GetErrorStream().Printf("error: unable to find any " 631 "variable expression path that " 632 "matches '%s'.\n", 633 entry.c_str()); 634 } 635 } 636 } 637 } else // No command arg specified. Use variable_list, instead. 638 { 639 const size_t num_variables = variable_list->GetSize(); 640 if (num_variables > 0) { 641 for (size_t i = 0; i < num_variables; i++) { 642 var_sp = variable_list->GetVariableAtIndex(i); 643 switch (var_sp->GetScope()) { 644 case eValueTypeVariableGlobal: 645 if (!m_option_variable.show_globals) 646 continue; 647 break; 648 case eValueTypeVariableStatic: 649 if (!m_option_variable.show_globals) 650 continue; 651 break; 652 case eValueTypeVariableArgument: 653 if (!m_option_variable.show_args) 654 continue; 655 break; 656 case eValueTypeVariableLocal: 657 if (!m_option_variable.show_locals) 658 continue; 659 break; 660 default: 661 continue; 662 break; 663 } 664 std::string scope_string; 665 if (m_option_variable.show_scope) 666 scope_string = GetScopeString(var_sp).str(); 667 668 // Use the variable object code to make sure we are using the same 669 // APIs as the public API will be using... 670 valobj_sp = frame->GetValueObjectForFrameVariable( 671 var_sp, m_varobj_options.use_dynamic); 672 if (valobj_sp) { 673 // When dumping all variables, don't print any variables that are 674 // not in scope to avoid extra unneeded output 675 if (valobj_sp->IsInScope()) { 676 if (!valobj_sp->GetTargetSP() 677 ->GetDisplayRuntimeSupportValues() && 678 valobj_sp->IsRuntimeSupportValue()) 679 continue; 680 681 if (!scope_string.empty()) 682 s.PutCString(scope_string); 683 684 if (m_option_variable.show_decl && 685 var_sp->GetDeclaration().GetFile()) { 686 var_sp->GetDeclaration().DumpStopContext(&s, false); 687 s.PutCString(": "); 688 } 689 690 options.SetFormat(format); 691 options.SetVariableFormatDisplayLanguage( 692 valobj_sp->GetPreferredDisplayLanguage()); 693 options.SetRootValueObjectName( 694 var_sp ? var_sp->GetName().AsCString() : nullptr); 695 valobj_sp->Dump(result.GetOutputStream(), options); 696 } 697 } 698 } 699 } 700 } 701 result.SetStatus(eReturnStatusSuccessFinishResult); 702 } 703 704 if (m_option_variable.show_recognized_args) { 705 auto recognized_frame = frame->GetRecognizedFrame(); 706 if (recognized_frame) { 707 ValueObjectListSP recognized_arg_list = 708 recognized_frame->GetRecognizedArguments(); 709 if (recognized_arg_list) { 710 for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { 711 options.SetFormat(m_option_format.GetFormat()); 712 options.SetVariableFormatDisplayLanguage( 713 rec_value_sp->GetPreferredDisplayLanguage()); 714 options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); 715 rec_value_sp->Dump(result.GetOutputStream(), options); 716 } 717 } 718 } 719 } 720 721 if (m_interpreter.TruncationWarningNecessary()) { 722 result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 723 m_cmd_name.c_str()); 724 m_interpreter.TruncationWarningGiven(); 725 } 726 727 // Increment statistics. 728 bool res = result.Succeeded(); 729 Target *target = GetSelectedOrDummyTarget(); 730 if (res) 731 target->IncrementStats(StatisticKind::FrameVarSuccess); 732 else 733 target->IncrementStats(StatisticKind::FrameVarFailure); 734 return res; 735 } 736 737 protected: 738 OptionGroupOptions m_option_group; 739 OptionGroupVariable m_option_variable; 740 OptionGroupFormat m_option_format; 741 OptionGroupValueObjectDisplay m_varobj_options; 742 }; 743 744 #pragma mark CommandObjectFrameRecognizer 745 746 static OptionDefinition g_frame_recognizer_add_options[] = { 747 // clang-format off 748 { LLDB_OPT_SET_ALL, false, "shlib", 's', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Name of the module or shared library that this recognizer applies to." }, 749 { LLDB_OPT_SET_ALL, false, "function", 'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeName, "Name of the function that this recognizer applies to." }, 750 { LLDB_OPT_SET_2, false, "python-class", 'l', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePythonClass, "Give the name of a Python class to use for this frame recognizer." }, 751 { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Function name and module name are actually regular expressions." } 752 // clang-format on 753 }; 754 755 class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { 756 private: 757 class CommandOptions : public Options { 758 public: 759 CommandOptions() : Options() {} 760 ~CommandOptions() override = default; 761 762 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 763 ExecutionContext *execution_context) override { 764 Status error; 765 const int short_option = m_getopt_table[option_idx].val; 766 767 switch (short_option) { 768 case 'l': 769 m_class_name = std::string(option_arg); 770 break; 771 case 's': 772 m_module = std::string(option_arg); 773 break; 774 case 'n': 775 m_function = std::string(option_arg); 776 break; 777 case 'x': 778 m_regex = true; 779 break; 780 default: 781 error.SetErrorStringWithFormat("unrecognized option '%c'", 782 short_option); 783 break; 784 } 785 786 return error; 787 } 788 789 void OptionParsingStarting(ExecutionContext *execution_context) override { 790 m_module = ""; 791 m_function = ""; 792 m_class_name = ""; 793 m_regex = false; 794 } 795 796 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 797 return llvm::makeArrayRef(g_frame_recognizer_add_options); 798 } 799 800 // Instance variables to hold the values for command options. 801 std::string m_class_name; 802 std::string m_module; 803 std::string m_function; 804 bool m_regex; 805 }; 806 807 CommandOptions m_options; 808 809 Options *GetOptions() override { return &m_options; } 810 811 protected: 812 bool DoExecute(Args &command, CommandReturnObject &result) override; 813 814 public: 815 CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 816 : CommandObjectParsed(interpreter, "frame recognizer add", 817 "Add a new frame recognizer.", nullptr), 818 m_options() { 819 SetHelpLong(R"( 820 Frame recognizers allow for retrieving information about special frames based on 821 ABI, arguments or other special properties of that frame, even without source 822 code or debug info. Currently, one use case is to extract function arguments 823 that would otherwise be unaccesible, or augment existing arguments. 824 825 Adding a custom frame recognizer is possible by implementing a Python class 826 and using the 'frame recognizer add' command. The Python class should have a 827 'get_recognized_arguments' method and it will receive an argument of type 828 lldb.SBFrame representing the current frame that we are trying to recognize. 829 The method should return a (possibly empty) list of lldb.SBValue objects that 830 represent the recognized arguments. 831 832 An example of a recognizer that retrieves the file descriptor values from libc 833 functions 'read', 'write' and 'close' follows: 834 835 class LibcFdRecognizer(object): 836 def get_recognized_arguments(self, frame): 837 if frame.name in ["read", "write", "close"]: 838 fd = frame.EvaluateExpression("$arg1").unsigned 839 value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) 840 return [value] 841 return [] 842 843 The file containing this implementation can be imported via 'command script 844 import' and then we can register this recognizer with 'frame recognizer add'. 845 It's important to restrict the recognizer to the libc library (which is 846 libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 847 in other modules: 848 849 (lldb) command script import .../fd_recognizer.py 850 (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 851 852 When the program is stopped at the beginning of the 'read' function in libc, we 853 can view the recognizer arguments in 'frame variable': 854 855 (lldb) b read 856 (lldb) r 857 Process 1234 stopped 858 * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 859 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 860 (lldb) frame variable 861 (int) fd = 3 862 863 )"); 864 } 865 ~CommandObjectFrameRecognizerAdd() override = default; 866 }; 867 868 bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 869 CommandReturnObject &result) { 870 #ifndef LLDB_DISABLE_PYTHON 871 if (m_options.m_class_name.empty()) { 872 result.AppendErrorWithFormat( 873 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 874 result.SetStatus(eReturnStatusFailed); 875 return false; 876 } 877 878 if (m_options.m_module.empty()) { 879 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 880 m_cmd_name.c_str()); 881 result.SetStatus(eReturnStatusFailed); 882 return false; 883 } 884 885 if (m_options.m_function.empty()) { 886 result.AppendErrorWithFormat("%s needs a function name (-n argument).\n", 887 m_cmd_name.c_str()); 888 result.SetStatus(eReturnStatusFailed); 889 return false; 890 } 891 892 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 893 894 if (interpreter && 895 !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 896 result.AppendWarning( 897 "The provided class does not exist - please define it " 898 "before attempting to use this frame recognizer"); 899 } 900 901 StackFrameRecognizerSP recognizer_sp = 902 StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 903 interpreter, m_options.m_class_name.c_str())); 904 if (m_options.m_regex) { 905 auto module = 906 RegularExpressionSP(new RegularExpression(m_options.m_module)); 907 auto func = 908 RegularExpressionSP(new RegularExpression(m_options.m_function)); 909 StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); 910 } else { 911 auto module = ConstString(m_options.m_module); 912 auto func = ConstString(m_options.m_function); 913 StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); 914 } 915 #endif 916 917 result.SetStatus(eReturnStatusSuccessFinishNoResult); 918 return result.Succeeded(); 919 } 920 921 class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 922 public: 923 CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 924 : CommandObjectParsed(interpreter, "frame recognizer clear", 925 "Delete all frame recognizers.", nullptr) {} 926 927 ~CommandObjectFrameRecognizerClear() override = default; 928 929 protected: 930 bool DoExecute(Args &command, CommandReturnObject &result) override { 931 StackFrameRecognizerManager::RemoveAllRecognizers(); 932 result.SetStatus(eReturnStatusSuccessFinishResult); 933 return result.Succeeded(); 934 } 935 }; 936 937 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 938 public: 939 CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 940 : CommandObjectParsed(interpreter, "frame recognizer delete", 941 "Delete an existing frame recognizer.", nullptr) {} 942 943 ~CommandObjectFrameRecognizerDelete() override = default; 944 945 protected: 946 bool DoExecute(Args &command, CommandReturnObject &result) override { 947 if (command.GetArgumentCount() == 0) { 948 if (!m_interpreter.Confirm( 949 "About to delete all frame recognizers, do you want to do that?", 950 true)) { 951 result.AppendMessage("Operation cancelled..."); 952 result.SetStatus(eReturnStatusFailed); 953 return false; 954 } 955 956 StackFrameRecognizerManager::RemoveAllRecognizers(); 957 result.SetStatus(eReturnStatusSuccessFinishResult); 958 return result.Succeeded(); 959 } 960 961 if (command.GetArgumentCount() != 1) { 962 result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 963 m_cmd_name.c_str()); 964 result.SetStatus(eReturnStatusFailed); 965 return false; 966 } 967 968 uint32_t recognizer_id = 969 StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 970 971 StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id); 972 result.SetStatus(eReturnStatusSuccessFinishResult); 973 return result.Succeeded(); 974 } 975 }; 976 977 class CommandObjectFrameRecognizerList : public CommandObjectParsed { 978 public: 979 CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 980 : CommandObjectParsed(interpreter, "frame recognizer list", 981 "Show a list of active frame recognizers.", 982 nullptr) {} 983 984 ~CommandObjectFrameRecognizerList() override = default; 985 986 protected: 987 bool DoExecute(Args &command, CommandReturnObject &result) override { 988 bool any_printed = false; 989 StackFrameRecognizerManager::ForEach( 990 [&result, &any_printed](uint32_t recognizer_id, std::string name, 991 std::string function, std::string symbol, 992 bool regexp) { 993 if (name == "") name = "(internal)"; 994 result.GetOutputStream().Printf( 995 "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(), 996 function.c_str(), symbol.c_str(), regexp ? " (regexp)" : ""); 997 any_printed = true; 998 }); 999 1000 if (any_printed) 1001 result.SetStatus(eReturnStatusSuccessFinishResult); 1002 else { 1003 result.GetOutputStream().PutCString("no matching results found.\n"); 1004 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1005 } 1006 return result.Succeeded(); 1007 } 1008 }; 1009 1010 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 1011 public: 1012 CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 1013 : CommandObjectParsed( 1014 interpreter, "frame recognizer info", 1015 "Show which frame recognizer is applied a stack frame (if any).", 1016 nullptr) { 1017 CommandArgumentEntry arg; 1018 CommandArgumentData index_arg; 1019 1020 // Define the first (and only) variant of this arg. 1021 index_arg.arg_type = eArgTypeFrameIndex; 1022 index_arg.arg_repetition = eArgRepeatPlain; 1023 1024 // There is only one variant this argument could be; put it into the 1025 // argument entry. 1026 arg.push_back(index_arg); 1027 1028 // Push the data for the first argument into the m_arguments vector. 1029 m_arguments.push_back(arg); 1030 } 1031 1032 ~CommandObjectFrameRecognizerInfo() override = default; 1033 1034 protected: 1035 bool DoExecute(Args &command, CommandReturnObject &result) override { 1036 Process *process = m_exe_ctx.GetProcessPtr(); 1037 if (process == nullptr) { 1038 result.AppendError("no process"); 1039 result.SetStatus(eReturnStatusFailed); 1040 return false; 1041 } 1042 Thread *thread = m_exe_ctx.GetThreadPtr(); 1043 if (thread == nullptr) { 1044 result.AppendError("no thread"); 1045 result.SetStatus(eReturnStatusFailed); 1046 return false; 1047 } 1048 if (command.GetArgumentCount() != 1) { 1049 result.AppendErrorWithFormat( 1050 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 1051 result.SetStatus(eReturnStatusFailed); 1052 return false; 1053 } 1054 1055 uint32_t frame_index = 1056 StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 1057 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 1058 if (!frame_sp) { 1059 result.AppendErrorWithFormat("no frame with index %u", frame_index); 1060 result.SetStatus(eReturnStatusFailed); 1061 return false; 1062 } 1063 1064 auto recognizer = 1065 StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp); 1066 1067 Stream &output_stream = result.GetOutputStream(); 1068 output_stream.Printf("frame %d ", frame_index); 1069 if (recognizer) { 1070 output_stream << "is recognized by "; 1071 output_stream << recognizer->GetName(); 1072 } else { 1073 output_stream << "not recognized by any recognizer"; 1074 } 1075 output_stream.EOL(); 1076 result.SetStatus(eReturnStatusSuccessFinishResult); 1077 return result.Succeeded(); 1078 } 1079 }; 1080 1081 class CommandObjectFrameRecognizer : public CommandObjectMultiword { 1082 public: 1083 CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 1084 : CommandObjectMultiword( 1085 interpreter, "frame recognizer", 1086 "Commands for editing and viewing frame recognizers.", 1087 "frame recognizer [<sub-command-options>] ") { 1088 LoadSubCommand( 1089 "add", 1090 CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter))); 1091 LoadSubCommand( 1092 "clear", 1093 CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 1094 LoadSubCommand( 1095 "delete", 1096 CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 1097 LoadSubCommand( 1098 "list", 1099 CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter))); 1100 LoadSubCommand( 1101 "info", 1102 CommandObjectSP(new CommandObjectFrameRecognizerInfo(interpreter))); 1103 } 1104 1105 ~CommandObjectFrameRecognizer() override = default; 1106 }; 1107 1108 #pragma mark CommandObjectMultiwordFrame 1109 1110 // CommandObjectMultiwordFrame 1111 1112 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1113 CommandInterpreter &interpreter) 1114 : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and " 1115 "examing the current " 1116 "thread's stack frames.", 1117 "frame <subcommand> [<subcommand-options>]") { 1118 LoadSubCommand("diagnose", 1119 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1120 LoadSubCommand("info", 1121 CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1122 LoadSubCommand("select", 1123 CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1124 LoadSubCommand("variable", 1125 CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 1126 #ifndef LLDB_DISABLE_PYTHON 1127 LoadSubCommand( 1128 "recognizer", 1129 CommandObjectSP(new CommandObjectFrameRecognizer(interpreter))); 1130 #endif 1131 } 1132 1133 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1134