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 330 // an error, but rather to just go to the top. So I have to count the 331 // stack here... 332 const uint32_t num_frames = thread->GetStackFrameCount(); 333 if (static_cast<int32_t>(num_frames - frame_idx) > 334 *m_options.relative_frame_offset) 335 frame_idx += *m_options.relative_frame_offset; 336 else { 337 if (frame_idx == num_frames - 1) { 338 // If we are already at the top of the stack, just warn and don't 339 // reset the frame. 340 result.AppendError("Already at the top of the stack."); 341 return false; 342 } else 343 frame_idx = num_frames - 1; 344 } 345 } 346 } else { 347 if (command.GetArgumentCount() > 1) { 348 result.AppendErrorWithFormat( 349 "too many arguments; expected frame-index, saw '%s'.\n", 350 command[0].c_str()); 351 m_options.GenerateOptionUsage( 352 result.GetErrorStream(), *this, 353 GetCommandInterpreter().GetDebugger().GetTerminalWidth()); 354 return false; 355 } 356 357 if (command.GetArgumentCount() == 1) { 358 if (command[0].ref().getAsInteger(0, frame_idx)) { 359 result.AppendErrorWithFormat("invalid frame index argument '%s'.", 360 command[0].c_str()); 361 return false; 362 } 363 } else if (command.GetArgumentCount() == 0) { 364 frame_idx = thread->GetSelectedFrameIndex(SelectMostRelevantFrame); 365 if (frame_idx == UINT32_MAX) { 366 frame_idx = 0; 367 } 368 } 369 } 370 371 bool success = thread->SetSelectedFrameByIndexNoisily( 372 frame_idx, result.GetOutputStream()); 373 if (success) { 374 m_exe_ctx.SetFrameSP(thread->GetSelectedFrame(SelectMostRelevantFrame)); 375 result.SetStatus(eReturnStatusSuccessFinishResult); 376 } else { 377 result.AppendErrorWithFormat("Frame index (%u) out of range.\n", 378 frame_idx); 379 } 380 381 return result.Succeeded(); 382 } 383 384 CommandOptions m_options; 385 }; 386 387 #pragma mark CommandObjectFrameVariable 388 // List images with associated information 389 class CommandObjectFrameVariable : public CommandObjectParsed { 390 public: 391 CommandObjectFrameVariable(CommandInterpreter &interpreter) 392 : CommandObjectParsed( 393 interpreter, "frame variable", 394 "Show variables for the current stack frame. Defaults to all " 395 "arguments and local variables in scope. Names of argument, " 396 "local, file static and file global variables can be specified.", 397 nullptr, 398 eCommandRequiresFrame | eCommandTryTargetAPILock | 399 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | 400 eCommandRequiresProcess), 401 m_option_variable( 402 true), // Include the frame specific options by passing "true" 403 m_option_format(eFormatDefault) { 404 SetHelpLong(R"( 405 Children of aggregate variables can be specified such as 'var->child.x'. In 406 'frame variable', the operators -> and [] do not invoke operator overloads if 407 they exist, but directly access the specified element. If you want to trigger 408 operator overloads use the expression command to print the variable instead. 409 410 It is worth noting that except for overloaded operators, when printing local 411 variables 'expr local_var' and 'frame var local_var' produce the same results. 412 However, 'frame variable' is more efficient, since it uses debug information and 413 memory reads directly, rather than parsing and evaluating an expression, which 414 may even involve JITing and running code in the target program.)"); 415 416 CommandArgumentEntry arg; 417 CommandArgumentData var_name_arg; 418 419 // Define the first (and only) variant of this arg. 420 var_name_arg.arg_type = eArgTypeVarName; 421 var_name_arg.arg_repetition = eArgRepeatStar; 422 423 // There is only one variant this argument could be; put it into the 424 // argument entry. 425 arg.push_back(var_name_arg); 426 427 // Push the data for the first argument into the m_arguments vector. 428 m_arguments.push_back(arg); 429 430 m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 431 m_option_group.Append(&m_option_format, 432 OptionGroupFormat::OPTION_GROUP_FORMAT | 433 OptionGroupFormat::OPTION_GROUP_GDB_FMT, 434 LLDB_OPT_SET_1); 435 m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 436 m_option_group.Finalize(); 437 } 438 439 ~CommandObjectFrameVariable() override = default; 440 441 Options *GetOptions() override { return &m_option_group; } 442 443 void 444 HandleArgumentCompletion(CompletionRequest &request, 445 OptionElementVector &opt_element_vector) override { 446 // Arguments are the standard source file completer. 447 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( 448 GetCommandInterpreter(), lldb::eVariablePathCompletion, request, 449 nullptr); 450 } 451 452 protected: 453 llvm::StringRef GetScopeString(VariableSP var_sp) { 454 if (!var_sp) 455 return llvm::StringRef(); 456 457 switch (var_sp->GetScope()) { 458 case eValueTypeVariableGlobal: 459 return "GLOBAL: "; 460 case eValueTypeVariableStatic: 461 return "STATIC: "; 462 case eValueTypeVariableArgument: 463 return "ARG: "; 464 case eValueTypeVariableLocal: 465 return "LOCAL: "; 466 case eValueTypeVariableThreadLocal: 467 return "THREAD: "; 468 default: 469 break; 470 } 471 472 return llvm::StringRef(); 473 } 474 475 bool DoExecute(Args &command, CommandReturnObject &result) override { 476 // No need to check "frame" for validity as eCommandRequiresFrame ensures 477 // it is valid 478 StackFrame *frame = m_exe_ctx.GetFramePtr(); 479 480 Stream &s = result.GetOutputStream(); 481 482 // Be careful about the stack frame, if any summary formatter runs code, it 483 // might clear the StackFrameList for the thread. So hold onto a shared 484 // pointer to the frame so it stays alive. 485 486 Status error; 487 VariableList *variable_list = 488 frame->GetVariableList(m_option_variable.show_globals, &error); 489 490 if (error.Fail() && (!variable_list || variable_list->GetSize() == 0)) { 491 result.AppendError(error.AsCString()); 492 493 } 494 VariableSP var_sp; 495 ValueObjectSP valobj_sp; 496 497 TypeSummaryImplSP summary_format_sp; 498 if (!m_option_variable.summary.IsCurrentValueEmpty()) 499 DataVisualization::NamedSummaryFormats::GetSummaryFormat( 500 ConstString(m_option_variable.summary.GetCurrentValue()), 501 summary_format_sp); 502 else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 503 summary_format_sp = std::make_shared<StringSummaryFormat>( 504 TypeSummaryImpl::Flags(), 505 m_option_variable.summary_string.GetCurrentValue()); 506 507 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( 508 eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault, 509 summary_format_sp)); 510 511 const SymbolContext &sym_ctx = 512 frame->GetSymbolContext(eSymbolContextFunction); 513 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 514 m_option_variable.show_globals = true; 515 516 if (variable_list) { 517 const Format format = m_option_format.GetFormat(); 518 options.SetFormat(format); 519 520 if (!command.empty()) { 521 VariableList regex_var_list; 522 523 // If we have any args to the variable command, we will make variable 524 // objects from them... 525 for (auto &entry : command) { 526 if (m_option_variable.use_regex) { 527 const size_t regex_start_index = regex_var_list.GetSize(); 528 llvm::StringRef name_str = entry.ref(); 529 RegularExpression regex(name_str); 530 if (regex.IsValid()) { 531 size_t num_matches = 0; 532 const size_t num_new_regex_vars = 533 variable_list->AppendVariablesIfUnique(regex, regex_var_list, 534 num_matches); 535 if (num_new_regex_vars > 0) { 536 for (size_t regex_idx = regex_start_index, 537 end_index = regex_var_list.GetSize(); 538 regex_idx < end_index; ++regex_idx) { 539 var_sp = regex_var_list.GetVariableAtIndex(regex_idx); 540 if (var_sp) { 541 valobj_sp = frame->GetValueObjectForFrameVariable( 542 var_sp, m_varobj_options.use_dynamic); 543 if (valobj_sp) { 544 std::string scope_string; 545 if (m_option_variable.show_scope) 546 scope_string = GetScopeString(var_sp).str(); 547 548 if (!scope_string.empty()) 549 s.PutCString(scope_string); 550 551 if (m_option_variable.show_decl && 552 var_sp->GetDeclaration().GetFile()) { 553 bool show_fullpaths = false; 554 bool show_module = true; 555 if (var_sp->DumpDeclaration(&s, show_fullpaths, 556 show_module)) 557 s.PutCString(": "); 558 } 559 valobj_sp->Dump(result.GetOutputStream(), options); 560 } 561 } 562 } 563 } else if (num_matches == 0) { 564 result.AppendErrorWithFormat( 565 "no variables matched the regular expression '%s'.", 566 entry.c_str()); 567 } 568 } else { 569 if (llvm::Error err = regex.GetError()) 570 result.AppendError(llvm::toString(std::move(err))); 571 else 572 result.AppendErrorWithFormat( 573 "unknown regex error when compiling '%s'", entry.c_str()); 574 } 575 } else // No regex, either exact variable names or variable 576 // expressions. 577 { 578 Status error; 579 uint32_t expr_path_options = 580 StackFrame::eExpressionPathOptionCheckPtrVsMember | 581 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 582 StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 583 lldb::VariableSP var_sp; 584 valobj_sp = frame->GetValueForVariableExpressionPath( 585 entry.ref(), m_varobj_options.use_dynamic, expr_path_options, 586 var_sp, error); 587 if (valobj_sp) { 588 std::string scope_string; 589 if (m_option_variable.show_scope) 590 scope_string = GetScopeString(var_sp).str(); 591 592 if (!scope_string.empty()) 593 s.PutCString(scope_string); 594 if (m_option_variable.show_decl && var_sp && 595 var_sp->GetDeclaration().GetFile()) { 596 var_sp->GetDeclaration().DumpStopContext(&s, false); 597 s.PutCString(": "); 598 } 599 600 options.SetFormat(format); 601 options.SetVariableFormatDisplayLanguage( 602 valobj_sp->GetPreferredDisplayLanguage()); 603 604 Stream &output_stream = result.GetOutputStream(); 605 options.SetRootValueObjectName( 606 valobj_sp->GetParent() ? entry.c_str() : nullptr); 607 valobj_sp->Dump(output_stream, options); 608 } else { 609 if (auto error_cstr = error.AsCString(nullptr)) 610 result.AppendError(error_cstr); 611 else 612 result.AppendErrorWithFormat( 613 "unable to find any variable expression path that matches " 614 "'%s'.", 615 entry.c_str()); 616 } 617 } 618 } 619 } else // No command arg specified. Use variable_list, instead. 620 { 621 const size_t num_variables = variable_list->GetSize(); 622 if (num_variables > 0) { 623 for (size_t i = 0; i < num_variables; i++) { 624 var_sp = variable_list->GetVariableAtIndex(i); 625 switch (var_sp->GetScope()) { 626 case eValueTypeVariableGlobal: 627 if (!m_option_variable.show_globals) 628 continue; 629 break; 630 case eValueTypeVariableStatic: 631 if (!m_option_variable.show_globals) 632 continue; 633 break; 634 case eValueTypeVariableArgument: 635 if (!m_option_variable.show_args) 636 continue; 637 break; 638 case eValueTypeVariableLocal: 639 if (!m_option_variable.show_locals) 640 continue; 641 break; 642 default: 643 continue; 644 break; 645 } 646 std::string scope_string; 647 if (m_option_variable.show_scope) 648 scope_string = GetScopeString(var_sp).str(); 649 650 // Use the variable object code to make sure we are using the same 651 // APIs as the public API will be using... 652 valobj_sp = frame->GetValueObjectForFrameVariable( 653 var_sp, m_varobj_options.use_dynamic); 654 if (valobj_sp) { 655 // When dumping all variables, don't print any variables that are 656 // not in scope to avoid extra unneeded output 657 if (valobj_sp->IsInScope()) { 658 if (!valobj_sp->GetTargetSP() 659 ->GetDisplayRuntimeSupportValues() && 660 valobj_sp->IsRuntimeSupportValue()) 661 continue; 662 663 if (!scope_string.empty()) 664 s.PutCString(scope_string); 665 666 if (m_option_variable.show_decl && 667 var_sp->GetDeclaration().GetFile()) { 668 var_sp->GetDeclaration().DumpStopContext(&s, false); 669 s.PutCString(": "); 670 } 671 672 options.SetFormat(format); 673 options.SetVariableFormatDisplayLanguage( 674 valobj_sp->GetPreferredDisplayLanguage()); 675 options.SetRootValueObjectName( 676 var_sp ? var_sp->GetName().AsCString() : nullptr); 677 valobj_sp->Dump(result.GetOutputStream(), options); 678 } 679 } 680 } 681 } 682 } 683 if (result.GetStatus() != eReturnStatusFailed) 684 result.SetStatus(eReturnStatusSuccessFinishResult); 685 } 686 687 if (m_option_variable.show_recognized_args) { 688 auto recognized_frame = frame->GetRecognizedFrame(); 689 if (recognized_frame) { 690 ValueObjectListSP recognized_arg_list = 691 recognized_frame->GetRecognizedArguments(); 692 if (recognized_arg_list) { 693 for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { 694 options.SetFormat(m_option_format.GetFormat()); 695 options.SetVariableFormatDisplayLanguage( 696 rec_value_sp->GetPreferredDisplayLanguage()); 697 options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); 698 rec_value_sp->Dump(result.GetOutputStream(), options); 699 } 700 } 701 } 702 } 703 704 m_interpreter.PrintWarningsIfNecessary(result.GetOutputStream(), 705 m_cmd_name); 706 707 // Increment statistics. 708 bool res = result.Succeeded(); 709 TargetStats &target_stats = GetSelectedOrDummyTarget().GetStatistics(); 710 if (res) 711 target_stats.GetFrameVariableStats().NotifySuccess(); 712 else 713 target_stats.GetFrameVariableStats().NotifyFailure(); 714 return res; 715 } 716 717 OptionGroupOptions m_option_group; 718 OptionGroupVariable m_option_variable; 719 OptionGroupFormat m_option_format; 720 OptionGroupValueObjectDisplay m_varobj_options; 721 }; 722 723 #pragma mark CommandObjectFrameRecognizer 724 725 #define LLDB_OPTIONS_frame_recognizer_add 726 #include "CommandOptions.inc" 727 728 class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { 729 private: 730 class CommandOptions : public Options { 731 public: 732 CommandOptions() = default; 733 ~CommandOptions() override = default; 734 735 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 736 ExecutionContext *execution_context) override { 737 Status error; 738 const int short_option = m_getopt_table[option_idx].val; 739 740 switch (short_option) { 741 case 'f': { 742 bool value, success; 743 value = OptionArgParser::ToBoolean(option_arg, true, &success); 744 if (success) { 745 m_first_instruction_only = value; 746 } else { 747 error.SetErrorStringWithFormat( 748 "invalid boolean value '%s' passed for -f option", 749 option_arg.str().c_str()); 750 } 751 } break; 752 case 'l': 753 m_class_name = std::string(option_arg); 754 break; 755 case 's': 756 m_module = std::string(option_arg); 757 break; 758 case 'n': 759 m_symbols.push_back(std::string(option_arg)); 760 break; 761 case 'x': 762 m_regex = true; 763 break; 764 default: 765 llvm_unreachable("Unimplemented option"); 766 } 767 768 return error; 769 } 770 771 void OptionParsingStarting(ExecutionContext *execution_context) override { 772 m_module = ""; 773 m_symbols.clear(); 774 m_class_name = ""; 775 m_regex = false; 776 m_first_instruction_only = true; 777 } 778 779 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 780 return llvm::ArrayRef(g_frame_recognizer_add_options); 781 } 782 783 // Instance variables to hold the values for command options. 784 std::string m_class_name; 785 std::string m_module; 786 std::vector<std::string> m_symbols; 787 bool m_regex; 788 bool m_first_instruction_only; 789 }; 790 791 CommandOptions m_options; 792 793 Options *GetOptions() override { return &m_options; } 794 795 protected: 796 bool DoExecute(Args &command, CommandReturnObject &result) override; 797 798 public: 799 CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 800 : CommandObjectParsed(interpreter, "frame recognizer add", 801 "Add a new frame recognizer.", nullptr) { 802 SetHelpLong(R"( 803 Frame recognizers allow for retrieving information about special frames based on 804 ABI, arguments or other special properties of that frame, even without source 805 code or debug info. Currently, one use case is to extract function arguments 806 that would otherwise be unaccesible, or augment existing arguments. 807 808 Adding a custom frame recognizer is possible by implementing a Python class 809 and using the 'frame recognizer add' command. The Python class should have a 810 'get_recognized_arguments' method and it will receive an argument of type 811 lldb.SBFrame representing the current frame that we are trying to recognize. 812 The method should return a (possibly empty) list of lldb.SBValue objects that 813 represent the recognized arguments. 814 815 An example of a recognizer that retrieves the file descriptor values from libc 816 functions 'read', 'write' and 'close' follows: 817 818 class LibcFdRecognizer(object): 819 def get_recognized_arguments(self, frame): 820 if frame.name in ["read", "write", "close"]: 821 fd = frame.EvaluateExpression("$arg1").unsigned 822 target = frame.thread.process.target 823 value = target.CreateValueFromExpression("fd", "(int)%d" % fd) 824 return [value] 825 return [] 826 827 The file containing this implementation can be imported via 'command script 828 import' and then we can register this recognizer with 'frame recognizer add'. 829 It's important to restrict the recognizer to the libc library (which is 830 libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 831 in other modules: 832 833 (lldb) command script import .../fd_recognizer.py 834 (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 835 836 When the program is stopped at the beginning of the 'read' function in libc, we 837 can view the recognizer arguments in 'frame variable': 838 839 (lldb) b read 840 (lldb) r 841 Process 1234 stopped 842 * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 843 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 844 (lldb) frame variable 845 (int) fd = 3 846 847 )"); 848 } 849 ~CommandObjectFrameRecognizerAdd() override = default; 850 }; 851 852 bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 853 CommandReturnObject &result) { 854 #if LLDB_ENABLE_PYTHON 855 if (m_options.m_class_name.empty()) { 856 result.AppendErrorWithFormat( 857 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 858 return false; 859 } 860 861 if (m_options.m_module.empty()) { 862 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 863 m_cmd_name.c_str()); 864 return false; 865 } 866 867 if (m_options.m_symbols.empty()) { 868 result.AppendErrorWithFormat( 869 "%s needs at least one symbol name (-n argument).\n", 870 m_cmd_name.c_str()); 871 return false; 872 } 873 874 if (m_options.m_regex && m_options.m_symbols.size() > 1) { 875 result.AppendErrorWithFormat( 876 "%s needs only one symbol regular expression (-n argument).\n", 877 m_cmd_name.c_str()); 878 return false; 879 } 880 881 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 882 883 if (interpreter && 884 !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 885 result.AppendWarning("The provided class does not exist - please define it " 886 "before attempting to use this frame recognizer"); 887 } 888 889 StackFrameRecognizerSP recognizer_sp = 890 StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 891 interpreter, m_options.m_class_name.c_str())); 892 if (m_options.m_regex) { 893 auto module = 894 RegularExpressionSP(new RegularExpression(m_options.m_module)); 895 auto func = 896 RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); 897 GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 898 recognizer_sp, module, func, m_options.m_first_instruction_only); 899 } else { 900 auto module = ConstString(m_options.m_module); 901 std::vector<ConstString> symbols(m_options.m_symbols.begin(), 902 m_options.m_symbols.end()); 903 GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 904 recognizer_sp, module, symbols, m_options.m_first_instruction_only); 905 } 906 #endif 907 908 result.SetStatus(eReturnStatusSuccessFinishNoResult); 909 return result.Succeeded(); 910 } 911 912 class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 913 public: 914 CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 915 : CommandObjectParsed(interpreter, "frame recognizer clear", 916 "Delete all frame recognizers.", nullptr) {} 917 918 ~CommandObjectFrameRecognizerClear() override = default; 919 920 protected: 921 bool DoExecute(Args &command, CommandReturnObject &result) override { 922 GetSelectedOrDummyTarget() 923 .GetFrameRecognizerManager() 924 .RemoveAllRecognizers(); 925 result.SetStatus(eReturnStatusSuccessFinishResult); 926 return result.Succeeded(); 927 } 928 }; 929 930 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 931 public: 932 CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 933 : CommandObjectParsed(interpreter, "frame recognizer delete", 934 "Delete an existing frame recognizer by id.", 935 nullptr) { 936 CommandArgumentData thread_arg{eArgTypeRecognizerID, eArgRepeatPlain}; 937 m_arguments.push_back({thread_arg}); 938 } 939 940 ~CommandObjectFrameRecognizerDelete() override = default; 941 942 void 943 HandleArgumentCompletion(CompletionRequest &request, 944 OptionElementVector &opt_element_vector) override { 945 if (request.GetCursorIndex() != 0) 946 return; 947 948 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 949 [&request](uint32_t rid, std::string rname, std::string module, 950 llvm::ArrayRef<lldb_private::ConstString> symbols, 951 bool regexp) { 952 StreamString strm; 953 if (rname.empty()) 954 rname = "(internal)"; 955 956 strm << rname; 957 if (!module.empty()) 958 strm << ", module " << module; 959 if (!symbols.empty()) 960 for (auto &symbol : symbols) 961 strm << ", symbol " << symbol; 962 if (regexp) 963 strm << " (regexp)"; 964 965 request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString()); 966 }); 967 } 968 969 protected: 970 bool DoExecute(Args &command, CommandReturnObject &result) override { 971 if (command.GetArgumentCount() == 0) { 972 if (!m_interpreter.Confirm( 973 "About to delete all frame recognizers, do you want to do that?", 974 true)) { 975 result.AppendMessage("Operation cancelled..."); 976 return false; 977 } 978 979 GetSelectedOrDummyTarget() 980 .GetFrameRecognizerManager() 981 .RemoveAllRecognizers(); 982 result.SetStatus(eReturnStatusSuccessFinishResult); 983 return result.Succeeded(); 984 } 985 986 if (command.GetArgumentCount() != 1) { 987 result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 988 m_cmd_name.c_str()); 989 return false; 990 } 991 992 uint32_t recognizer_id; 993 if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) { 994 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 995 command.GetArgumentAtIndex(0)); 996 return false; 997 } 998 999 if (!GetSelectedOrDummyTarget() 1000 .GetFrameRecognizerManager() 1001 .RemoveRecognizerWithID(recognizer_id)) { 1002 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 1003 command.GetArgumentAtIndex(0)); 1004 return false; 1005 } 1006 result.SetStatus(eReturnStatusSuccessFinishResult); 1007 return result.Succeeded(); 1008 } 1009 }; 1010 1011 class CommandObjectFrameRecognizerList : public CommandObjectParsed { 1012 public: 1013 CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 1014 : CommandObjectParsed(interpreter, "frame recognizer list", 1015 "Show a list of active frame recognizers.", 1016 nullptr) {} 1017 1018 ~CommandObjectFrameRecognizerList() override = default; 1019 1020 protected: 1021 bool DoExecute(Args &command, CommandReturnObject &result) override { 1022 bool any_printed = false; 1023 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 1024 [&result, &any_printed]( 1025 uint32_t recognizer_id, std::string name, std::string module, 1026 llvm::ArrayRef<ConstString> symbols, bool regexp) { 1027 Stream &stream = result.GetOutputStream(); 1028 1029 if (name.empty()) 1030 name = "(internal)"; 1031 1032 stream << std::to_string(recognizer_id) << ": " << name; 1033 if (!module.empty()) 1034 stream << ", module " << module; 1035 if (!symbols.empty()) 1036 for (auto &symbol : symbols) 1037 stream << ", symbol " << symbol; 1038 if (regexp) 1039 stream << " (regexp)"; 1040 1041 stream.EOL(); 1042 stream.Flush(); 1043 1044 any_printed = true; 1045 }); 1046 1047 if (any_printed) 1048 result.SetStatus(eReturnStatusSuccessFinishResult); 1049 else { 1050 result.GetOutputStream().PutCString("no matching results found.\n"); 1051 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1052 } 1053 return result.Succeeded(); 1054 } 1055 }; 1056 1057 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 1058 public: 1059 CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 1060 : CommandObjectParsed( 1061 interpreter, "frame recognizer info", 1062 "Show which frame recognizer is applied a stack frame (if any).", 1063 nullptr) { 1064 CommandArgumentEntry arg; 1065 CommandArgumentData index_arg; 1066 1067 // Define the first (and only) variant of this arg. 1068 index_arg.arg_type = eArgTypeFrameIndex; 1069 index_arg.arg_repetition = eArgRepeatPlain; 1070 1071 // There is only one variant this argument could be; put it into the 1072 // argument entry. 1073 arg.push_back(index_arg); 1074 1075 // Push the data for the first argument into the m_arguments vector. 1076 m_arguments.push_back(arg); 1077 } 1078 1079 ~CommandObjectFrameRecognizerInfo() override = default; 1080 1081 protected: 1082 bool DoExecute(Args &command, CommandReturnObject &result) override { 1083 const char *frame_index_str = command.GetArgumentAtIndex(0); 1084 uint32_t frame_index; 1085 if (!llvm::to_integer(frame_index_str, frame_index)) { 1086 result.AppendErrorWithFormat("'%s' is not a valid frame index.", 1087 frame_index_str); 1088 return false; 1089 } 1090 1091 Process *process = m_exe_ctx.GetProcessPtr(); 1092 if (process == nullptr) { 1093 result.AppendError("no process"); 1094 return false; 1095 } 1096 Thread *thread = m_exe_ctx.GetThreadPtr(); 1097 if (thread == nullptr) { 1098 result.AppendError("no thread"); 1099 return false; 1100 } 1101 if (command.GetArgumentCount() != 1) { 1102 result.AppendErrorWithFormat( 1103 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 1104 return false; 1105 } 1106 1107 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 1108 if (!frame_sp) { 1109 result.AppendErrorWithFormat("no frame with index %u", frame_index); 1110 return false; 1111 } 1112 1113 auto recognizer = GetSelectedOrDummyTarget() 1114 .GetFrameRecognizerManager() 1115 .GetRecognizerForFrame(frame_sp); 1116 1117 Stream &output_stream = result.GetOutputStream(); 1118 output_stream.Printf("frame %d ", frame_index); 1119 if (recognizer) { 1120 output_stream << "is recognized by "; 1121 output_stream << recognizer->GetName(); 1122 } else { 1123 output_stream << "not recognized by any recognizer"; 1124 } 1125 output_stream.EOL(); 1126 result.SetStatus(eReturnStatusSuccessFinishResult); 1127 return result.Succeeded(); 1128 } 1129 }; 1130 1131 class CommandObjectFrameRecognizer : public CommandObjectMultiword { 1132 public: 1133 CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 1134 : CommandObjectMultiword( 1135 interpreter, "frame recognizer", 1136 "Commands for editing and viewing frame recognizers.", 1137 "frame recognizer [<sub-command-options>] ") { 1138 LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd( 1139 interpreter))); 1140 LoadSubCommand( 1141 "clear", 1142 CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 1143 LoadSubCommand( 1144 "delete", 1145 CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 1146 LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList( 1147 interpreter))); 1148 LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo( 1149 interpreter))); 1150 } 1151 1152 ~CommandObjectFrameRecognizer() override = default; 1153 }; 1154 1155 #pragma mark CommandObjectMultiwordFrame 1156 1157 // CommandObjectMultiwordFrame 1158 1159 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1160 CommandInterpreter &interpreter) 1161 : CommandObjectMultiword(interpreter, "frame", 1162 "Commands for selecting and " 1163 "examing the current " 1164 "thread's stack frames.", 1165 "frame <subcommand> [<subcommand-options>]") { 1166 LoadSubCommand("diagnose", 1167 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1168 LoadSubCommand("info", 1169 CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1170 LoadSubCommand("select", 1171 CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1172 LoadSubCommand("variable", 1173 CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 1174 #if LLDB_ENABLE_PYTHON 1175 LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer( 1176 interpreter))); 1177 #endif 1178 } 1179 1180 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1181