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