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