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