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