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