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