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) { 141 if (m_options.reg || m_options.offset) { 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); 147 } else if (m_options.reg) { 148 valobj_sp = frame_sp->GuessValueForRegisterAndOffset( 149 m_options.reg.value(), m_options.offset.value_or(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) { 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 m_interpreter.PrintWarningsIfNecessary(result.GetOutputStream(), 699 m_cmd_name); 700 701 // Increment statistics. 702 bool res = result.Succeeded(); 703 TargetStats &target_stats = GetSelectedOrDummyTarget().GetStatistics(); 704 if (res) 705 target_stats.GetFrameVariableStats().NotifySuccess(); 706 else 707 target_stats.GetFrameVariableStats().NotifyFailure(); 708 return res; 709 } 710 711 OptionGroupOptions m_option_group; 712 OptionGroupVariable m_option_variable; 713 OptionGroupFormat m_option_format; 714 OptionGroupValueObjectDisplay m_varobj_options; 715 }; 716 717 #pragma mark CommandObjectFrameRecognizer 718 719 #define LLDB_OPTIONS_frame_recognizer_add 720 #include "CommandOptions.inc" 721 722 class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { 723 private: 724 class CommandOptions : public Options { 725 public: 726 CommandOptions() = default; 727 ~CommandOptions() override = default; 728 729 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 730 ExecutionContext *execution_context) override { 731 Status error; 732 const int short_option = m_getopt_table[option_idx].val; 733 734 switch (short_option) { 735 case 'f': { 736 bool value, success; 737 value = OptionArgParser::ToBoolean(option_arg, true, &success); 738 if (success) { 739 m_first_instruction_only = value; 740 } else { 741 error.SetErrorStringWithFormat( 742 "invalid boolean value '%s' passed for -f option", 743 option_arg.str().c_str()); 744 } 745 } break; 746 case 'l': 747 m_class_name = std::string(option_arg); 748 break; 749 case 's': 750 m_module = std::string(option_arg); 751 break; 752 case 'n': 753 m_symbols.push_back(std::string(option_arg)); 754 break; 755 case 'x': 756 m_regex = true; 757 break; 758 default: 759 llvm_unreachable("Unimplemented option"); 760 } 761 762 return error; 763 } 764 765 void OptionParsingStarting(ExecutionContext *execution_context) override { 766 m_module = ""; 767 m_symbols.clear(); 768 m_class_name = ""; 769 m_regex = false; 770 m_first_instruction_only = true; 771 } 772 773 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 774 return llvm::makeArrayRef(g_frame_recognizer_add_options); 775 } 776 777 // Instance variables to hold the values for command options. 778 std::string m_class_name; 779 std::string m_module; 780 std::vector<std::string> m_symbols; 781 bool m_regex; 782 bool m_first_instruction_only; 783 }; 784 785 CommandOptions m_options; 786 787 Options *GetOptions() override { return &m_options; } 788 789 protected: 790 bool DoExecute(Args &command, CommandReturnObject &result) override; 791 792 public: 793 CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 794 : CommandObjectParsed(interpreter, "frame recognizer add", 795 "Add a new frame recognizer.", nullptr) { 796 SetHelpLong(R"( 797 Frame recognizers allow for retrieving information about special frames based on 798 ABI, arguments or other special properties of that frame, even without source 799 code or debug info. Currently, one use case is to extract function arguments 800 that would otherwise be unaccesible, or augment existing arguments. 801 802 Adding a custom frame recognizer is possible by implementing a Python class 803 and using the 'frame recognizer add' command. The Python class should have a 804 'get_recognized_arguments' method and it will receive an argument of type 805 lldb.SBFrame representing the current frame that we are trying to recognize. 806 The method should return a (possibly empty) list of lldb.SBValue objects that 807 represent the recognized arguments. 808 809 An example of a recognizer that retrieves the file descriptor values from libc 810 functions 'read', 'write' and 'close' follows: 811 812 class LibcFdRecognizer(object): 813 def get_recognized_arguments(self, frame): 814 if frame.name in ["read", "write", "close"]: 815 fd = frame.EvaluateExpression("$arg1").unsigned 816 value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) 817 return [value] 818 return [] 819 820 The file containing this implementation can be imported via 'command script 821 import' and then we can register this recognizer with 'frame recognizer add'. 822 It's important to restrict the recognizer to the libc library (which is 823 libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 824 in other modules: 825 826 (lldb) command script import .../fd_recognizer.py 827 (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 828 829 When the program is stopped at the beginning of the 'read' function in libc, we 830 can view the recognizer arguments in 'frame variable': 831 832 (lldb) b read 833 (lldb) r 834 Process 1234 stopped 835 * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 836 frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 837 (lldb) frame variable 838 (int) fd = 3 839 840 )"); 841 } 842 ~CommandObjectFrameRecognizerAdd() override = default; 843 }; 844 845 bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 846 CommandReturnObject &result) { 847 #if LLDB_ENABLE_PYTHON 848 if (m_options.m_class_name.empty()) { 849 result.AppendErrorWithFormat( 850 "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 851 return false; 852 } 853 854 if (m_options.m_module.empty()) { 855 result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 856 m_cmd_name.c_str()); 857 return false; 858 } 859 860 if (m_options.m_symbols.empty()) { 861 result.AppendErrorWithFormat( 862 "%s needs at least one symbol name (-n argument).\n", 863 m_cmd_name.c_str()); 864 return false; 865 } 866 867 if (m_options.m_regex && m_options.m_symbols.size() > 1) { 868 result.AppendErrorWithFormat( 869 "%s needs only one symbol regular expression (-n argument).\n", 870 m_cmd_name.c_str()); 871 return false; 872 } 873 874 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 875 876 if (interpreter && 877 !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 878 result.AppendWarning("The provided class does not exist - please define it " 879 "before attempting to use this frame recognizer"); 880 } 881 882 StackFrameRecognizerSP recognizer_sp = 883 StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 884 interpreter, m_options.m_class_name.c_str())); 885 if (m_options.m_regex) { 886 auto module = 887 RegularExpressionSP(new RegularExpression(m_options.m_module)); 888 auto func = 889 RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); 890 GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 891 recognizer_sp, module, func, m_options.m_first_instruction_only); 892 } else { 893 auto module = ConstString(m_options.m_module); 894 std::vector<ConstString> symbols(m_options.m_symbols.begin(), 895 m_options.m_symbols.end()); 896 GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 897 recognizer_sp, module, symbols, m_options.m_first_instruction_only); 898 } 899 #endif 900 901 result.SetStatus(eReturnStatusSuccessFinishNoResult); 902 return result.Succeeded(); 903 } 904 905 class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 906 public: 907 CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 908 : CommandObjectParsed(interpreter, "frame recognizer clear", 909 "Delete all frame recognizers.", nullptr) {} 910 911 ~CommandObjectFrameRecognizerClear() override = default; 912 913 protected: 914 bool DoExecute(Args &command, CommandReturnObject &result) override { 915 GetSelectedOrDummyTarget() 916 .GetFrameRecognizerManager() 917 .RemoveAllRecognizers(); 918 result.SetStatus(eReturnStatusSuccessFinishResult); 919 return result.Succeeded(); 920 } 921 }; 922 923 class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 924 public: 925 CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 926 : CommandObjectParsed(interpreter, "frame recognizer delete", 927 "Delete an existing frame recognizer.", nullptr) {} 928 929 ~CommandObjectFrameRecognizerDelete() override = default; 930 931 void 932 HandleArgumentCompletion(CompletionRequest &request, 933 OptionElementVector &opt_element_vector) override { 934 if (request.GetCursorIndex() != 0) 935 return; 936 937 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 938 [&request](uint32_t rid, std::string rname, std::string module, 939 llvm::ArrayRef<lldb_private::ConstString> symbols, 940 bool regexp) { 941 StreamString strm; 942 if (rname.empty()) 943 rname = "(internal)"; 944 945 strm << rname; 946 if (!module.empty()) 947 strm << ", module " << module; 948 if (!symbols.empty()) 949 for (auto &symbol : symbols) 950 strm << ", symbol " << symbol; 951 if (regexp) 952 strm << " (regexp)"; 953 954 request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString()); 955 }); 956 } 957 958 protected: 959 bool DoExecute(Args &command, CommandReturnObject &result) override { 960 if (command.GetArgumentCount() == 0) { 961 if (!m_interpreter.Confirm( 962 "About to delete all frame recognizers, do you want to do that?", 963 true)) { 964 result.AppendMessage("Operation cancelled..."); 965 return false; 966 } 967 968 GetSelectedOrDummyTarget() 969 .GetFrameRecognizerManager() 970 .RemoveAllRecognizers(); 971 result.SetStatus(eReturnStatusSuccessFinishResult); 972 return result.Succeeded(); 973 } 974 975 if (command.GetArgumentCount() != 1) { 976 result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 977 m_cmd_name.c_str()); 978 return false; 979 } 980 981 uint32_t recognizer_id; 982 if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) { 983 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 984 command.GetArgumentAtIndex(0)); 985 return false; 986 } 987 988 if (!GetSelectedOrDummyTarget() 989 .GetFrameRecognizerManager() 990 .RemoveRecognizerWithID(recognizer_id)) { 991 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 992 command.GetArgumentAtIndex(0)); 993 return false; 994 } 995 result.SetStatus(eReturnStatusSuccessFinishResult); 996 return result.Succeeded(); 997 } 998 }; 999 1000 class CommandObjectFrameRecognizerList : public CommandObjectParsed { 1001 public: 1002 CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 1003 : CommandObjectParsed(interpreter, "frame recognizer list", 1004 "Show a list of active frame recognizers.", 1005 nullptr) {} 1006 1007 ~CommandObjectFrameRecognizerList() override = default; 1008 1009 protected: 1010 bool DoExecute(Args &command, CommandReturnObject &result) override { 1011 bool any_printed = false; 1012 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 1013 [&result, &any_printed]( 1014 uint32_t recognizer_id, std::string name, std::string module, 1015 llvm::ArrayRef<ConstString> symbols, bool regexp) { 1016 Stream &stream = result.GetOutputStream(); 1017 1018 if (name.empty()) 1019 name = "(internal)"; 1020 1021 stream << std::to_string(recognizer_id) << ": " << name; 1022 if (!module.empty()) 1023 stream << ", module " << module; 1024 if (!symbols.empty()) 1025 for (auto &symbol : symbols) 1026 stream << ", symbol " << symbol; 1027 if (regexp) 1028 stream << " (regexp)"; 1029 1030 stream.EOL(); 1031 stream.Flush(); 1032 1033 any_printed = true; 1034 }); 1035 1036 if (any_printed) 1037 result.SetStatus(eReturnStatusSuccessFinishResult); 1038 else { 1039 result.GetOutputStream().PutCString("no matching results found.\n"); 1040 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1041 } 1042 return result.Succeeded(); 1043 } 1044 }; 1045 1046 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 1047 public: 1048 CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 1049 : CommandObjectParsed( 1050 interpreter, "frame recognizer info", 1051 "Show which frame recognizer is applied a stack frame (if any).", 1052 nullptr) { 1053 CommandArgumentEntry arg; 1054 CommandArgumentData index_arg; 1055 1056 // Define the first (and only) variant of this arg. 1057 index_arg.arg_type = eArgTypeFrameIndex; 1058 index_arg.arg_repetition = eArgRepeatPlain; 1059 1060 // There is only one variant this argument could be; put it into the 1061 // argument entry. 1062 arg.push_back(index_arg); 1063 1064 // Push the data for the first argument into the m_arguments vector. 1065 m_arguments.push_back(arg); 1066 } 1067 1068 ~CommandObjectFrameRecognizerInfo() override = default; 1069 1070 protected: 1071 bool DoExecute(Args &command, CommandReturnObject &result) override { 1072 const char *frame_index_str = command.GetArgumentAtIndex(0); 1073 uint32_t frame_index; 1074 if (!llvm::to_integer(frame_index_str, frame_index)) { 1075 result.AppendErrorWithFormat("'%s' is not a valid frame index.", 1076 frame_index_str); 1077 return false; 1078 } 1079 1080 Process *process = m_exe_ctx.GetProcessPtr(); 1081 if (process == nullptr) { 1082 result.AppendError("no process"); 1083 return false; 1084 } 1085 Thread *thread = m_exe_ctx.GetThreadPtr(); 1086 if (thread == nullptr) { 1087 result.AppendError("no thread"); 1088 return false; 1089 } 1090 if (command.GetArgumentCount() != 1) { 1091 result.AppendErrorWithFormat( 1092 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 1093 return false; 1094 } 1095 1096 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 1097 if (!frame_sp) { 1098 result.AppendErrorWithFormat("no frame with index %u", frame_index); 1099 return false; 1100 } 1101 1102 auto recognizer = GetSelectedOrDummyTarget() 1103 .GetFrameRecognizerManager() 1104 .GetRecognizerForFrame(frame_sp); 1105 1106 Stream &output_stream = result.GetOutputStream(); 1107 output_stream.Printf("frame %d ", frame_index); 1108 if (recognizer) { 1109 output_stream << "is recognized by "; 1110 output_stream << recognizer->GetName(); 1111 } else { 1112 output_stream << "not recognized by any recognizer"; 1113 } 1114 output_stream.EOL(); 1115 result.SetStatus(eReturnStatusSuccessFinishResult); 1116 return result.Succeeded(); 1117 } 1118 }; 1119 1120 class CommandObjectFrameRecognizer : public CommandObjectMultiword { 1121 public: 1122 CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 1123 : CommandObjectMultiword( 1124 interpreter, "frame recognizer", 1125 "Commands for editing and viewing frame recognizers.", 1126 "frame recognizer [<sub-command-options>] ") { 1127 LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd( 1128 interpreter))); 1129 LoadSubCommand( 1130 "clear", 1131 CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 1132 LoadSubCommand( 1133 "delete", 1134 CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 1135 LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList( 1136 interpreter))); 1137 LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo( 1138 interpreter))); 1139 } 1140 1141 ~CommandObjectFrameRecognizer() override = default; 1142 }; 1143 1144 #pragma mark CommandObjectMultiwordFrame 1145 1146 // CommandObjectMultiwordFrame 1147 1148 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1149 CommandInterpreter &interpreter) 1150 : CommandObjectMultiword(interpreter, "frame", 1151 "Commands for selecting and " 1152 "examing the current " 1153 "thread's stack frames.", 1154 "frame <subcommand> [<subcommand-options>]") { 1155 LoadSubCommand("diagnose", 1156 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1157 LoadSubCommand("info", 1158 CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1159 LoadSubCommand("select", 1160 CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1161 LoadSubCommand("variable", 1162 CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 1163 #if LLDB_ENABLE_PYTHON 1164 LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer( 1165 interpreter))); 1166 #endif 1167 } 1168 1169 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1170