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