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