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