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/CommandReturnObject.h" 17 #include "lldb/Interpreter/OptionArgParser.h" 18 #include "lldb/Interpreter/OptionGroupFormat.h" 19 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" 20 #include "lldb/Interpreter/OptionGroupVariable.h" 21 #include "lldb/Interpreter/Options.h" 22 #include "lldb/Symbol/Function.h" 23 #include "lldb/Symbol/SymbolContext.h" 24 #include "lldb/Symbol/Variable.h" 25 #include "lldb/Symbol/VariableList.h" 26 #include "lldb/Target/StackFrame.h" 27 #include "lldb/Target/StackFrameRecognizer.h" 28 #include "lldb/Target/StopInfo.h" 29 #include "lldb/Target/Target.h" 30 #include "lldb/Target/Thread.h" 31 #include "lldb/Utility/Args.h" 32 33 #include <memory> 34 #include <string> 35 36 using namespace lldb; 37 using namespace lldb_private; 38 39 #pragma mark CommandObjectFrameDiagnose 40 41 // CommandObjectFrameInfo 42 43 // CommandObjectFrameDiagnose 44 45 #define LLDB_OPTIONS_frame_diag 46 #include "CommandOptions.inc" 47 48 class CommandObjectFrameDiagnose : public CommandObjectParsed { 49 public: 50 class CommandOptions : public Options { 51 public: 52 CommandOptions() : Options() { OptionParsingStarting(nullptr); } 53 54 ~CommandOptions() override = default; 55 56 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 57 ExecutionContext *execution_context) override { 58 Status error; 59 const int short_option = m_getopt_table[option_idx].val; 60 switch (short_option) { 61 case 'r': 62 reg = ConstString(option_arg); 63 break; 64 65 case 'a': { 66 address.emplace(); 67 if (option_arg.getAsInteger(0, *address)) { 68 address.reset(); 69 error.SetErrorStringWithFormat("invalid address argument '%s'", 70 option_arg.str().c_str()); 71 } 72 } break; 73 74 case 'o': { 75 offset.emplace(); 76 if (option_arg.getAsInteger(0, *offset)) { 77 offset.reset(); 78 error.SetErrorStringWithFormat("invalid offset argument '%s'", 79 option_arg.str().c_str()); 80 } 81 } break; 82 83 default: 84 llvm_unreachable("Unimplemented option"); 85 } 86 87 return error; 88 } 89 90 void OptionParsingStarting(ExecutionContext *execution_context) override { 91 address.reset(); 92 reg.reset(); 93 offset.reset(); 94 } 95 96 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 97 return llvm::makeArrayRef(g_frame_diag_options); 98 } 99 100 // Options. 101 llvm::Optional<lldb::addr_t> address; 102 llvm::Optional<ConstString> reg; 103 llvm::Optional<int64_t> offset; 104 }; 105 106 CommandObjectFrameDiagnose(CommandInterpreter &interpreter) 107 : CommandObjectParsed(interpreter, "frame diagnose", 108 "Try to determine what path the current stop " 109 "location used to get to a register or address", 110 nullptr, 111 eCommandRequiresThread | eCommandTryTargetAPILock | 112 eCommandProcessMustBeLaunched | 113 eCommandProcessMustBePaused), 114 m_options() { 115 CommandArgumentEntry arg; 116 CommandArgumentData index_arg; 117 118 // Define the first (and only) variant of this arg. 119 index_arg.arg_type = eArgTypeFrameIndex; 120 index_arg.arg_repetition = eArgRepeatOptional; 121 122 // There is only one variant this argument could be; put it into the 123 // argument entry. 124 arg.push_back(index_arg); 125 126 // Push the data for the first argument into the m_arguments vector. 127 m_arguments.push_back(arg); 128 } 129 130 ~CommandObjectFrameDiagnose() override = default; 131 132 Options *GetOptions() override { return &m_options; } 133 134 protected: 135 bool DoExecute(Args &command, CommandReturnObject &result) override { 136 Thread *thread = m_exe_ctx.GetThreadPtr(); 137 StackFrameSP frame_sp = thread->GetSelectedFrame(); 138 139 ValueObjectSP valobj_sp; 140 141 if (m_options.address.hasValue()) { 142 if (m_options.reg.hasValue() || m_options.offset.hasValue()) { 143 result.AppendError( 144 "`frame diagnose --address` is incompatible with other arguments."); 145 return false; 146 } 147 valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue()); 148 } else if (m_options.reg.hasValue()) { 149 valobj_sp = frame_sp->GuessValueForRegisterAndOffset( 150 m_options.reg.getValue(), m_options.offset.getValueOr(0)); 151 } else { 152 StopInfoSP stop_info_sp = thread->GetStopInfo(); 153 if (!stop_info_sp) { 154 result.AppendError("No arguments provided, and no stop info."); 155 return false; 156 } 157 158 valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp); 159 } 160 161 if (!valobj_sp) { 162 result.AppendError("No diagnosis available."); 163 return false; 164 } 165 166 DumpValueObjectOptions::DeclPrintingHelper helper = 167 [&valobj_sp](ConstString type, ConstString var, 168 const DumpValueObjectOptions &opts, 169 Stream &stream) -> bool { 170 const ValueObject::GetExpressionPathFormat format = ValueObject:: 171 GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers; 172 valobj_sp->GetExpressionPath(stream, format); 173 stream.PutCString(" ="); 174 return true; 175 }; 176 177 DumpValueObjectOptions options; 178 options.SetDeclPrintingHelper(helper); 179 ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), 180 options); 181 printer.PrintValueObject(); 182 183 return true; 184 } 185 186 CommandOptions m_options; 187 }; 188 189 #pragma mark CommandObjectFrameInfo 190 191 // CommandObjectFrameInfo 192 193 class CommandObjectFrameInfo : public CommandObjectParsed { 194 public: 195 CommandObjectFrameInfo(CommandInterpreter &interpreter) 196 : CommandObjectParsed(interpreter, "frame info", 197 "List information about the current " 198 "stack frame in the current thread.", 199 "frame info", 200 eCommandRequiresFrame | eCommandTryTargetAPILock | 201 eCommandProcessMustBeLaunched | 202 eCommandProcessMustBePaused) {} 203 204 ~CommandObjectFrameInfo() override = default; 205 206 protected: 207 bool DoExecute(Args &command, CommandReturnObject &result) override { 208 m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream()); 209 result.SetStatus(eReturnStatusSuccessFinishResult); 210 return result.Succeeded(); 211 } 212 }; 213 214 #pragma mark CommandObjectFrameSelect 215 216 // CommandObjectFrameSelect 217 218 #define LLDB_OPTIONS_frame_select 219 #include "CommandOptions.inc" 220 221 class CommandObjectFrameSelect : public CommandObjectParsed { 222 public: 223 class CommandOptions : public Options { 224 public: 225 CommandOptions() : Options() { OptionParsingStarting(nullptr); } 226 227 ~CommandOptions() override = default; 228 229 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 230 ExecutionContext *execution_context) override { 231 Status error; 232 const int short_option = m_getopt_table[option_idx].val; 233 switch (short_option) { 234 case 'r': { 235 int32_t offset = 0; 236 if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) { 237 error.SetErrorStringWithFormat("invalid frame offset argument '%s'", 238 option_arg.str().c_str()); 239 } else 240 relative_frame_offset = offset; 241 break; 242 } 243 244 default: 245 llvm_unreachable("Unimplemented option"); 246 } 247 248 return error; 249 } 250 251 void OptionParsingStarting(ExecutionContext *execution_context) override { 252 relative_frame_offset.reset(); 253 } 254 255 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 256 return llvm::makeArrayRef(g_frame_select_options); 257 } 258 259 llvm::Optional<int32_t> relative_frame_offset; 260 }; 261 262 CommandObjectFrameSelect(CommandInterpreter &interpreter) 263 : CommandObjectParsed(interpreter, "frame select", 264 "Select the current stack frame by " 265 "index from within the current thread " 266 "(see 'thread backtrace'.)", 267 nullptr, 268 eCommandRequiresThread | eCommandTryTargetAPILock | 269 eCommandProcessMustBeLaunched | 270 eCommandProcessMustBePaused), 271 m_options() { 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.hasValue()) { 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 "Children of aggregate variables can be specified such as " 399 "'var->child.x'. The -> and [] operators in 'frame variable' do " 400 "not invoke operator overloads if they exist, but directly access " 401 "the specified element. If you want to trigger operator overloads " 402 "use the expression command to print the variable instead." 403 "\nIt is worth noting that except for overloaded " 404 "operators, when printing local variables 'expr local_var' and " 405 "'frame var local_var' produce the same " 406 "results. However, 'frame variable' is more efficient, since it " 407 "uses debug information and memory reads directly, rather than " 408 "parsing and evaluating an expression, which may even involve " 409 "JITing and running code in the target program.", 410 nullptr, 411 eCommandRequiresFrame | eCommandTryTargetAPILock | 412 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | 413 eCommandRequiresProcess), 414 m_option_group(), 415 m_option_variable( 416 true), // Include the frame specific options by passing "true" 417 m_option_format(eFormatDefault), m_varobj_options() { 418 CommandArgumentEntry arg; 419 CommandArgumentData var_name_arg; 420 421 // Define the first (and only) variant of this arg. 422 var_name_arg.arg_type = eArgTypeVarName; 423 var_name_arg.arg_repetition = eArgRepeatStar; 424 425 // There is only one variant this argument could be; put it into the 426 // argument entry. 427 arg.push_back(var_name_arg); 428 429 // Push the data for the first argument into the m_arguments vector. 430 m_arguments.push_back(arg); 431 432 m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 433 m_option_group.Append(&m_option_format, 434 OptionGroupFormat::OPTION_GROUP_FORMAT | 435 OptionGroupFormat::OPTION_GROUP_GDB_FMT, 436 LLDB_OPT_SET_1); 437 m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 438 m_option_group.Finalize(); 439 } 440 441 ~CommandObjectFrameVariable() override = default; 442 443 Options *GetOptions() override { return &m_option_group; } 444 445 void 446 HandleArgumentCompletion(CompletionRequest &request, 447 OptionElementVector &opt_element_vector) override { 448 // Arguments are the standard source file completer. 449 CommandCompletions::InvokeCommonCompletionCallbacks( 450 GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, 451 request, nullptr); 452 } 453 454 protected: 455 llvm::StringRef GetScopeString(VariableSP var_sp) { 456 if (!var_sp) 457 return llvm::StringRef(); 458 459 switch (var_sp->GetScope()) { 460 case eValueTypeVariableGlobal: 461 return "GLOBAL: "; 462 case eValueTypeVariableStatic: 463 return "STATIC: "; 464 case eValueTypeVariableArgument: 465 return "ARG: "; 466 case eValueTypeVariableLocal: 467 return "LOCAL: "; 468 case eValueTypeVariableThreadLocal: 469 return "THREAD: "; 470 default: 471 break; 472 } 473 474 return llvm::StringRef(); 475 } 476 477 bool DoExecute(Args &command, CommandReturnObject &result) override { 478 // No need to check "frame" for validity as eCommandRequiresFrame ensures 479 // it is valid 480 StackFrame *frame = m_exe_ctx.GetFramePtr(); 481 482 Stream &s = result.GetOutputStream(); 483 484 // Be careful about the stack frame, if any summary formatter runs code, it 485 // might clear the StackFrameList for the thread. So hold onto a shared 486 // pointer to the frame so it stays alive. 487 488 VariableList *variable_list = 489 frame->GetVariableList(m_option_variable.show_globals); 490 491 VariableSP var_sp; 492 ValueObjectSP valobj_sp; 493 494 TypeSummaryImplSP summary_format_sp; 495 if (!m_option_variable.summary.IsCurrentValueEmpty()) 496 DataVisualization::NamedSummaryFormats::GetSummaryFormat( 497 ConstString(m_option_variable.summary.GetCurrentValue()), 498 summary_format_sp); 499 else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 500 summary_format_sp = std::make_shared<StringSummaryFormat>( 501 TypeSummaryImpl::Flags(), 502 m_option_variable.summary_string.GetCurrentValue()); 503 504 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( 505 eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault, 506 summary_format_sp)); 507 508 const SymbolContext &sym_ctx = 509 frame->GetSymbolContext(eSymbolContextFunction); 510 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 511 m_option_variable.show_globals = true; 512 513 if (variable_list) { 514 const Format format = m_option_format.GetFormat(); 515 options.SetFormat(format); 516 517 if (!command.empty()) { 518 VariableList regex_var_list; 519 520 // If we have any args to the variable command, we will make variable 521 // objects from them... 522 for (auto &entry : command) { 523 if (m_option_variable.use_regex) { 524 const size_t regex_start_index = regex_var_list.GetSize(); 525 llvm::StringRef name_str = entry.ref(); 526 RegularExpression regex(name_str); 527 if (regex.IsValid()) { 528 size_t num_matches = 0; 529 const size_t num_new_regex_vars = 530 variable_list->AppendVariablesIfUnique(regex, regex_var_list, 531 num_matches); 532 if (num_new_regex_vars > 0) { 533 for (size_t regex_idx = regex_start_index, 534 end_index = regex_var_list.GetSize(); 535 regex_idx < end_index; ++regex_idx) { 536 var_sp = regex_var_list.GetVariableAtIndex(regex_idx); 537 if (var_sp) { 538 valobj_sp = frame->GetValueObjectForFrameVariable( 539 var_sp, m_varobj_options.use_dynamic); 540 if (valobj_sp) { 541 std::string scope_string; 542 if (m_option_variable.show_scope) 543 scope_string = GetScopeString(var_sp).str(); 544 545 if (!scope_string.empty()) 546 s.PutCString(scope_string); 547 548 if (m_option_variable.show_decl && 549 var_sp->GetDeclaration().GetFile()) { 550 bool show_fullpaths = false; 551 bool show_module = true; 552 if (var_sp->DumpDeclaration(&s, show_fullpaths, 553 show_module)) 554 s.PutCString(": "); 555 } 556 valobj_sp->Dump(result.GetOutputStream(), options); 557 } 558 } 559 } 560 } else if (num_matches == 0) { 561 result.GetErrorStream().Printf("error: no variables matched " 562 "the regular expression '%s'.\n", 563 entry.c_str()); 564 } 565 } else { 566 if (llvm::Error err = regex.GetError()) 567 result.GetErrorStream().Printf( 568 "error: %s\n", llvm::toString(std::move(err)).c_str()); 569 else 570 result.GetErrorStream().Printf( 571 "error: unknown regex error when compiling '%s'\n", 572 entry.c_str()); 573 } 574 } else // No regex, either exact variable names or variable 575 // expressions. 576 { 577 Status error; 578 uint32_t expr_path_options = 579 StackFrame::eExpressionPathOptionCheckPtrVsMember | 580 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 581 StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 582 lldb::VariableSP var_sp; 583 valobj_sp = frame->GetValueForVariableExpressionPath( 584 entry.ref(), m_varobj_options.use_dynamic, expr_path_options, 585 var_sp, error); 586 if (valobj_sp) { 587 std::string scope_string; 588 if (m_option_variable.show_scope) 589 scope_string = GetScopeString(var_sp).str(); 590 591 if (!scope_string.empty()) 592 s.PutCString(scope_string); 593 if (m_option_variable.show_decl && var_sp && 594 var_sp->GetDeclaration().GetFile()) { 595 var_sp->GetDeclaration().DumpStopContext(&s, false); 596 s.PutCString(": "); 597 } 598 599 options.SetFormat(format); 600 options.SetVariableFormatDisplayLanguage( 601 valobj_sp->GetPreferredDisplayLanguage()); 602 603 Stream &output_stream = result.GetOutputStream(); 604 options.SetRootValueObjectName( 605 valobj_sp->GetParent() ? entry.c_str() : nullptr); 606 valobj_sp->Dump(output_stream, options); 607 } else { 608 const char *error_cstr = error.AsCString(nullptr); 609 if (error_cstr) 610 result.GetErrorStream().Printf("error: %s\n", error_cstr); 611 else 612 result.GetErrorStream().Printf("error: unable to find any " 613 "variable expression path that " 614 "matches '%s'.\n", 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 result.SetStatus(eReturnStatusSuccessFinishResult); 684 } 685 686 if (m_option_variable.show_recognized_args) { 687 auto recognized_frame = frame->GetRecognizedFrame(); 688 if (recognized_frame) { 689 ValueObjectListSP recognized_arg_list = 690 recognized_frame->GetRecognizedArguments(); 691 if (recognized_arg_list) { 692 for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { 693 options.SetFormat(m_option_format.GetFormat()); 694 options.SetVariableFormatDisplayLanguage( 695 rec_value_sp->GetPreferredDisplayLanguage()); 696 options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); 697 rec_value_sp->Dump(result.GetOutputStream(), options); 698 } 699 } 700 } 701 } 702 703 if (m_interpreter.TruncationWarningNecessary()) { 704 result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 705 m_cmd_name.c_str()); 706 m_interpreter.TruncationWarningGiven(); 707 } 708 709 // Increment statistics. 710 bool res = result.Succeeded(); 711 TargetStats &target_stats = GetSelectedOrDummyTarget().GetStatistics(); 712 if (res) 713 target_stats.GetFrameVariableStats().NotifySuccess(); 714 else 715 target_stats.GetFrameVariableStats().NotifyFailure(); 716 return res; 717 } 718 719 OptionGroupOptions m_option_group; 720 OptionGroupVariable m_option_variable; 721 OptionGroupFormat m_option_format; 722 OptionGroupValueObjectDisplay m_varobj_options; 723 }; 724 725 #pragma mark CommandObjectFrameRecognizer 726 727 #define LLDB_OPTIONS_frame_recognizer_add 728 #include "CommandOptions.inc" 729 730 class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { 731 private: 732 class CommandOptions : public Options { 733 public: 734 CommandOptions() : Options() {} 735 ~CommandOptions() override = default; 736 737 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 738 ExecutionContext *execution_context) override { 739 Status error; 740 const int short_option = m_getopt_table[option_idx].val; 741 742 switch (short_option) { 743 case 'f': { 744 bool value, success; 745 value = OptionArgParser::ToBoolean(option_arg, true, &success); 746 if (success) { 747 m_first_instruction_only = value; 748 } else { 749 error.SetErrorStringWithFormat( 750 "invalid boolean value '%s' passed for -f option", 751 option_arg.str().c_str()); 752 } 753 } break; 754 case 'l': 755 m_class_name = std::string(option_arg); 756 break; 757 case 's': 758 m_module = std::string(option_arg); 759 break; 760 case 'n': 761 m_symbols.push_back(std::string(option_arg)); 762 break; 763 case 'x': 764 m_regex = true; 765 break; 766 default: 767 llvm_unreachable("Unimplemented option"); 768 } 769 770 return error; 771 } 772 773 void OptionParsingStarting(ExecutionContext *execution_context) override { 774 m_module = ""; 775 m_symbols.clear(); 776 m_class_name = ""; 777 m_regex = false; 778 m_first_instruction_only = true; 779 } 780 781 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 782 return llvm::makeArrayRef(g_frame_recognizer_add_options); 783 } 784 785 // Instance variables to hold the values for command options. 786 std::string m_class_name; 787 std::string m_module; 788 std::vector<std::string> m_symbols; 789 bool m_regex; 790 bool m_first_instruction_only; 791 }; 792 793 CommandOptions m_options; 794 795 Options *GetOptions() override { return &m_options; } 796 797 protected: 798 bool DoExecute(Args &command, CommandReturnObject &result) override; 799 800 public: 801 CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 802 : CommandObjectParsed(interpreter, "frame recognizer add", 803 "Add a new frame recognizer.", nullptr), 804 m_options() { 805 SetHelpLong(R"( 806 Frame recognizers allow for retrieving information about special frames based on 807 ABI, arguments or other special properties of that frame, even without source 808 code or debug info. Currently, one use case is to extract function arguments 809 that would otherwise be unaccesible, or augment existing arguments. 810 811 Adding a custom frame recognizer is possible by implementing a Python class 812 and using the 'frame recognizer add' command. The Python class should have a 813 'get_recognized_arguments' method and it will receive an argument of type 814 lldb.SBFrame representing the current frame that we are trying to recognize. 815 The method should return a (possibly empty) list of lldb.SBValue objects that 816 represent the recognized arguments. 817 818 An example of a recognizer that retrieves the file descriptor values from libc 819 functions 'read', 'write' and 'close' follows: 820 821 class LibcFdRecognizer(object): 822 def get_recognized_arguments(self, frame): 823 if frame.name in ["read", "write", "close"]: 824 fd = frame.EvaluateExpression("$arg1").unsigned 825 value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) 826 return [value] 827 return [] 828 829 The file containing this implementation can be imported via 'command script 830 import' and then we can register this recognizer with 'frame recognizer add'. 831 It's important to restrict the recognizer to the libc library (which is 832 libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 833 in other modules: 834 835 (lldb) command script import .../fd_recognizer.py 836 (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 837 838 When the program is stopped at the beginning of the 'read' function in libc, we 839 can view the recognizer arguments in 'frame variable': 840 841 (lldb) b read 842 (lldb) r 843 Process 1234 stopped 844 * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 845 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 846 (lldb) frame variable 847 (int) fd = 3 848 849 )"); 850 } 851 ~CommandObjectFrameRecognizerAdd() override = default; 852 }; 853 854 bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 855 CommandReturnObject &result) { 856 #if LLDB_ENABLE_PYTHON 857 if (m_options.m_class_name.empty()) { 858 result.AppendErrorWithFormat( 859 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 860 return false; 861 } 862 863 if (m_options.m_module.empty()) { 864 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 865 m_cmd_name.c_str()); 866 return false; 867 } 868 869 if (m_options.m_symbols.empty()) { 870 result.AppendErrorWithFormat( 871 "%s needs at least one symbol name (-n argument).\n", 872 m_cmd_name.c_str()); 873 return false; 874 } 875 876 if (m_options.m_regex && m_options.m_symbols.size() > 1) { 877 result.AppendErrorWithFormat( 878 "%s needs only one symbol regular expression (-n argument).\n", 879 m_cmd_name.c_str()); 880 return false; 881 } 882 883 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 884 885 if (interpreter && 886 !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 887 result.AppendWarning("The provided class does not exist - please define it " 888 "before attempting to use this frame recognizer"); 889 } 890 891 StackFrameRecognizerSP recognizer_sp = 892 StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 893 interpreter, m_options.m_class_name.c_str())); 894 if (m_options.m_regex) { 895 auto module = 896 RegularExpressionSP(new RegularExpression(m_options.m_module)); 897 auto func = 898 RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); 899 GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 900 recognizer_sp, module, func, m_options.m_first_instruction_only); 901 } else { 902 auto module = ConstString(m_options.m_module); 903 std::vector<ConstString> symbols(m_options.m_symbols.begin(), 904 m_options.m_symbols.end()); 905 GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 906 recognizer_sp, module, symbols, m_options.m_first_instruction_only); 907 } 908 #endif 909 910 result.SetStatus(eReturnStatusSuccessFinishNoResult); 911 return result.Succeeded(); 912 } 913 914 class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 915 public: 916 CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 917 : CommandObjectParsed(interpreter, "frame recognizer clear", 918 "Delete all frame recognizers.", nullptr) {} 919 920 ~CommandObjectFrameRecognizerClear() override = default; 921 922 protected: 923 bool DoExecute(Args &command, CommandReturnObject &result) override { 924 GetSelectedOrDummyTarget() 925 .GetFrameRecognizerManager() 926 .RemoveAllRecognizers(); 927 result.SetStatus(eReturnStatusSuccessFinishResult); 928 return result.Succeeded(); 929 } 930 }; 931 932 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 933 public: 934 CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 935 : CommandObjectParsed(interpreter, "frame recognizer delete", 936 "Delete an existing frame recognizer.", nullptr) {} 937 938 ~CommandObjectFrameRecognizerDelete() override = default; 939 940 void 941 HandleArgumentCompletion(CompletionRequest &request, 942 OptionElementVector &opt_element_vector) override { 943 if (request.GetCursorIndex() != 0) 944 return; 945 946 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 947 [&request](uint32_t rid, std::string rname, std::string module, 948 llvm::ArrayRef<lldb_private::ConstString> symbols, 949 bool regexp) { 950 StreamString strm; 951 if (rname.empty()) 952 rname = "(internal)"; 953 954 strm << rname; 955 if (!module.empty()) 956 strm << ", module " << module; 957 if (!symbols.empty()) 958 for (auto &symbol : symbols) 959 strm << ", symbol " << symbol; 960 if (regexp) 961 strm << " (regexp)"; 962 963 request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString()); 964 }); 965 } 966 967 protected: 968 bool DoExecute(Args &command, CommandReturnObject &result) override { 969 if (command.GetArgumentCount() == 0) { 970 if (!m_interpreter.Confirm( 971 "About to delete all frame recognizers, do you want to do that?", 972 true)) { 973 result.AppendMessage("Operation cancelled..."); 974 return false; 975 } 976 977 GetSelectedOrDummyTarget() 978 .GetFrameRecognizerManager() 979 .RemoveAllRecognizers(); 980 result.SetStatus(eReturnStatusSuccessFinishResult); 981 return result.Succeeded(); 982 } 983 984 if (command.GetArgumentCount() != 1) { 985 result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 986 m_cmd_name.c_str()); 987 return false; 988 } 989 990 uint32_t recognizer_id; 991 if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) { 992 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 993 command.GetArgumentAtIndex(0)); 994 return false; 995 } 996 997 if (!GetSelectedOrDummyTarget() 998 .GetFrameRecognizerManager() 999 .RemoveRecognizerWithID(recognizer_id)) { 1000 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 1001 command.GetArgumentAtIndex(0)); 1002 return false; 1003 } 1004 result.SetStatus(eReturnStatusSuccessFinishResult); 1005 return result.Succeeded(); 1006 } 1007 }; 1008 1009 class CommandObjectFrameRecognizerList : public CommandObjectParsed { 1010 public: 1011 CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 1012 : CommandObjectParsed(interpreter, "frame recognizer list", 1013 "Show a list of active frame recognizers.", 1014 nullptr) {} 1015 1016 ~CommandObjectFrameRecognizerList() override = default; 1017 1018 protected: 1019 bool DoExecute(Args &command, CommandReturnObject &result) override { 1020 bool any_printed = false; 1021 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 1022 [&result, &any_printed]( 1023 uint32_t recognizer_id, std::string name, std::string module, 1024 llvm::ArrayRef<ConstString> symbols, bool regexp) { 1025 Stream &stream = result.GetOutputStream(); 1026 1027 if (name.empty()) 1028 name = "(internal)"; 1029 1030 stream << std::to_string(recognizer_id) << ": " << name; 1031 if (!module.empty()) 1032 stream << ", module " << module; 1033 if (!symbols.empty()) 1034 for (auto &symbol : symbols) 1035 stream << ", symbol " << symbol; 1036 if (regexp) 1037 stream << " (regexp)"; 1038 1039 stream.EOL(); 1040 stream.Flush(); 1041 1042 any_printed = true; 1043 }); 1044 1045 if (any_printed) 1046 result.SetStatus(eReturnStatusSuccessFinishResult); 1047 else { 1048 result.GetOutputStream().PutCString("no matching results found.\n"); 1049 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1050 } 1051 return result.Succeeded(); 1052 } 1053 }; 1054 1055 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 1056 public: 1057 CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 1058 : CommandObjectParsed( 1059 interpreter, "frame recognizer info", 1060 "Show which frame recognizer is applied a stack frame (if any).", 1061 nullptr) { 1062 CommandArgumentEntry arg; 1063 CommandArgumentData index_arg; 1064 1065 // Define the first (and only) variant of this arg. 1066 index_arg.arg_type = eArgTypeFrameIndex; 1067 index_arg.arg_repetition = eArgRepeatPlain; 1068 1069 // There is only one variant this argument could be; put it into the 1070 // argument entry. 1071 arg.push_back(index_arg); 1072 1073 // Push the data for the first argument into the m_arguments vector. 1074 m_arguments.push_back(arg); 1075 } 1076 1077 ~CommandObjectFrameRecognizerInfo() override = default; 1078 1079 protected: 1080 bool DoExecute(Args &command, CommandReturnObject &result) override { 1081 const char *frame_index_str = command.GetArgumentAtIndex(0); 1082 uint32_t frame_index; 1083 if (!llvm::to_integer(frame_index_str, frame_index)) { 1084 result.AppendErrorWithFormat("'%s' is not a valid frame index.", 1085 frame_index_str); 1086 return false; 1087 } 1088 1089 Process *process = m_exe_ctx.GetProcessPtr(); 1090 if (process == nullptr) { 1091 result.AppendError("no process"); 1092 return false; 1093 } 1094 Thread *thread = m_exe_ctx.GetThreadPtr(); 1095 if (thread == nullptr) { 1096 result.AppendError("no thread"); 1097 return false; 1098 } 1099 if (command.GetArgumentCount() != 1) { 1100 result.AppendErrorWithFormat( 1101 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 1102 return false; 1103 } 1104 1105 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 1106 if (!frame_sp) { 1107 result.AppendErrorWithFormat("no frame with index %u", frame_index); 1108 return false; 1109 } 1110 1111 auto recognizer = GetSelectedOrDummyTarget() 1112 .GetFrameRecognizerManager() 1113 .GetRecognizerForFrame(frame_sp); 1114 1115 Stream &output_stream = result.GetOutputStream(); 1116 output_stream.Printf("frame %d ", frame_index); 1117 if (recognizer) { 1118 output_stream << "is recognized by "; 1119 output_stream << recognizer->GetName(); 1120 } else { 1121 output_stream << "not recognized by any recognizer"; 1122 } 1123 output_stream.EOL(); 1124 result.SetStatus(eReturnStatusSuccessFinishResult); 1125 return result.Succeeded(); 1126 } 1127 }; 1128 1129 class CommandObjectFrameRecognizer : public CommandObjectMultiword { 1130 public: 1131 CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 1132 : CommandObjectMultiword( 1133 interpreter, "frame recognizer", 1134 "Commands for editing and viewing frame recognizers.", 1135 "frame recognizer [<sub-command-options>] ") { 1136 LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd( 1137 interpreter))); 1138 LoadSubCommand( 1139 "clear", 1140 CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 1141 LoadSubCommand( 1142 "delete", 1143 CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 1144 LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList( 1145 interpreter))); 1146 LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo( 1147 interpreter))); 1148 } 1149 1150 ~CommandObjectFrameRecognizer() override = default; 1151 }; 1152 1153 #pragma mark CommandObjectMultiwordFrame 1154 1155 // CommandObjectMultiwordFrame 1156 1157 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1158 CommandInterpreter &interpreter) 1159 : CommandObjectMultiword(interpreter, "frame", 1160 "Commands for selecting and " 1161 "examing the current " 1162 "thread's stack frames.", 1163 "frame <subcommand> [<subcommand-options>]") { 1164 LoadSubCommand("diagnose", 1165 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1166 LoadSubCommand("info", 1167 CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1168 LoadSubCommand("select", 1169 CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1170 LoadSubCommand("variable", 1171 CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 1172 #if LLDB_ENABLE_PYTHON 1173 LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer( 1174 interpreter))); 1175 #endif 1176 } 1177 1178 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1179