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 nullptr, 399 eCommandRequiresFrame | eCommandTryTargetAPILock | 400 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | 401 eCommandRequiresProcess), 402 m_option_group(), 403 m_option_variable( 404 true), // Include the frame specific options by passing "true" 405 m_option_format(eFormatDefault), m_varobj_options() { 406 SetHelpLong(R"( 407 Children of aggregate variables can be specified such as 'var->child.x'. In 408 'frame variable', the operators -> and [] do not invoke operator overloads if 409 they exist, but directly access the specified element. If you want to trigger 410 operator overloads use the expression command to print the variable instead. 411 412 It is worth noting that except for overloaded operators, when printing local 413 variables 'expr local_var' and 'frame var local_var' produce the same results. 414 However, 'frame variable' is more efficient, since it uses debug information and 415 memory reads directly, rather than parsing and evaluating an expression, which 416 may even involve JITing and running code in the target program.)"); 417 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.AppendErrorWithFormat( 562 "no variables matched the regular expression '%s'.", 563 entry.c_str()); 564 } 565 } else { 566 if (llvm::Error err = regex.GetError()) 567 result.AppendError(llvm::toString(std::move(err))); 568 else 569 result.AppendErrorWithFormat( 570 "unknown regex error when compiling '%s'", entry.c_str()); 571 } 572 } else // No regex, either exact variable names or variable 573 // expressions. 574 { 575 Status error; 576 uint32_t expr_path_options = 577 StackFrame::eExpressionPathOptionCheckPtrVsMember | 578 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 579 StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 580 lldb::VariableSP var_sp; 581 valobj_sp = frame->GetValueForVariableExpressionPath( 582 entry.ref(), m_varobj_options.use_dynamic, expr_path_options, 583 var_sp, error); 584 if (valobj_sp) { 585 std::string scope_string; 586 if (m_option_variable.show_scope) 587 scope_string = GetScopeString(var_sp).str(); 588 589 if (!scope_string.empty()) 590 s.PutCString(scope_string); 591 if (m_option_variable.show_decl && var_sp && 592 var_sp->GetDeclaration().GetFile()) { 593 var_sp->GetDeclaration().DumpStopContext(&s, false); 594 s.PutCString(": "); 595 } 596 597 options.SetFormat(format); 598 options.SetVariableFormatDisplayLanguage( 599 valobj_sp->GetPreferredDisplayLanguage()); 600 601 Stream &output_stream = result.GetOutputStream(); 602 options.SetRootValueObjectName( 603 valobj_sp->GetParent() ? entry.c_str() : nullptr); 604 valobj_sp->Dump(output_stream, options); 605 } else { 606 if (auto error_cstr = error.AsCString(nullptr)) 607 result.AppendError(error_cstr); 608 else 609 result.AppendErrorWithFormat( 610 "unable to find any variable expression path that matches " 611 "'%s'.", 612 entry.c_str()); 613 } 614 } 615 } 616 } else // No command arg specified. Use variable_list, instead. 617 { 618 const size_t num_variables = variable_list->GetSize(); 619 if (num_variables > 0) { 620 for (size_t i = 0; i < num_variables; i++) { 621 var_sp = variable_list->GetVariableAtIndex(i); 622 switch (var_sp->GetScope()) { 623 case eValueTypeVariableGlobal: 624 if (!m_option_variable.show_globals) 625 continue; 626 break; 627 case eValueTypeVariableStatic: 628 if (!m_option_variable.show_globals) 629 continue; 630 break; 631 case eValueTypeVariableArgument: 632 if (!m_option_variable.show_args) 633 continue; 634 break; 635 case eValueTypeVariableLocal: 636 if (!m_option_variable.show_locals) 637 continue; 638 break; 639 default: 640 continue; 641 break; 642 } 643 std::string scope_string; 644 if (m_option_variable.show_scope) 645 scope_string = GetScopeString(var_sp).str(); 646 647 // Use the variable object code to make sure we are using the same 648 // APIs as the public API will be using... 649 valobj_sp = frame->GetValueObjectForFrameVariable( 650 var_sp, m_varobj_options.use_dynamic); 651 if (valobj_sp) { 652 // When dumping all variables, don't print any variables that are 653 // not in scope to avoid extra unneeded output 654 if (valobj_sp->IsInScope()) { 655 if (!valobj_sp->GetTargetSP() 656 ->GetDisplayRuntimeSupportValues() && 657 valobj_sp->IsRuntimeSupportValue()) 658 continue; 659 660 if (!scope_string.empty()) 661 s.PutCString(scope_string); 662 663 if (m_option_variable.show_decl && 664 var_sp->GetDeclaration().GetFile()) { 665 var_sp->GetDeclaration().DumpStopContext(&s, false); 666 s.PutCString(": "); 667 } 668 669 options.SetFormat(format); 670 options.SetVariableFormatDisplayLanguage( 671 valobj_sp->GetPreferredDisplayLanguage()); 672 options.SetRootValueObjectName( 673 var_sp ? var_sp->GetName().AsCString() : nullptr); 674 valobj_sp->Dump(result.GetOutputStream(), options); 675 } 676 } 677 } 678 } 679 } 680 if (result.GetStatus() != eReturnStatusFailed) 681 result.SetStatus(eReturnStatusSuccessFinishResult); 682 } 683 684 if (m_option_variable.show_recognized_args) { 685 auto recognized_frame = frame->GetRecognizedFrame(); 686 if (recognized_frame) { 687 ValueObjectListSP recognized_arg_list = 688 recognized_frame->GetRecognizedArguments(); 689 if (recognized_arg_list) { 690 for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { 691 options.SetFormat(m_option_format.GetFormat()); 692 options.SetVariableFormatDisplayLanguage( 693 rec_value_sp->GetPreferredDisplayLanguage()); 694 options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); 695 rec_value_sp->Dump(result.GetOutputStream(), options); 696 } 697 } 698 } 699 } 700 701 if (m_interpreter.TruncationWarningNecessary()) { 702 result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 703 m_cmd_name.c_str()); 704 m_interpreter.TruncationWarningGiven(); 705 } 706 707 // Increment statistics. 708 bool res = result.Succeeded(); 709 TargetStats &target_stats = GetSelectedOrDummyTarget().GetStatistics(); 710 if (res) 711 target_stats.GetFrameVariableStats().NotifySuccess(); 712 else 713 target_stats.GetFrameVariableStats().NotifyFailure(); 714 return res; 715 } 716 717 OptionGroupOptions m_option_group; 718 OptionGroupVariable m_option_variable; 719 OptionGroupFormat m_option_format; 720 OptionGroupValueObjectDisplay m_varobj_options; 721 }; 722 723 #pragma mark CommandObjectFrameRecognizer 724 725 #define LLDB_OPTIONS_frame_recognizer_add 726 #include "CommandOptions.inc" 727 728 class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { 729 private: 730 class CommandOptions : public Options { 731 public: 732 CommandOptions() : Options() {} 733 ~CommandOptions() override = default; 734 735 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 736 ExecutionContext *execution_context) override { 737 Status error; 738 const int short_option = m_getopt_table[option_idx].val; 739 740 switch (short_option) { 741 case 'f': { 742 bool value, success; 743 value = OptionArgParser::ToBoolean(option_arg, true, &success); 744 if (success) { 745 m_first_instruction_only = value; 746 } else { 747 error.SetErrorStringWithFormat( 748 "invalid boolean value '%s' passed for -f option", 749 option_arg.str().c_str()); 750 } 751 } break; 752 case 'l': 753 m_class_name = std::string(option_arg); 754 break; 755 case 's': 756 m_module = std::string(option_arg); 757 break; 758 case 'n': 759 m_symbols.push_back(std::string(option_arg)); 760 break; 761 case 'x': 762 m_regex = true; 763 break; 764 default: 765 llvm_unreachable("Unimplemented option"); 766 } 767 768 return error; 769 } 770 771 void OptionParsingStarting(ExecutionContext *execution_context) override { 772 m_module = ""; 773 m_symbols.clear(); 774 m_class_name = ""; 775 m_regex = false; 776 m_first_instruction_only = true; 777 } 778 779 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 780 return llvm::makeArrayRef(g_frame_recognizer_add_options); 781 } 782 783 // Instance variables to hold the values for command options. 784 std::string m_class_name; 785 std::string m_module; 786 std::vector<std::string> m_symbols; 787 bool m_regex; 788 bool m_first_instruction_only; 789 }; 790 791 CommandOptions m_options; 792 793 Options *GetOptions() override { return &m_options; } 794 795 protected: 796 bool DoExecute(Args &command, CommandReturnObject &result) override; 797 798 public: 799 CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 800 : CommandObjectParsed(interpreter, "frame recognizer add", 801 "Add a new frame recognizer.", nullptr), 802 m_options() { 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 value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) 824 return [value] 825 return [] 826 827 The file containing this implementation can be imported via 'command script 828 import' and then we can register this recognizer with 'frame recognizer add'. 829 It's important to restrict the recognizer to the libc library (which is 830 libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 831 in other modules: 832 833 (lldb) command script import .../fd_recognizer.py 834 (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 835 836 When the program is stopped at the beginning of the 'read' function in libc, we 837 can view the recognizer arguments in 'frame variable': 838 839 (lldb) b read 840 (lldb) r 841 Process 1234 stopped 842 * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 843 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 844 (lldb) frame variable 845 (int) fd = 3 846 847 )"); 848 } 849 ~CommandObjectFrameRecognizerAdd() override = default; 850 }; 851 852 bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 853 CommandReturnObject &result) { 854 #if LLDB_ENABLE_PYTHON 855 if (m_options.m_class_name.empty()) { 856 result.AppendErrorWithFormat( 857 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 858 return false; 859 } 860 861 if (m_options.m_module.empty()) { 862 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 863 m_cmd_name.c_str()); 864 return false; 865 } 866 867 if (m_options.m_symbols.empty()) { 868 result.AppendErrorWithFormat( 869 "%s needs at least one symbol name (-n argument).\n", 870 m_cmd_name.c_str()); 871 return false; 872 } 873 874 if (m_options.m_regex && m_options.m_symbols.size() > 1) { 875 result.AppendErrorWithFormat( 876 "%s needs only one symbol regular expression (-n argument).\n", 877 m_cmd_name.c_str()); 878 return false; 879 } 880 881 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 882 883 if (interpreter && 884 !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 885 result.AppendWarning("The provided class does not exist - please define it " 886 "before attempting to use this frame recognizer"); 887 } 888 889 StackFrameRecognizerSP recognizer_sp = 890 StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 891 interpreter, m_options.m_class_name.c_str())); 892 if (m_options.m_regex) { 893 auto module = 894 RegularExpressionSP(new RegularExpression(m_options.m_module)); 895 auto func = 896 RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); 897 GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 898 recognizer_sp, module, func, m_options.m_first_instruction_only); 899 } else { 900 auto module = ConstString(m_options.m_module); 901 std::vector<ConstString> symbols(m_options.m_symbols.begin(), 902 m_options.m_symbols.end()); 903 GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 904 recognizer_sp, module, symbols, m_options.m_first_instruction_only); 905 } 906 #endif 907 908 result.SetStatus(eReturnStatusSuccessFinishNoResult); 909 return result.Succeeded(); 910 } 911 912 class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 913 public: 914 CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 915 : CommandObjectParsed(interpreter, "frame recognizer clear", 916 "Delete all frame recognizers.", nullptr) {} 917 918 ~CommandObjectFrameRecognizerClear() override = default; 919 920 protected: 921 bool DoExecute(Args &command, CommandReturnObject &result) override { 922 GetSelectedOrDummyTarget() 923 .GetFrameRecognizerManager() 924 .RemoveAllRecognizers(); 925 result.SetStatus(eReturnStatusSuccessFinishResult); 926 return result.Succeeded(); 927 } 928 }; 929 930 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 931 public: 932 CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 933 : CommandObjectParsed(interpreter, "frame recognizer delete", 934 "Delete an existing frame recognizer.", nullptr) {} 935 936 ~CommandObjectFrameRecognizerDelete() override = default; 937 938 void 939 HandleArgumentCompletion(CompletionRequest &request, 940 OptionElementVector &opt_element_vector) override { 941 if (request.GetCursorIndex() != 0) 942 return; 943 944 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 945 [&request](uint32_t rid, std::string rname, std::string module, 946 llvm::ArrayRef<lldb_private::ConstString> symbols, 947 bool regexp) { 948 StreamString strm; 949 if (rname.empty()) 950 rname = "(internal)"; 951 952 strm << rname; 953 if (!module.empty()) 954 strm << ", module " << module; 955 if (!symbols.empty()) 956 for (auto &symbol : symbols) 957 strm << ", symbol " << symbol; 958 if (regexp) 959 strm << " (regexp)"; 960 961 request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString()); 962 }); 963 } 964 965 protected: 966 bool DoExecute(Args &command, CommandReturnObject &result) override { 967 if (command.GetArgumentCount() == 0) { 968 if (!m_interpreter.Confirm( 969 "About to delete all frame recognizers, do you want to do that?", 970 true)) { 971 result.AppendMessage("Operation cancelled..."); 972 return false; 973 } 974 975 GetSelectedOrDummyTarget() 976 .GetFrameRecognizerManager() 977 .RemoveAllRecognizers(); 978 result.SetStatus(eReturnStatusSuccessFinishResult); 979 return result.Succeeded(); 980 } 981 982 if (command.GetArgumentCount() != 1) { 983 result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 984 m_cmd_name.c_str()); 985 return false; 986 } 987 988 uint32_t recognizer_id; 989 if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) { 990 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 991 command.GetArgumentAtIndex(0)); 992 return false; 993 } 994 995 if (!GetSelectedOrDummyTarget() 996 .GetFrameRecognizerManager() 997 .RemoveRecognizerWithID(recognizer_id)) { 998 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 999 command.GetArgumentAtIndex(0)); 1000 return false; 1001 } 1002 result.SetStatus(eReturnStatusSuccessFinishResult); 1003 return result.Succeeded(); 1004 } 1005 }; 1006 1007 class CommandObjectFrameRecognizerList : public CommandObjectParsed { 1008 public: 1009 CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 1010 : CommandObjectParsed(interpreter, "frame recognizer list", 1011 "Show a list of active frame recognizers.", 1012 nullptr) {} 1013 1014 ~CommandObjectFrameRecognizerList() override = default; 1015 1016 protected: 1017 bool DoExecute(Args &command, CommandReturnObject &result) override { 1018 bool any_printed = false; 1019 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 1020 [&result, &any_printed]( 1021 uint32_t recognizer_id, std::string name, std::string module, 1022 llvm::ArrayRef<ConstString> symbols, bool regexp) { 1023 Stream &stream = result.GetOutputStream(); 1024 1025 if (name.empty()) 1026 name = "(internal)"; 1027 1028 stream << std::to_string(recognizer_id) << ": " << name; 1029 if (!module.empty()) 1030 stream << ", module " << module; 1031 if (!symbols.empty()) 1032 for (auto &symbol : symbols) 1033 stream << ", symbol " << symbol; 1034 if (regexp) 1035 stream << " (regexp)"; 1036 1037 stream.EOL(); 1038 stream.Flush(); 1039 1040 any_printed = true; 1041 }); 1042 1043 if (any_printed) 1044 result.SetStatus(eReturnStatusSuccessFinishResult); 1045 else { 1046 result.GetOutputStream().PutCString("no matching results found.\n"); 1047 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1048 } 1049 return result.Succeeded(); 1050 } 1051 }; 1052 1053 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 1054 public: 1055 CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 1056 : CommandObjectParsed( 1057 interpreter, "frame recognizer info", 1058 "Show which frame recognizer is applied a stack frame (if any).", 1059 nullptr) { 1060 CommandArgumentEntry arg; 1061 CommandArgumentData index_arg; 1062 1063 // Define the first (and only) variant of this arg. 1064 index_arg.arg_type = eArgTypeFrameIndex; 1065 index_arg.arg_repetition = eArgRepeatPlain; 1066 1067 // There is only one variant this argument could be; put it into the 1068 // argument entry. 1069 arg.push_back(index_arg); 1070 1071 // Push the data for the first argument into the m_arguments vector. 1072 m_arguments.push_back(arg); 1073 } 1074 1075 ~CommandObjectFrameRecognizerInfo() override = default; 1076 1077 protected: 1078 bool DoExecute(Args &command, CommandReturnObject &result) override { 1079 const char *frame_index_str = command.GetArgumentAtIndex(0); 1080 uint32_t frame_index; 1081 if (!llvm::to_integer(frame_index_str, frame_index)) { 1082 result.AppendErrorWithFormat("'%s' is not a valid frame index.", 1083 frame_index_str); 1084 return false; 1085 } 1086 1087 Process *process = m_exe_ctx.GetProcessPtr(); 1088 if (process == nullptr) { 1089 result.AppendError("no process"); 1090 return false; 1091 } 1092 Thread *thread = m_exe_ctx.GetThreadPtr(); 1093 if (thread == nullptr) { 1094 result.AppendError("no thread"); 1095 return false; 1096 } 1097 if (command.GetArgumentCount() != 1) { 1098 result.AppendErrorWithFormat( 1099 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 1100 return false; 1101 } 1102 1103 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 1104 if (!frame_sp) { 1105 result.AppendErrorWithFormat("no frame with index %u", frame_index); 1106 return false; 1107 } 1108 1109 auto recognizer = GetSelectedOrDummyTarget() 1110 .GetFrameRecognizerManager() 1111 .GetRecognizerForFrame(frame_sp); 1112 1113 Stream &output_stream = result.GetOutputStream(); 1114 output_stream.Printf("frame %d ", frame_index); 1115 if (recognizer) { 1116 output_stream << "is recognized by "; 1117 output_stream << recognizer->GetName(); 1118 } else { 1119 output_stream << "not recognized by any recognizer"; 1120 } 1121 output_stream.EOL(); 1122 result.SetStatus(eReturnStatusSuccessFinishResult); 1123 return result.Succeeded(); 1124 } 1125 }; 1126 1127 class CommandObjectFrameRecognizer : public CommandObjectMultiword { 1128 public: 1129 CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 1130 : CommandObjectMultiword( 1131 interpreter, "frame recognizer", 1132 "Commands for editing and viewing frame recognizers.", 1133 "frame recognizer [<sub-command-options>] ") { 1134 LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd( 1135 interpreter))); 1136 LoadSubCommand( 1137 "clear", 1138 CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 1139 LoadSubCommand( 1140 "delete", 1141 CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 1142 LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList( 1143 interpreter))); 1144 LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo( 1145 interpreter))); 1146 } 1147 1148 ~CommandObjectFrameRecognizer() override = default; 1149 }; 1150 1151 #pragma mark CommandObjectMultiwordFrame 1152 1153 // CommandObjectMultiwordFrame 1154 1155 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1156 CommandInterpreter &interpreter) 1157 : CommandObjectMultiword(interpreter, "frame", 1158 "Commands for selecting and " 1159 "examing the current " 1160 "thread's stack frames.", 1161 "frame <subcommand> [<subcommand-options>]") { 1162 LoadSubCommand("diagnose", 1163 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1164 LoadSubCommand("info", 1165 CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1166 LoadSubCommand("select", 1167 CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1168 LoadSubCommand("variable", 1169 CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 1170 #if LLDB_ENABLE_PYTHON 1171 LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer( 1172 interpreter))); 1173 #endif 1174 } 1175 1176 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1177