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