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