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