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