1 //===-- CommandObjectFrame.cpp ----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 #include <string> 13 14 // Other libraries and framework includes 15 // Project includes 16 #include "CommandObjectFrame.h" 17 #include "lldb/Core/Debugger.h" 18 #include "lldb/Core/Module.h" 19 #include "lldb/Core/StreamFile.h" 20 #include "lldb/Core/Value.h" 21 #include "lldb/Core/ValueObject.h" 22 #include "lldb/Core/ValueObjectVariable.h" 23 #include "lldb/DataFormatters/DataVisualization.h" 24 #include "lldb/DataFormatters/ValueObjectPrinter.h" 25 #include "lldb/Host/Host.h" 26 #include "lldb/Host/OptionParser.h" 27 #include "lldb/Interpreter/CommandInterpreter.h" 28 #include "lldb/Interpreter/CommandReturnObject.h" 29 #include "lldb/Interpreter/OptionGroupFormat.h" 30 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" 31 #include "lldb/Interpreter/OptionGroupVariable.h" 32 #include "lldb/Interpreter/Options.h" 33 #include "lldb/Symbol/ClangASTContext.h" 34 #include "lldb/Symbol/CompilerType.h" 35 #include "lldb/Symbol/Function.h" 36 #include "lldb/Symbol/ObjectFile.h" 37 #include "lldb/Symbol/SymbolContext.h" 38 #include "lldb/Symbol/Type.h" 39 #include "lldb/Symbol/Variable.h" 40 #include "lldb/Symbol/VariableList.h" 41 #include "lldb/Target/Process.h" 42 #include "lldb/Target/StackFrame.h" 43 #include "lldb/Target/StopInfo.h" 44 #include "lldb/Target/Target.h" 45 #include "lldb/Target/Thread.h" 46 #include "lldb/Utility/Args.h" 47 #include "lldb/Utility/LLDBAssert.h" 48 #include "lldb/Utility/StreamString.h" 49 #include "lldb/Utility/Timer.h" 50 51 using namespace lldb; 52 using namespace lldb_private; 53 54 #pragma mark CommandObjectFrameDiagnose 55 56 //------------------------------------------------------------------------- 57 // CommandObjectFrameInfo 58 //------------------------------------------------------------------------- 59 60 //------------------------------------------------------------------------- 61 // CommandObjectFrameDiagnose 62 //------------------------------------------------------------------------- 63 64 static OptionDefinition g_frame_diag_options[] = { 65 // clang-format off 66 { LLDB_OPT_SET_1, false, "register", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeRegisterName, "A register to diagnose." }, 67 { LLDB_OPT_SET_1, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddress, "An address to diagnose." }, 68 { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "An optional offset. Requires --register." } 69 // clang-format on 70 }; 71 72 class CommandObjectFrameDiagnose : public CommandObjectParsed { 73 public: 74 class CommandOptions : public Options { 75 public: 76 CommandOptions() : Options() { OptionParsingStarting(nullptr); } 77 78 ~CommandOptions() override = default; 79 80 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 81 ExecutionContext *execution_context) override { 82 Status error; 83 const int short_option = m_getopt_table[option_idx].val; 84 switch (short_option) { 85 case 'r': 86 reg = ConstString(option_arg); 87 break; 88 89 case 'a': { 90 address.emplace(); 91 if (option_arg.getAsInteger(0, *address)) { 92 address.reset(); 93 error.SetErrorStringWithFormat("invalid address argument '%s'", 94 option_arg.str().c_str()); 95 } 96 } break; 97 98 case 'o': { 99 offset.emplace(); 100 if (option_arg.getAsInteger(0, *offset)) { 101 offset.reset(); 102 error.SetErrorStringWithFormat("invalid offset argument '%s'", 103 option_arg.str().c_str()); 104 } 105 } break; 106 107 default: 108 error.SetErrorStringWithFormat("invalid short option character '%c'", 109 short_option); 110 break; 111 } 112 113 return error; 114 } 115 116 void OptionParsingStarting(ExecutionContext *execution_context) override { 117 address.reset(); 118 reg.reset(); 119 offset.reset(); 120 } 121 122 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 123 return llvm::makeArrayRef(g_frame_diag_options); 124 } 125 126 // Options. 127 llvm::Optional<lldb::addr_t> address; 128 llvm::Optional<ConstString> reg; 129 llvm::Optional<int64_t> offset; 130 }; 131 132 CommandObjectFrameDiagnose(CommandInterpreter &interpreter) 133 : CommandObjectParsed(interpreter, "frame diagnose", 134 "Try to determine what path path the current stop " 135 "location used to get to a register or address", 136 nullptr, 137 eCommandRequiresThread | eCommandTryTargetAPILock | 138 eCommandProcessMustBeLaunched | 139 eCommandProcessMustBePaused), 140 m_options() { 141 CommandArgumentEntry arg; 142 CommandArgumentData index_arg; 143 144 // Define the first (and only) variant of this arg. 145 index_arg.arg_type = eArgTypeFrameIndex; 146 index_arg.arg_repetition = eArgRepeatOptional; 147 148 // There is only one variant this argument could be; put it into the 149 // argument entry. 150 arg.push_back(index_arg); 151 152 // Push the data for the first argument into the m_arguments vector. 153 m_arguments.push_back(arg); 154 } 155 156 ~CommandObjectFrameDiagnose() override = default; 157 158 Options *GetOptions() override { return &m_options; } 159 160 protected: 161 bool DoExecute(Args &command, CommandReturnObject &result) override { 162 Thread *thread = m_exe_ctx.GetThreadPtr(); 163 StackFrameSP frame_sp = thread->GetSelectedFrame(); 164 165 ValueObjectSP valobj_sp; 166 167 if (m_options.address.hasValue()) { 168 if (m_options.reg.hasValue() || m_options.offset.hasValue()) { 169 result.AppendError( 170 "`frame diagnose --address` is incompatible with other arguments."); 171 result.SetStatus(eReturnStatusFailed); 172 return false; 173 } 174 valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue()); 175 } else if (m_options.reg.hasValue()) { 176 valobj_sp = frame_sp->GuessValueForRegisterAndOffset( 177 m_options.reg.getValue(), m_options.offset.getValueOr(0)); 178 } else { 179 StopInfoSP stop_info_sp = thread->GetStopInfo(); 180 if (!stop_info_sp) { 181 result.AppendError("No arguments provided, and no stop info."); 182 result.SetStatus(eReturnStatusFailed); 183 return false; 184 } 185 186 valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp); 187 } 188 189 if (!valobj_sp) { 190 result.AppendError("No diagnosis available."); 191 result.SetStatus(eReturnStatusFailed); 192 return false; 193 } 194 195 196 DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp]( 197 ConstString type, ConstString var, const DumpValueObjectOptions &opts, 198 Stream &stream) -> bool { 199 const ValueObject::GetExpressionPathFormat format = ValueObject:: 200 GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers; 201 const bool qualify_cxx_base_classes = false; 202 valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format); 203 stream.PutCString(" ="); 204 return true; 205 }; 206 207 DumpValueObjectOptions options; 208 options.SetDeclPrintingHelper(helper); 209 ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), 210 options); 211 printer.PrintValueObject(); 212 213 return true; 214 } 215 216 protected: 217 CommandOptions m_options; 218 }; 219 220 #pragma mark CommandObjectFrameInfo 221 222 //------------------------------------------------------------------------- 223 // CommandObjectFrameInfo 224 //------------------------------------------------------------------------- 225 226 class CommandObjectFrameInfo : public CommandObjectParsed { 227 public: 228 CommandObjectFrameInfo(CommandInterpreter &interpreter) 229 : CommandObjectParsed( 230 interpreter, "frame info", "List information about the current " 231 "stack frame in the current thread.", 232 "frame info", 233 eCommandRequiresFrame | eCommandTryTargetAPILock | 234 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 235 236 ~CommandObjectFrameInfo() override = default; 237 238 protected: 239 bool DoExecute(Args &command, CommandReturnObject &result) override { 240 m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream()); 241 result.SetStatus(eReturnStatusSuccessFinishResult); 242 return result.Succeeded(); 243 } 244 }; 245 246 #pragma mark CommandObjectFrameSelect 247 248 //------------------------------------------------------------------------- 249 // CommandObjectFrameSelect 250 //------------------------------------------------------------------------- 251 252 static OptionDefinition g_frame_select_options[] = { 253 // clang-format off 254 { LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "A relative frame index offset from the current frame index." }, 255 // clang-format on 256 }; 257 258 class CommandObjectFrameSelect : public CommandObjectParsed { 259 public: 260 class CommandOptions : public Options { 261 public: 262 CommandOptions() : Options() { OptionParsingStarting(nullptr); } 263 264 ~CommandOptions() override = default; 265 266 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 267 ExecutionContext *execution_context) override { 268 Status error; 269 const int short_option = m_getopt_table[option_idx].val; 270 switch (short_option) { 271 case 'r': 272 if (option_arg.getAsInteger(0, relative_frame_offset)) { 273 relative_frame_offset = INT32_MIN; 274 error.SetErrorStringWithFormat("invalid frame offset argument '%s'", 275 option_arg.str().c_str()); 276 } 277 break; 278 279 default: 280 error.SetErrorStringWithFormat("invalid short option character '%c'", 281 short_option); 282 break; 283 } 284 285 return error; 286 } 287 288 void OptionParsingStarting(ExecutionContext *execution_context) override { 289 relative_frame_offset = INT32_MIN; 290 } 291 292 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 293 return llvm::makeArrayRef(g_frame_select_options); 294 } 295 296 int32_t relative_frame_offset; 297 }; 298 299 CommandObjectFrameSelect(CommandInterpreter &interpreter) 300 : CommandObjectParsed( 301 interpreter, "frame select", "Select the current stack frame by " 302 "index from within the current thread " 303 "(see 'thread backtrace'.)", 304 nullptr, 305 eCommandRequiresThread | eCommandTryTargetAPILock | 306 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 307 m_options() { 308 CommandArgumentEntry arg; 309 CommandArgumentData index_arg; 310 311 // Define the first (and only) variant of this arg. 312 index_arg.arg_type = eArgTypeFrameIndex; 313 index_arg.arg_repetition = eArgRepeatOptional; 314 315 // There is only one variant this argument could be; put it into the 316 // argument entry. 317 arg.push_back(index_arg); 318 319 // Push the data for the first argument into the m_arguments vector. 320 m_arguments.push_back(arg); 321 } 322 323 ~CommandObjectFrameSelect() override = default; 324 325 Options *GetOptions() override { return &m_options; } 326 327 protected: 328 bool DoExecute(Args &command, CommandReturnObject &result) override { 329 // No need to check "thread" for validity as eCommandRequiresThread ensures 330 // it is valid 331 Thread *thread = m_exe_ctx.GetThreadPtr(); 332 333 uint32_t frame_idx = UINT32_MAX; 334 if (m_options.relative_frame_offset != INT32_MIN) { 335 // The one and only argument is a signed relative frame index 336 frame_idx = thread->GetSelectedFrameIndex(); 337 if (frame_idx == UINT32_MAX) 338 frame_idx = 0; 339 340 if (m_options.relative_frame_offset < 0) { 341 if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset) 342 frame_idx += m_options.relative_frame_offset; 343 else { 344 if (frame_idx == 0) { 345 // If you are already at the bottom of the stack, then just warn 346 // and don't reset the frame. 347 result.AppendError("Already at the bottom of the stack."); 348 result.SetStatus(eReturnStatusFailed); 349 return false; 350 } else 351 frame_idx = 0; 352 } 353 } else if (m_options.relative_frame_offset > 0) { 354 // I don't want "up 20" where "20" takes you past the top of the stack 355 // to produce 356 // an error, but rather to just go to the top. So I have to count the 357 // stack here... 358 const uint32_t num_frames = thread->GetStackFrameCount(); 359 if (static_cast<int32_t>(num_frames - frame_idx) > 360 m_options.relative_frame_offset) 361 frame_idx += m_options.relative_frame_offset; 362 else { 363 if (frame_idx == num_frames - 1) { 364 // If we are already at the top of the stack, just warn and don't 365 // reset the frame. 366 result.AppendError("Already at the top of the stack."); 367 result.SetStatus(eReturnStatusFailed); 368 return false; 369 } else 370 frame_idx = num_frames - 1; 371 } 372 } 373 } else { 374 if (command.GetArgumentCount() > 1) { 375 result.AppendErrorWithFormat( 376 "too many arguments; expected frame-index, saw '%s'.\n", 377 command[0].c_str()); 378 m_options.GenerateOptionUsage( 379 result.GetErrorStream(), this, 380 GetCommandInterpreter().GetDebugger().GetTerminalWidth()); 381 return false; 382 } 383 384 if (command.GetArgumentCount() == 1) { 385 if (command[0].ref.getAsInteger(0, frame_idx)) { 386 result.AppendErrorWithFormat("invalid frame index argument '%s'.", 387 command[0].c_str()); 388 result.SetStatus(eReturnStatusFailed); 389 return false; 390 } 391 } else if (command.GetArgumentCount() == 0) { 392 frame_idx = thread->GetSelectedFrameIndex(); 393 if (frame_idx == UINT32_MAX) { 394 frame_idx = 0; 395 } 396 } 397 } 398 399 bool success = thread->SetSelectedFrameByIndexNoisily( 400 frame_idx, result.GetOutputStream()); 401 if (success) { 402 m_exe_ctx.SetFrameSP(thread->GetSelectedFrame()); 403 result.SetStatus(eReturnStatusSuccessFinishResult); 404 } else { 405 result.AppendErrorWithFormat("Frame index (%u) out of range.\n", 406 frame_idx); 407 result.SetStatus(eReturnStatusFailed); 408 } 409 410 return result.Succeeded(); 411 } 412 413 protected: 414 CommandOptions m_options; 415 }; 416 417 #pragma mark CommandObjectFrameVariable 418 //---------------------------------------------------------------------- 419 // List images with associated information 420 //---------------------------------------------------------------------- 421 class CommandObjectFrameVariable : public CommandObjectParsed { 422 public: 423 CommandObjectFrameVariable(CommandInterpreter &interpreter) 424 : CommandObjectParsed( 425 interpreter, "frame variable", 426 "Show variables for the current stack frame. Defaults to all " 427 "arguments and local variables in scope. Names of argument, " 428 "local, file static and file global variables can be specified. " 429 "Children of aggregate variables can be specified such as " 430 "'var->child.x'.", 431 nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock | 432 eCommandProcessMustBeLaunched | 433 eCommandProcessMustBePaused | eCommandRequiresProcess), 434 m_option_group(), 435 m_option_variable( 436 true), // Include the frame specific options by passing "true" 437 m_option_format(eFormatDefault), 438 m_varobj_options() { 439 CommandArgumentEntry arg; 440 CommandArgumentData var_name_arg; 441 442 // Define the first (and only) variant of this arg. 443 var_name_arg.arg_type = eArgTypeVarName; 444 var_name_arg.arg_repetition = eArgRepeatStar; 445 446 // There is only one variant this argument could be; put it into the 447 // argument entry. 448 arg.push_back(var_name_arg); 449 450 // Push the data for the first argument into the m_arguments vector. 451 m_arguments.push_back(arg); 452 453 m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 454 m_option_group.Append(&m_option_format, 455 OptionGroupFormat::OPTION_GROUP_FORMAT | 456 OptionGroupFormat::OPTION_GROUP_GDB_FMT, 457 LLDB_OPT_SET_1); 458 m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 459 m_option_group.Finalize(); 460 } 461 462 ~CommandObjectFrameVariable() override = default; 463 464 Options *GetOptions() override { return &m_option_group; } 465 466 int HandleArgumentCompletion(Args &input, int &cursor_index, 467 int &cursor_char_position, 468 OptionElementVector &opt_element_vector, 469 int match_start_point, int max_return_elements, 470 bool &word_complete, 471 StringList &matches) override { 472 // Arguments are the standard source file completer. 473 auto completion_str = input[cursor_index].ref; 474 completion_str = completion_str.take_front(cursor_char_position); 475 476 CommandCompletions::InvokeCommonCompletionCallbacks( 477 GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, 478 completion_str, match_start_point, max_return_elements, nullptr, 479 word_complete, matches); 480 return matches.GetSize(); 481 } 482 483 protected: 484 llvm::StringRef GetScopeString(VariableSP var_sp) { 485 if (!var_sp) 486 return llvm::StringRef::withNullAsEmpty(nullptr); 487 488 switch (var_sp->GetScope()) { 489 case eValueTypeVariableGlobal: 490 return "GLOBAL: "; 491 case eValueTypeVariableStatic: 492 return "STATIC: "; 493 case eValueTypeVariableArgument: 494 return "ARG: "; 495 case eValueTypeVariableLocal: 496 return "LOCAL: "; 497 case eValueTypeVariableThreadLocal: 498 return "THREAD: "; 499 default: 500 break; 501 } 502 503 return llvm::StringRef::withNullAsEmpty(nullptr); 504 } 505 506 bool DoExecute(Args &command, CommandReturnObject &result) override { 507 // No need to check "frame" for validity as eCommandRequiresFrame ensures 508 // it is valid 509 StackFrame *frame = m_exe_ctx.GetFramePtr(); 510 511 Stream &s = result.GetOutputStream(); 512 513 // Be careful about the stack frame, if any summary formatter runs code, it 514 // might clear the StackFrameList for the thread. So hold onto a shared 515 // pointer to the frame so it stays alive. 516 517 VariableList *variable_list = 518 frame->GetVariableList(m_option_variable.show_globals); 519 520 VariableSP var_sp; 521 ValueObjectSP valobj_sp; 522 523 TypeSummaryImplSP summary_format_sp; 524 if (!m_option_variable.summary.IsCurrentValueEmpty()) 525 DataVisualization::NamedSummaryFormats::GetSummaryFormat( 526 ConstString(m_option_variable.summary.GetCurrentValue()), 527 summary_format_sp); 528 else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 529 summary_format_sp.reset(new StringSummaryFormat( 530 TypeSummaryImpl::Flags(), 531 m_option_variable.summary_string.GetCurrentValue())); 532 533 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( 534 eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault, 535 summary_format_sp)); 536 537 const SymbolContext &sym_ctx = 538 frame->GetSymbolContext(eSymbolContextFunction); 539 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 540 m_option_variable.show_globals = true; 541 542 if (variable_list) { 543 const Format format = m_option_format.GetFormat(); 544 options.SetFormat(format); 545 546 if (!command.empty()) { 547 VariableList regex_var_list; 548 549 // If we have any args to the variable command, we will make variable 550 // objects from them... 551 for (auto &entry : command) { 552 if (m_option_variable.use_regex) { 553 const size_t regex_start_index = regex_var_list.GetSize(); 554 llvm::StringRef name_str = entry.ref; 555 RegularExpression regex(name_str); 556 if (regex.Compile(name_str)) { 557 size_t num_matches = 0; 558 const size_t num_new_regex_vars = 559 variable_list->AppendVariablesIfUnique(regex, regex_var_list, 560 num_matches); 561 if (num_new_regex_vars > 0) { 562 for (size_t regex_idx = regex_start_index, 563 end_index = regex_var_list.GetSize(); 564 regex_idx < end_index; ++regex_idx) { 565 var_sp = regex_var_list.GetVariableAtIndex(regex_idx); 566 if (var_sp) { 567 valobj_sp = frame->GetValueObjectForFrameVariable( 568 var_sp, m_varobj_options.use_dynamic); 569 if (valobj_sp) { 570 std::string scope_string; 571 if (m_option_variable.show_scope) 572 scope_string = GetScopeString(var_sp).str(); 573 574 if (!scope_string.empty()) 575 s.PutCString(scope_string); 576 577 if (m_option_variable.show_decl && 578 var_sp->GetDeclaration().GetFile()) { 579 bool show_fullpaths = false; 580 bool show_module = true; 581 if (var_sp->DumpDeclaration(&s, show_fullpaths, 582 show_module)) 583 s.PutCString(": "); 584 } 585 valobj_sp->Dump(result.GetOutputStream(), options); 586 } 587 } 588 } 589 } else if (num_matches == 0) { 590 result.GetErrorStream().Printf("error: no variables matched " 591 "the regular expression '%s'.\n", 592 entry.c_str()); 593 } 594 } else { 595 char regex_error[1024]; 596 if (regex.GetErrorAsCString(regex_error, sizeof(regex_error))) 597 result.GetErrorStream().Printf("error: %s\n", regex_error); 598 else 599 result.GetErrorStream().Printf( 600 "error: unknown regex error when compiling '%s'\n", 601 entry.c_str()); 602 } 603 } else // No regex, either exact variable names or variable 604 // expressions. 605 { 606 Status error; 607 uint32_t expr_path_options = 608 StackFrame::eExpressionPathOptionCheckPtrVsMember | 609 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 610 StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 611 lldb::VariableSP var_sp; 612 valobj_sp = frame->GetValueForVariableExpressionPath( 613 entry.ref, m_varobj_options.use_dynamic, expr_path_options, 614 var_sp, error); 615 if (valobj_sp) { 616 std::string scope_string; 617 if (m_option_variable.show_scope) 618 scope_string = GetScopeString(var_sp).str(); 619 620 if (!scope_string.empty()) 621 s.PutCString(scope_string); 622 if (m_option_variable.show_decl && var_sp && 623 var_sp->GetDeclaration().GetFile()) { 624 var_sp->GetDeclaration().DumpStopContext(&s, false); 625 s.PutCString(": "); 626 } 627 628 options.SetFormat(format); 629 options.SetVariableFormatDisplayLanguage( 630 valobj_sp->GetPreferredDisplayLanguage()); 631 632 Stream &output_stream = result.GetOutputStream(); 633 options.SetRootValueObjectName( 634 valobj_sp->GetParent() ? entry.c_str() : nullptr); 635 valobj_sp->Dump(output_stream, options); 636 } else { 637 const char *error_cstr = error.AsCString(nullptr); 638 if (error_cstr) 639 result.GetErrorStream().Printf("error: %s\n", error_cstr); 640 else 641 result.GetErrorStream().Printf("error: unable to find any " 642 "variable expression path that " 643 "matches '%s'.\n", 644 entry.c_str()); 645 } 646 } 647 } 648 } else // No command arg specified. Use variable_list, instead. 649 { 650 const size_t num_variables = variable_list->GetSize(); 651 if (num_variables > 0) { 652 for (size_t i = 0; i < num_variables; i++) { 653 var_sp = variable_list->GetVariableAtIndex(i); 654 switch (var_sp->GetScope()) { 655 case eValueTypeVariableGlobal: 656 if (!m_option_variable.show_globals) 657 continue; 658 break; 659 case eValueTypeVariableStatic: 660 if (!m_option_variable.show_globals) 661 continue; 662 break; 663 case eValueTypeVariableArgument: 664 if (!m_option_variable.show_args) 665 continue; 666 break; 667 case eValueTypeVariableLocal: 668 if (!m_option_variable.show_locals) 669 continue; 670 break; 671 default: 672 continue; 673 break; 674 } 675 std::string scope_string; 676 if (m_option_variable.show_scope) 677 scope_string = GetScopeString(var_sp).str(); 678 679 // Use the variable object code to make sure we are using the same 680 // APIs as the public API will be using... 681 valobj_sp = frame->GetValueObjectForFrameVariable( 682 var_sp, m_varobj_options.use_dynamic); 683 if (valobj_sp) { 684 // When dumping all variables, don't print any variables that are 685 // not in scope to avoid extra unneeded output 686 if (valobj_sp->IsInScope()) { 687 if (!valobj_sp->GetTargetSP() 688 ->GetDisplayRuntimeSupportValues() && 689 valobj_sp->IsRuntimeSupportValue()) 690 continue; 691 692 if (!scope_string.empty()) 693 s.PutCString(scope_string); 694 695 if (m_option_variable.show_decl && 696 var_sp->GetDeclaration().GetFile()) { 697 var_sp->GetDeclaration().DumpStopContext(&s, false); 698 s.PutCString(": "); 699 } 700 701 options.SetFormat(format); 702 options.SetVariableFormatDisplayLanguage( 703 valobj_sp->GetPreferredDisplayLanguage()); 704 options.SetRootValueObjectName( 705 var_sp ? var_sp->GetName().AsCString() : nullptr); 706 valobj_sp->Dump(result.GetOutputStream(), options); 707 } 708 } 709 } 710 } 711 } 712 result.SetStatus(eReturnStatusSuccessFinishResult); 713 } 714 715 if (m_interpreter.TruncationWarningNecessary()) { 716 result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 717 m_cmd_name.c_str()); 718 m_interpreter.TruncationWarningGiven(); 719 } 720 721 // Increment statistics. 722 bool res = result.Succeeded(); 723 Target *target = GetSelectedOrDummyTarget(); 724 if (res) 725 target->IncrementStats(StatisticKind::FrameVarSuccess); 726 else 727 target->IncrementStats(StatisticKind::FrameVarFailure); 728 return res; 729 } 730 731 protected: 732 OptionGroupOptions m_option_group; 733 OptionGroupVariable m_option_variable; 734 OptionGroupFormat m_option_format; 735 OptionGroupValueObjectDisplay m_varobj_options; 736 }; 737 738 #pragma mark CommandObjectMultiwordFrame 739 740 //------------------------------------------------------------------------- 741 // CommandObjectMultiwordFrame 742 //------------------------------------------------------------------------- 743 744 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 745 CommandInterpreter &interpreter) 746 : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and " 747 "examing the current " 748 "thread's stack frames.", 749 "frame <subcommand> [<subcommand-options>]") { 750 LoadSubCommand("diagnose", 751 CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 752 LoadSubCommand("info", 753 CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 754 LoadSubCommand("select", 755 CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 756 LoadSubCommand("variable", 757 CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 758 } 759 760 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 761