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