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