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