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