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