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