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.getValue()); 147 } else if (m_options.reg) { 148 valobj_sp = frame_sp->GuessValueForRegisterAndOffset( 149 m_options.reg.getValue(), 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 by id.", 928 nullptr) { 929 CommandArgumentData thread_arg{eArgTypeRecognizerID, eArgRepeatPlain}; 930 m_arguments.push_back({thread_arg}); 931 } 932 933 ~CommandObjectFrameRecognizerDelete() override = default; 934 935 void 936 HandleArgumentCompletion(CompletionRequest &request, 937 OptionElementVector &opt_element_vector) override { 938 if (request.GetCursorIndex() != 0) 939 return; 940 941 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 942 [&request](uint32_t rid, std::string rname, std::string module, 943 llvm::ArrayRef<lldb_private::ConstString> symbols, 944 bool regexp) { 945 StreamString strm; 946 if (rname.empty()) 947 rname = "(internal)"; 948 949 strm << rname; 950 if (!module.empty()) 951 strm << ", module " << module; 952 if (!symbols.empty()) 953 for (auto &symbol : symbols) 954 strm << ", symbol " << symbol; 955 if (regexp) 956 strm << " (regexp)"; 957 958 request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString()); 959 }); 960 } 961 962 protected: 963 bool DoExecute(Args &command, CommandReturnObject &result) override { 964 if (command.GetArgumentCount() == 0) { 965 if (!m_interpreter.Confirm( 966 "About to delete all frame recognizers, do you want to do that?", 967 true)) { 968 result.AppendMessage("Operation cancelled..."); 969 return false; 970 } 971 972 GetSelectedOrDummyTarget() 973 .GetFrameRecognizerManager() 974 .RemoveAllRecognizers(); 975 result.SetStatus(eReturnStatusSuccessFinishResult); 976 return result.Succeeded(); 977 } 978 979 if (command.GetArgumentCount() != 1) { 980 result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 981 m_cmd_name.c_str()); 982 return false; 983 } 984 985 uint32_t recognizer_id; 986 if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) { 987 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 988 command.GetArgumentAtIndex(0)); 989 return false; 990 } 991 992 if (!GetSelectedOrDummyTarget() 993 .GetFrameRecognizerManager() 994 .RemoveRecognizerWithID(recognizer_id)) { 995 result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 996 command.GetArgumentAtIndex(0)); 997 return false; 998 } 999 result.SetStatus(eReturnStatusSuccessFinishResult); 1000 return result.Succeeded(); 1001 } 1002 }; 1003 1004 class CommandObjectFrameRecognizerList : public CommandObjectParsed { 1005 public: 1006 CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 1007 : CommandObjectParsed(interpreter, "frame recognizer list", 1008 "Show a list of active frame recognizers.", 1009 nullptr) {} 1010 1011 ~CommandObjectFrameRecognizerList() override = default; 1012 1013 protected: 1014 bool DoExecute(Args &command, CommandReturnObject &result) override { 1015 bool any_printed = false; 1016 GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 1017 [&result, &any_printed]( 1018 uint32_t recognizer_id, std::string name, std::string module, 1019 llvm::ArrayRef<ConstString> symbols, bool regexp) { 1020 Stream &stream = result.GetOutputStream(); 1021 1022 if (name.empty()) 1023 name = "(internal)"; 1024 1025 stream << std::to_string(recognizer_id) << ": " << name; 1026 if (!module.empty()) 1027 stream << ", module " << module; 1028 if (!symbols.empty()) 1029 for (auto &symbol : symbols) 1030 stream << ", symbol " << symbol; 1031 if (regexp) 1032 stream << " (regexp)"; 1033 1034 stream.EOL(); 1035 stream.Flush(); 1036 1037 any_printed = true; 1038 }); 1039 1040 if (any_printed) 1041 result.SetStatus(eReturnStatusSuccessFinishResult); 1042 else { 1043 result.GetOutputStream().PutCString("no matching results found.\n"); 1044 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1045 } 1046 return result.Succeeded(); 1047 } 1048 }; 1049 1050 class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 1051 public: 1052 CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 1053 : CommandObjectParsed( 1054 interpreter, "frame recognizer info", 1055 "Show which frame recognizer is applied a stack frame (if any).", 1056 nullptr) { 1057 CommandArgumentEntry arg; 1058 CommandArgumentData index_arg; 1059 1060 // Define the first (and only) variant of this arg. 1061 index_arg.arg_type = eArgTypeFrameIndex; 1062 index_arg.arg_repetition = eArgRepeatPlain; 1063 1064 // There is only one variant this argument could be; put it into the 1065 // argument entry. 1066 arg.push_back(index_arg); 1067 1068 // Push the data for the first argument into the m_arguments vector. 1069 m_arguments.push_back(arg); 1070 } 1071 1072 ~CommandObjectFrameRecognizerInfo() override = default; 1073 1074 protected: 1075 bool DoExecute(Args &command, CommandReturnObject &result) override { 1076 const char *frame_index_str = command.GetArgumentAtIndex(0); 1077 uint32_t frame_index; 1078 if (!llvm::to_integer(frame_index_str, frame_index)) { 1079 result.AppendErrorWithFormat("'%s' is not a valid frame index.", 1080 frame_index_str); 1081 return false; 1082 } 1083 1084 Process *process = m_exe_ctx.GetProcessPtr(); 1085 if (process == nullptr) { 1086 result.AppendError("no process"); 1087 return false; 1088 } 1089 Thread *thread = m_exe_ctx.GetThreadPtr(); 1090 if (thread == nullptr) { 1091 result.AppendError("no thread"); 1092 return false; 1093 } 1094 if (command.GetArgumentCount() != 1) { 1095 result.AppendErrorWithFormat( 1096 "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 1097 return false; 1098 } 1099 1100 StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 1101 if (!frame_sp) { 1102 result.AppendErrorWithFormat("no frame with index %u", frame_index); 1103 return false; 1104 } 1105 1106 auto recognizer = GetSelectedOrDummyTarget() 1107 .GetFrameRecognizerManager() 1108 .GetRecognizerForFrame(frame_sp); 1109 1110 Stream &output_stream = result.GetOutputStream(); 1111 output_stream.Printf("frame %d ", frame_index); 1112 if (recognizer) { 1113 output_stream << "is recognized by "; 1114 output_stream << recognizer->GetName(); 1115 } else { 1116 output_stream << "not recognized by any recognizer"; 1117 } 1118 output_stream.EOL(); 1119 result.SetStatus(eReturnStatusSuccessFinishResult); 1120 return result.Succeeded(); 1121 } 1122 }; 1123 1124 class CommandObjectFrameRecognizer : public CommandObjectMultiword { 1125 public: 1126 CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 1127 : CommandObjectMultiword( 1128 interpreter, "frame recognizer", 1129 "Commands for editing and viewing frame recognizers.", 1130 "frame recognizer [<sub-command-options>] ") { 1131 LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd( 1132 interpreter))); 1133 LoadSubCommand( 1134 "clear", 1135 CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 1136 LoadSubCommand( 1137 "delete", 1138 CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 1139 LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList( 1140 interpreter))); 1141 LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo( 1142 interpreter))); 1143 } 1144 1145 ~CommandObjectFrameRecognizer() override = default; 1146 }; 1147 1148 #pragma mark CommandObjectMultiwordFrame 1149 1150 // CommandObjectMultiwordFrame 1151 1152 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1153 CommandInterpreter &interpreter) 1154 : CommandObjectMultiword(interpreter, "frame", 1155 "Commands for selecting and " 1156 "examing the current " 1157 "thread's stack frames.", 1158 "frame <subcommand> [<subcommand-options>]") { 1159 LoadSubCommand("diagnose", 1160 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1161 LoadSubCommand("info", 1162 CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1163 LoadSubCommand("select", 1164 CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1165 LoadSubCommand("variable", 1166 CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 1167 #if LLDB_ENABLE_PYTHON 1168 LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer( 1169 interpreter))); 1170 #endif 1171 } 1172 1173 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1174