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 } 498 499 /// Finds all the variables in `all_variables` whose name matches `regex`, 500 /// inserting them into `matches`. Variables already contained in `matches` 501 /// are not inserted again. 502 /// Nullopt is returned in case of no matches. 503 /// A sub-range of `matches` with all newly inserted variables is returned. 504 /// This may be empty if all matches were already contained in `matches`. 505 std::optional<llvm::ArrayRef<VariableSP>> 506 findUniqueRegexMatches(RegularExpression ®ex, 507 VariableList &matches, 508 const VariableList &all_variables) { 509 bool any_matches = false; 510 const size_t previous_num_vars = matches.GetSize(); 511 512 for (const VariableSP &var : all_variables) { 513 if (!var->NameMatches(regex) || !ScopeRequested(var->GetScope())) 514 continue; 515 any_matches = true; 516 matches.AddVariableIfUnique(var); 517 } 518 519 if (any_matches) 520 return matches.toArrayRef().drop_front(previous_num_vars); 521 return std::nullopt; 522 } 523 524 void DoExecute(Args &command, CommandReturnObject &result) override { 525 // No need to check "frame" for validity as eCommandRequiresFrame ensures 526 // it is valid 527 StackFrame *frame = m_exe_ctx.GetFramePtr(); 528 529 Stream &s = result.GetOutputStream(); 530 531 // Using a regex should behave like looking for an exact name match: it 532 // also finds globals. 533 m_option_variable.show_globals |= m_option_variable.use_regex; 534 535 // Be careful about the stack frame, if any summary formatter runs code, it 536 // might clear the StackFrameList for the thread. So hold onto a shared 537 // pointer to the frame so it stays alive. 538 539 Status error; 540 VariableList *variable_list = 541 frame->GetVariableList(m_option_variable.show_globals, &error); 542 543 if (error.Fail() && (!variable_list || variable_list->GetSize() == 0)) { 544 result.AppendError(error.AsCString()); 545 546 } 547 ValueObjectSP valobj_sp; 548 549 TypeSummaryImplSP summary_format_sp; 550 if (!m_option_variable.summary.IsCurrentValueEmpty()) 551 DataVisualization::NamedSummaryFormats::GetSummaryFormat( 552 ConstString(m_option_variable.summary.GetCurrentValue()), 553 summary_format_sp); 554 else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 555 summary_format_sp = std::make_shared<StringSummaryFormat>( 556 TypeSummaryImpl::Flags(), 557 m_option_variable.summary_string.GetCurrentValue()); 558 559 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( 560 eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault, 561 summary_format_sp)); 562 563 const SymbolContext &sym_ctx = 564 frame->GetSymbolContext(eSymbolContextFunction); 565 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 566 m_option_variable.show_globals = true; 567 568 if (variable_list) { 569 const Format format = m_option_format.GetFormat(); 570 options.SetFormat(format); 571 572 if (!command.empty()) { 573 VariableList regex_var_list; 574 575 // If we have any args to the variable command, we will make variable 576 // objects from them... 577 for (auto &entry : command) { 578 if (m_option_variable.use_regex) { 579 llvm::StringRef name_str = entry.ref(); 580 RegularExpression regex(name_str); 581 if (regex.IsValid()) { 582 std::optional<llvm::ArrayRef<VariableSP>> results = 583 findUniqueRegexMatches(regex, regex_var_list, *variable_list); 584 if (!results) { 585 result.AppendErrorWithFormat( 586 "no variables matched the regular expression '%s'.", 587 entry.c_str()); 588 continue; 589 } 590 for (const VariableSP &var_sp : *results) { 591 valobj_sp = frame->GetValueObjectForFrameVariable( 592 var_sp, m_varobj_options.use_dynamic); 593 if (valobj_sp) { 594 std::string scope_string; 595 if (m_option_variable.show_scope) 596 scope_string = GetScopeString(var_sp).str(); 597 598 if (!scope_string.empty()) 599 s.PutCString(scope_string); 600 601 if (m_option_variable.show_decl && 602 var_sp->GetDeclaration().GetFile()) { 603 bool show_fullpaths = false; 604 bool show_module = true; 605 if (var_sp->DumpDeclaration(&s, show_fullpaths, 606 show_module)) 607 s.PutCString(": "); 608 } 609 valobj_sp->Dump(result.GetOutputStream(), options); 610 } 611 } 612 } else { 613 if (llvm::Error err = regex.GetError()) 614 result.AppendError(llvm::toString(std::move(err))); 615 else 616 result.AppendErrorWithFormat( 617 "unknown regex error when compiling '%s'", entry.c_str()); 618 } 619 } else // No regex, either exact variable names or variable 620 // expressions. 621 { 622 Status error; 623 uint32_t expr_path_options = 624 StackFrame::eExpressionPathOptionCheckPtrVsMember | 625 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 626 StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 627 lldb::VariableSP var_sp; 628 valobj_sp = frame->GetValueForVariableExpressionPath( 629 entry.ref(), m_varobj_options.use_dynamic, expr_path_options, 630 var_sp, error); 631 if (valobj_sp) { 632 std::string scope_string; 633 if (m_option_variable.show_scope) 634 scope_string = GetScopeString(var_sp).str(); 635 636 if (!scope_string.empty()) 637 s.PutCString(scope_string); 638 if (m_option_variable.show_decl && var_sp && 639 var_sp->GetDeclaration().GetFile()) { 640 var_sp->GetDeclaration().DumpStopContext(&s, false); 641 s.PutCString(": "); 642 } 643 644 options.SetFormat(format); 645 options.SetVariableFormatDisplayLanguage( 646 valobj_sp->GetPreferredDisplayLanguage()); 647 648 Stream &output_stream = result.GetOutputStream(); 649 options.SetRootValueObjectName( 650 valobj_sp->GetParent() ? entry.c_str() : nullptr); 651 valobj_sp->Dump(output_stream, options); 652 } else { 653 if (auto error_cstr = error.AsCString(nullptr)) 654 result.AppendError(error_cstr); 655 else 656 result.AppendErrorWithFormat( 657 "unable to find any variable expression path that matches " 658 "'%s'.", 659 entry.c_str()); 660 } 661 } 662 } 663 } else // No command arg specified. Use variable_list, instead. 664 { 665 const size_t num_variables = variable_list->GetSize(); 666 if (num_variables > 0) { 667 for (size_t i = 0; i < num_variables; i++) { 668 VariableSP var_sp = variable_list->GetVariableAtIndex(i); 669 if (!ScopeRequested(var_sp->GetScope())) 670 continue; 671 std::string scope_string; 672 if (m_option_variable.show_scope) 673 scope_string = GetScopeString(var_sp).str(); 674 675 // Use the variable object code to make sure we are using the same 676 // APIs as the public API will be using... 677 valobj_sp = frame->GetValueObjectForFrameVariable( 678 var_sp, m_varobj_options.use_dynamic); 679 if (valobj_sp) { 680 // When dumping all variables, don't print any variables that are 681 // not in scope to avoid extra unneeded output 682 if (valobj_sp->IsInScope()) { 683 if (!valobj_sp->GetTargetSP() 684 ->GetDisplayRuntimeSupportValues() && 685 valobj_sp->IsRuntimeSupportValue()) 686 continue; 687 688 if (!scope_string.empty()) 689 s.PutCString(scope_string); 690 691 if (m_option_variable.show_decl && 692 var_sp->GetDeclaration().GetFile()) { 693 var_sp->GetDeclaration().DumpStopContext(&s, false); 694 s.PutCString(": "); 695 } 696 697 options.SetFormat(format); 698 options.SetVariableFormatDisplayLanguage( 699 valobj_sp->GetPreferredDisplayLanguage()); 700 options.SetRootValueObjectName( 701 var_sp ? var_sp->GetName().AsCString() : nullptr); 702 valobj_sp->Dump(result.GetOutputStream(), options); 703 } 704 } 705 } 706 } 707 } 708 if (result.GetStatus() != eReturnStatusFailed) 709 result.SetStatus(eReturnStatusSuccessFinishResult); 710 } 711 712 if (m_option_variable.show_recognized_args) { 713 auto recognized_frame = frame->GetRecognizedFrame(); 714 if (recognized_frame) { 715 ValueObjectListSP recognized_arg_list = 716 recognized_frame->GetRecognizedArguments(); 717 if (recognized_arg_list) { 718 for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { 719 options.SetFormat(m_option_format.GetFormat()); 720 options.SetVariableFormatDisplayLanguage( 721 rec_value_sp->GetPreferredDisplayLanguage()); 722 options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); 723 rec_value_sp->Dump(result.GetOutputStream(), options); 724 } 725 } 726 } 727 } 728 729 m_interpreter.PrintWarningsIfNecessary(result.GetOutputStream(), 730 m_cmd_name); 731 732 // Increment statistics. 733 TargetStats &target_stats = GetSelectedOrDummyTarget().GetStatistics(); 734 if (result.Succeeded()) 735 target_stats.GetFrameVariableStats().NotifySuccess(); 736 else 737 target_stats.GetFrameVariableStats().NotifyFailure(); 738 } 739 740 OptionGroupOptions m_option_group; 741 OptionGroupVariable m_option_variable; 742 OptionGroupFormat m_option_format; 743 OptionGroupValueObjectDisplay m_varobj_options; 744 }; 745 746 #pragma mark CommandObjectFrameRecognizer 747 748 #define LLDB_OPTIONS_frame_recognizer_add 749 #include "CommandOptions.inc" 750 751 class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { 752 private: 753 class CommandOptions : public Options { 754 public: 755 CommandOptions() = default; 756 ~CommandOptions() override = default; 757 758 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 759 ExecutionContext *execution_context) override { 760 Status error; 761 const int short_option = m_getopt_table[option_idx].val; 762 763 switch (short_option) { 764 case 'f': { 765 bool value, success; 766 value = OptionArgParser::ToBoolean(option_arg, true, &success); 767 if (success) { 768 m_first_instruction_only = value; 769 } else { 770 error.SetErrorStringWithFormat( 771 "invalid boolean value '%s' passed for -f option", 772 option_arg.str().c_str()); 773 } 774 } break; 775 case 'l': 776 m_class_name = std::string(option_arg); 777 break; 778 case 's': 779 m_module = std::string(option_arg); 780 break; 781 case 'n': 782 m_symbols.push_back(std::string(option_arg)); 783 break; 784 case 'x': 785 m_regex = true; 786 break; 787 default: 788 llvm_unreachable("Unimplemented option"); 789 } 790 791 return error; 792 } 793 794 void OptionParsingStarting(ExecutionContext *execution_context) override { 795 m_module = ""; 796 m_symbols.clear(); 797 m_class_name = ""; 798 m_regex = false; 799 m_first_instruction_only = true; 800 } 801 802 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 803 return llvm::ArrayRef(g_frame_recognizer_add_options); 804 } 805 806 // Instance variables to hold the values for command options. 807 std::string m_class_name; 808 std::string m_module; 809 std::vector<std::string> m_symbols; 810 bool m_regex; 811 bool m_first_instruction_only; 812 }; 813 814 CommandOptions m_options; 815 816 Options *GetOptions() override { return &m_options; } 817 818 protected: 819 void DoExecute(Args &command, CommandReturnObject &result) override; 820 821 public: 822 CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 823 : CommandObjectParsed(interpreter, "frame recognizer add", 824 "Add a new frame recognizer.", nullptr) { 825 SetHelpLong(R"( 826 Frame recognizers allow for retrieving information about special frames based on 827 ABI, arguments or other special properties of that frame, even without source 828 code or debug info. Currently, one use case is to extract function arguments 829 that would otherwise be unaccesible, or augment existing arguments. 830 831 Adding a custom frame recognizer is possible by implementing a Python class 832 and using the 'frame recognizer add' command. The Python class should have a 833 'get_recognized_arguments' method and it will receive an argument of type 834 lldb.SBFrame representing the current frame that we are trying to recognize. 835 The method should return a (possibly empty) list of lldb.SBValue objects that 836 represent the recognized arguments. 837 838 An example of a recognizer that retrieves the file descriptor values from libc 839 functions 'read', 'write' and 'close' follows: 840 841 class LibcFdRecognizer(object): 842 def get_recognized_arguments(self, frame): 843 if frame.name in ["read", "write", "close"]: 844 fd = frame.EvaluateExpression("$arg1").unsigned 845 target = frame.thread.process.target 846 value = target.CreateValueFromExpression("fd", "(int)%d" % fd) 847 return [value] 848 return [] 849 850 The file containing this implementation can be imported via 'command script 851 import' and then we can register this recognizer with 'frame recognizer add'. 852 It's important to restrict the recognizer to the libc library (which is 853 libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 854 in other modules: 855 856 (lldb) command script import .../fd_recognizer.py 857 (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 858 859 When the program is stopped at the beginning of the 'read' function in libc, we 860 can view the recognizer arguments in 'frame variable': 861 862 (lldb) b read 863 (lldb) r 864 Process 1234 stopped 865 * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 866 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 867 (lldb) frame variable 868 (int) fd = 3 869 870 )"); 871 } 872 ~CommandObjectFrameRecognizerAdd() override = default; 873 }; 874 875 void CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 876 CommandReturnObject &result) { 877 #if LLDB_ENABLE_PYTHON 878 if (m_options.m_class_name.empty()) { 879 result.AppendErrorWithFormat( 880 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 881 return; 882 } 883 884 if (m_options.m_module.empty()) { 885 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 886 m_cmd_name.c_str()); 887 return; 888 } 889 890 if (m_options.m_symbols.empty()) { 891 result.AppendErrorWithFormat( 892 "%s needs at least one symbol name (-n argument).\n", 893 m_cmd_name.c_str()); 894 return; 895 } 896 897 if (m_options.m_regex && m_options.m_symbols.size() > 1) { 898 result.AppendErrorWithFormat( 899 "%s needs only one symbol regular expression (-n argument).\n", 900 m_cmd_name.c_str()); 901 return; 902 } 903 904 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 905 906 if (interpreter && 907 !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 908 result.AppendWarning("The provided class does not exist - please define it " 909 "before attempting to use this frame recognizer"); 910 } 911 912 StackFrameRecognizerSP recognizer_sp = 913 StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 914 interpreter, m_options.m_class_name.c_str())); 915 if (m_options.m_regex) { 916 auto module = 917 RegularExpressionSP(new RegularExpression(m_options.m_module)); 918 auto func = 919 RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); 920 GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 921 recognizer_sp, module, func, m_options.m_first_instruction_only); 922 } else { 923 auto module = ConstString(m_options.m_module); 924 std::vector<ConstString> symbols(m_options.m_symbols.begin(), 925 m_options.m_symbols.end()); 926 GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 927 recognizer_sp, module, symbols, m_options.m_first_instruction_only); 928 } 929 #endif 930 931 result.SetStatus(eReturnStatusSuccessFinishNoResult); 932 } 933 934 class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 935 public: 936 CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 937 : CommandObjectParsed(interpreter, "frame recognizer clear", 938 "Delete all frame recognizers.", nullptr) {} 939 940 ~CommandObjectFrameRecognizerClear() override = default; 941 942 protected: 943 void DoExecute(Args &command, CommandReturnObject &result) override { 944 GetSelectedOrDummyTarget() 945 .GetFrameRecognizerManager() 946 .RemoveAllRecognizers(); 947 result.SetStatus(eReturnStatusSuccessFinishResult); 948 } 949 }; 950 951 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 952 public: 953 CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 954 : CommandObjectParsed(interpreter, "frame recognizer delete", 955 "Delete an existing frame recognizer by id.", 956 nullptr) { 957 CommandArgumentData thread_arg{eArgTypeRecognizerID, eArgRepeatPlain}; 958 m_arguments.push_back({thread_arg}); 959 } 960 961 ~CommandObjectFrameRecognizerDelete() override = default; 962 963 void 964 HandleArgumentCompletion(CompletionRequest &request, 965 OptionElementVector &opt_element_vector) override { 966 if (request.GetCursorIndex() != 0) 967 return; 968 969 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 970 [&request](uint32_t rid, std::string rname, std::string module, 971 llvm::ArrayRef<lldb_private::ConstString> symbols, 972 bool regexp) { 973 StreamString strm; 974 if (rname.empty()) 975 rname = "(internal)"; 976 977 strm << rname; 978 if (!module.empty()) 979 strm << ", module " << module; 980 if (!symbols.empty()) 981 for (auto &symbol : symbols) 982 strm << ", symbol " << symbol; 983 if (regexp) 984 strm << " (regexp)"; 985 986 request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString()); 987 }); 988 } 989 990 protected: 991 void DoExecute(Args &command, CommandReturnObject &result) override { 992 if (command.GetArgumentCount() == 0) { 993 if (!m_interpreter.Confirm( 994 "About to delete all frame recognizers, do you want to do that?", 995 true)) { 996 result.AppendMessage("Operation cancelled..."); 997 return; 998 } 999 1000 GetSelectedOrDummyTarget() 1001 .GetFrameRecognizerManager() 1002 .RemoveAllRecognizers(); 1003 result.SetStatus(eReturnStatusSuccessFinishResult); 1004 return; 1005 } 1006 1007 if (command.GetArgumentCount() != 1) { 1008 result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 1009 m_cmd_name.c_str()); 1010 return; 1011 } 1012 1013 uint32_t recognizer_id; 1014 if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) { 1015 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 1016 command.GetArgumentAtIndex(0)); 1017 return; 1018 } 1019 1020 if (!GetSelectedOrDummyTarget() 1021 .GetFrameRecognizerManager() 1022 .RemoveRecognizerWithID(recognizer_id)) { 1023 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 1024 command.GetArgumentAtIndex(0)); 1025 return; 1026 } 1027 result.SetStatus(eReturnStatusSuccessFinishResult); 1028 } 1029 }; 1030 1031 class CommandObjectFrameRecognizerList : public CommandObjectParsed { 1032 public: 1033 CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 1034 : CommandObjectParsed(interpreter, "frame recognizer list", 1035 "Show a list of active frame recognizers.", 1036 nullptr) {} 1037 1038 ~CommandObjectFrameRecognizerList() override = default; 1039 1040 protected: 1041 void DoExecute(Args &command, CommandReturnObject &result) override { 1042 bool any_printed = false; 1043 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 1044 [&result, &any_printed]( 1045 uint32_t recognizer_id, std::string name, std::string module, 1046 llvm::ArrayRef<ConstString> symbols, bool regexp) { 1047 Stream &stream = result.GetOutputStream(); 1048 1049 if (name.empty()) 1050 name = "(internal)"; 1051 1052 stream << std::to_string(recognizer_id) << ": " << name; 1053 if (!module.empty()) 1054 stream << ", module " << module; 1055 if (!symbols.empty()) 1056 for (auto &symbol : symbols) 1057 stream << ", symbol " << symbol; 1058 if (regexp) 1059 stream << " (regexp)"; 1060 1061 stream.EOL(); 1062 stream.Flush(); 1063 1064 any_printed = true; 1065 }); 1066 1067 if (any_printed) 1068 result.SetStatus(eReturnStatusSuccessFinishResult); 1069 else { 1070 result.GetOutputStream().PutCString("no matching results found.\n"); 1071 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1072 } 1073 } 1074 }; 1075 1076 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 1077 public: 1078 CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 1079 : CommandObjectParsed( 1080 interpreter, "frame recognizer info", 1081 "Show which frame recognizer is applied a stack frame (if any).", 1082 nullptr) { 1083 CommandArgumentEntry arg; 1084 CommandArgumentData index_arg; 1085 1086 // Define the first (and only) variant of this arg. 1087 index_arg.arg_type = eArgTypeFrameIndex; 1088 index_arg.arg_repetition = eArgRepeatPlain; 1089 1090 // There is only one variant this argument could be; put it into the 1091 // argument entry. 1092 arg.push_back(index_arg); 1093 1094 // Push the data for the first argument into the m_arguments vector. 1095 m_arguments.push_back(arg); 1096 } 1097 1098 ~CommandObjectFrameRecognizerInfo() override = default; 1099 1100 protected: 1101 void DoExecute(Args &command, CommandReturnObject &result) override { 1102 const char *frame_index_str = command.GetArgumentAtIndex(0); 1103 uint32_t frame_index; 1104 if (!llvm::to_integer(frame_index_str, frame_index)) { 1105 result.AppendErrorWithFormat("'%s' is not a valid frame index.", 1106 frame_index_str); 1107 return; 1108 } 1109 1110 Process *process = m_exe_ctx.GetProcessPtr(); 1111 if (process == nullptr) { 1112 result.AppendError("no process"); 1113 return; 1114 } 1115 Thread *thread = m_exe_ctx.GetThreadPtr(); 1116 if (thread == nullptr) { 1117 result.AppendError("no thread"); 1118 return; 1119 } 1120 if (command.GetArgumentCount() != 1) { 1121 result.AppendErrorWithFormat( 1122 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 1123 return; 1124 } 1125 1126 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 1127 if (!frame_sp) { 1128 result.AppendErrorWithFormat("no frame with index %u", frame_index); 1129 return; 1130 } 1131 1132 auto recognizer = GetSelectedOrDummyTarget() 1133 .GetFrameRecognizerManager() 1134 .GetRecognizerForFrame(frame_sp); 1135 1136 Stream &output_stream = result.GetOutputStream(); 1137 output_stream.Printf("frame %d ", frame_index); 1138 if (recognizer) { 1139 output_stream << "is recognized by "; 1140 output_stream << recognizer->GetName(); 1141 } else { 1142 output_stream << "not recognized by any recognizer"; 1143 } 1144 output_stream.EOL(); 1145 result.SetStatus(eReturnStatusSuccessFinishResult); 1146 } 1147 }; 1148 1149 class CommandObjectFrameRecognizer : public CommandObjectMultiword { 1150 public: 1151 CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 1152 : CommandObjectMultiword( 1153 interpreter, "frame recognizer", 1154 "Commands for editing and viewing frame recognizers.", 1155 "frame recognizer [<sub-command-options>] ") { 1156 LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd( 1157 interpreter))); 1158 LoadSubCommand( 1159 "clear", 1160 CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 1161 LoadSubCommand( 1162 "delete", 1163 CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 1164 LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList( 1165 interpreter))); 1166 LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo( 1167 interpreter))); 1168 } 1169 1170 ~CommandObjectFrameRecognizer() override = default; 1171 }; 1172 1173 #pragma mark CommandObjectMultiwordFrame 1174 1175 // CommandObjectMultiwordFrame 1176 1177 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1178 CommandInterpreter &interpreter) 1179 : CommandObjectMultiword(interpreter, "frame", 1180 "Commands for selecting and " 1181 "examing the current " 1182 "thread's stack frames.", 1183 "frame <subcommand> [<subcommand-options>]") { 1184 LoadSubCommand("diagnose", 1185 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1186 LoadSubCommand("info", 1187 CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1188 LoadSubCommand("select", 1189 CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1190 LoadSubCommand("variable", 1191 CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 1192 #if LLDB_ENABLE_PYTHON 1193 LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer( 1194 interpreter))); 1195 #endif 1196 } 1197 1198 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1199