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