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