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