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