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