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