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