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 #include "CommandObjectFrame.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Core/Debugger.h" 17 #include "lldb/Core/Module.h" 18 #include "lldb/Core/StreamFile.h" 19 #include "lldb/Core/Timer.h" 20 #include "lldb/Core/Value.h" 21 #include "lldb/Core/ValueObject.h" 22 #include "lldb/Core/ValueObjectVariable.h" 23 #include "lldb/Interpreter/Args.h" 24 #include "lldb/Interpreter/CommandInterpreter.h" 25 #include "lldb/Interpreter/CommandReturnObject.h" 26 #include "lldb/Interpreter/Options.h" 27 #include "lldb/Symbol/ClangASTType.h" 28 #include "lldb/Symbol/ClangASTContext.h" 29 #include "lldb/Symbol/ObjectFile.h" 30 #include "lldb/Symbol/SymbolContext.h" 31 #include "lldb/Symbol/Type.h" 32 #include "lldb/Symbol/Variable.h" 33 #include "lldb/Symbol/VariableList.h" 34 #include "lldb/Target/Process.h" 35 #include "lldb/Target/StackFrame.h" 36 #include "lldb/Target/Thread.h" 37 #include "lldb/Target/Target.h" 38 39 #include "CommandObjectThread.h" 40 41 using namespace lldb; 42 using namespace lldb_private; 43 44 #pragma mark CommandObjectFrameInfo 45 46 //------------------------------------------------------------------------- 47 // CommandObjectFrameInfo 48 //------------------------------------------------------------------------- 49 50 class CommandObjectFrameInfo : public CommandObject 51 { 52 public: 53 54 CommandObjectFrameInfo () : 55 CommandObject ("frame info", 56 "Lists information about the currently selected frame in the current thread.", 57 "frame info", 58 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) 59 { 60 } 61 62 ~CommandObjectFrameInfo () 63 { 64 } 65 66 bool 67 Execute (CommandInterpreter &interpreter, 68 Args& command, 69 CommandReturnObject &result) 70 { 71 ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext()); 72 if (exe_ctx.frame) 73 { 74 exe_ctx.frame->Dump (&result.GetOutputStream(), true); 75 result.GetOutputStream().EOL(); 76 result.SetStatus (eReturnStatusSuccessFinishResult); 77 } 78 else 79 { 80 result.AppendError ("no current frame"); 81 result.SetStatus (eReturnStatusFailed); 82 } 83 return result.Succeeded(); 84 } 85 }; 86 87 #pragma mark CommandObjectFrameSelect 88 89 //------------------------------------------------------------------------- 90 // CommandObjectFrameSelect 91 //------------------------------------------------------------------------- 92 93 class CommandObjectFrameSelect : public CommandObject 94 { 95 public: 96 97 CommandObjectFrameSelect () : 98 CommandObject ("frame select", 99 "Select the current frame by index in the current thread.", 100 "frame select <frame-index>", 101 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) 102 { 103 } 104 105 ~CommandObjectFrameSelect () 106 { 107 } 108 109 bool 110 Execute (CommandInterpreter &interpreter, 111 Args& command, 112 CommandReturnObject &result) 113 { 114 ExecutionContext exe_ctx (interpreter.GetDebugger().GetExecutionContext()); 115 if (exe_ctx.thread) 116 { 117 if (command.GetArgumentCount() == 1) 118 { 119 const char *frame_idx_cstr = command.GetArgumentAtIndex(0); 120 121 const uint32_t num_frames = exe_ctx.thread->GetStackFrameCount(); 122 const uint32_t frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0); 123 if (frame_idx < num_frames) 124 { 125 exe_ctx.thread->SetSelectedFrameByIndex (frame_idx); 126 exe_ctx.frame = exe_ctx.thread->GetSelectedFrame ().get(); 127 128 if (exe_ctx.frame) 129 { 130 bool already_shown = false; 131 SymbolContext frame_sc(exe_ctx.frame->GetSymbolContext(eSymbolContextLineEntry)); 132 if (interpreter.GetDebugger().UseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0) 133 { 134 already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line); 135 } 136 137 if (DisplayFrameForExecutionContext (exe_ctx.thread, 138 exe_ctx.frame, 139 interpreter, 140 result.GetOutputStream(), 141 true, 142 !already_shown, 143 3, 144 3)) 145 { 146 result.SetStatus (eReturnStatusSuccessFinishResult); 147 return result.Succeeded(); 148 } 149 } 150 } 151 if (frame_idx == UINT32_MAX) 152 result.AppendErrorWithFormat ("Invalid frame index: %s.\n", frame_idx_cstr); 153 else 154 result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx); 155 } 156 else 157 { 158 result.AppendError ("invalid arguments"); 159 result.AppendErrorWithFormat ("Usage: %s\n", m_cmd_syntax.c_str()); 160 } 161 } 162 else 163 { 164 result.AppendError ("no current thread"); 165 } 166 result.SetStatus (eReturnStatusFailed); 167 return false; 168 } 169 }; 170 171 #pragma mark CommandObjectFrameVariable 172 //---------------------------------------------------------------------- 173 // List images with associated information 174 //---------------------------------------------------------------------- 175 class CommandObjectFrameVariable : public CommandObject 176 { 177 public: 178 179 class CommandOptions : public Options 180 { 181 public: 182 183 CommandOptions () : 184 Options() 185 { 186 ResetOptionValues (); 187 } 188 189 virtual 190 ~CommandOptions () 191 { 192 } 193 194 virtual Error 195 SetOptionValue (int option_idx, const char *option_arg) 196 { 197 Error error; 198 bool success; 199 char short_option = (char) m_getopt_table[option_idx].val; 200 switch (short_option) 201 { 202 case 'o': use_objc = true; break; 203 case 'n': name = option_arg; break; 204 case 'r': use_regex = true; break; 205 case 'a': show_args = false; break; 206 case 'l': show_locals = false; break; 207 case 'g': show_globals = false; break; 208 case 't': show_types = false; break; 209 case 'y': show_summary = false; break; 210 case 'L': show_location= true; break; 211 case 'D': debug = true; break; 212 case 'd': 213 max_depth = Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success); 214 if (!success) 215 error.SetErrorStringWithFormat("Invalid max depth '%s'.\n", option_arg); 216 break; 217 218 case 'p': 219 ptr_depth = Args::StringToUInt32 (option_arg, 0, 0, &success); 220 if (!success) 221 error.SetErrorStringWithFormat("Invalid pointer depth '%s'.\n", option_arg); 222 break; 223 224 case 'G': 225 { 226 ConstString const_string (option_arg); 227 globals.push_back(const_string); 228 } 229 break; 230 231 case 's': 232 show_scope = true; 233 break; 234 235 default: 236 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); 237 break; 238 } 239 240 return error; 241 } 242 243 void 244 ResetOptionValues () 245 { 246 Options::ResetOptionValues(); 247 248 name.clear(); 249 use_objc = false; 250 use_regex = false; 251 show_args = true; 252 show_locals = true; 253 show_globals = true; 254 show_types = true; 255 show_scope = false; 256 show_summary = true; 257 show_location = false; 258 debug = false; 259 max_depth = UINT32_MAX; 260 ptr_depth = 0; 261 globals.clear(); 262 } 263 264 const lldb::OptionDefinition* 265 GetDefinitions () 266 { 267 return g_option_table; 268 } 269 270 // Options table: Required for subclasses of Options. 271 272 static lldb::OptionDefinition g_option_table[]; 273 std::string name; 274 bool use_objc; 275 bool use_regex; 276 bool show_args; 277 bool show_locals; 278 bool show_globals; 279 bool show_types; 280 bool show_scope; // local/arg/global/static 281 bool show_summary; 282 bool show_location; 283 bool debug; 284 uint32_t max_depth; // The depth to print when dumping concrete (not pointers) aggreate values 285 uint32_t ptr_depth; // The default depth that is dumped when we find pointers 286 std::vector<ConstString> globals; 287 // Instance variables to hold the values for command options. 288 }; 289 290 CommandObjectFrameVariable () : 291 CommandObject ( 292 "frame variable", 293 "Show specified argument, local variable, static variable or global variable for the current frame. If none specified, list them all.", 294 "frame variable [<cmd-options>] [<var-name1> [<var-name2>...]]") 295 { 296 } 297 298 virtual 299 ~CommandObjectFrameVariable () 300 { 301 } 302 303 virtual 304 Options * 305 GetOptions () 306 { 307 return &m_options; 308 } 309 310 void 311 DumpVariable (CommandReturnObject &result, ExecutionContext *exe_ctx, Variable *variable) 312 { 313 if (variable) 314 { 315 Stream &s = result.GetOutputStream(); 316 DWARFExpression &expr = variable->LocationExpression(); 317 Value expr_result; 318 Error expr_error; 319 Type *variable_type = variable->GetType(); 320 bool expr_success = expr.Evaluate(exe_ctx, NULL, NULL, expr_result, &expr_error); 321 322 if (m_options.debug) 323 s.Printf ("Variable{0x%8.8x}: ", variable->GetID()); 324 325 if (!expr_success) 326 s.Printf ("%s = ERROR: %s\n", variable->GetName().AsCString(NULL), expr_error.AsCString()); 327 else 328 { 329 Value::ValueType expr_value_type = expr_result.GetValueType(); 330 switch (expr_value_type) 331 { 332 case Value::eValueTypeScalar: 333 s.Printf ("%s = ", variable->GetName().AsCString(NULL)); 334 if (variable_type) 335 { 336 DataExtractor data; 337 if (expr_result.ResolveValue (exe_ctx, NULL).GetData (data)) 338 variable_type->DumpValue (exe_ctx, &s, data, 0, m_options.show_types, m_options.show_summary, m_options.debug); 339 } 340 break; 341 342 case Value::eValueTypeFileAddress: 343 case Value::eValueTypeLoadAddress: 344 case Value::eValueTypeHostAddress: 345 { 346 s.Printf ("%s = ", variable->GetName().AsCString(NULL)); 347 lldb::addr_t addr = LLDB_INVALID_ADDRESS; 348 lldb::AddressType addr_type = eAddressTypeLoad; 349 350 if (expr_value_type == Value::eValueTypeFileAddress) 351 { 352 lldb::addr_t file_addr = expr_result.ResolveValue (exe_ctx, NULL).ULongLong(LLDB_INVALID_ADDRESS); 353 SymbolContext var_sc; 354 variable->CalculateSymbolContext(&var_sc); 355 if (var_sc.module_sp) 356 { 357 ObjectFile *objfile = var_sc.module_sp->GetObjectFile(); 358 if (objfile) 359 { 360 Address so_addr(file_addr, objfile->GetSectionList()); 361 addr = so_addr.GetLoadAddress(exe_ctx->process); 362 } 363 if (addr == LLDB_INVALID_ADDRESS) 364 { 365 result.GetErrorStream().Printf ("error: %s is not loaded", var_sc.module_sp->GetFileSpec().GetFilename().AsCString()); 366 } 367 } 368 else 369 { 370 result.GetErrorStream().Printf ("error: unable to resolve the variable address 0x%llx", file_addr); 371 } 372 } 373 else 374 { 375 if (expr_value_type == Value::eValueTypeHostAddress) 376 addr_type = eAddressTypeHost; 377 addr = expr_result.ResolveValue (exe_ctx, NULL).ULongLong(LLDB_INVALID_ADDRESS); 378 } 379 380 if (addr != LLDB_INVALID_ADDRESS) 381 { 382 if (m_options.debug) 383 s.Printf("@ 0x%8.8llx, value = ", addr); 384 variable_type->DumpValueInMemory (exe_ctx, &s, addr, addr_type, m_options.show_types, m_options.show_summary, m_options.debug); 385 } 386 } 387 break; 388 } 389 s.EOL(); 390 } 391 } 392 } 393 394 void 395 DumpValueObject (CommandReturnObject &result, 396 ExecutionContextScope *exe_scope, 397 ValueObject *valobj, 398 const char *root_valobj_name, 399 uint32_t ptr_depth, 400 uint32_t curr_depth, 401 uint32_t max_depth, 402 bool use_objc) 403 { 404 if (valobj) 405 { 406 Stream &s = result.GetOutputStream(); 407 408 //const char *loc_cstr = valobj->GetLocationAsCString(); 409 if (m_options.show_location) 410 { 411 s.Printf("@ %s: ", valobj->GetLocationAsCString(exe_scope)); 412 } 413 if (m_options.debug) 414 s.Printf ("%p ValueObject{%u} ", valobj, valobj->GetID()); 415 416 s.Indent(); 417 418 if (m_options.show_types) 419 s.Printf("(%s) ", valobj->GetTypeName().AsCString()); 420 421 const char *name_cstr = root_valobj_name ? root_valobj_name : valobj->GetName().AsCString(""); 422 s.Printf ("%s = ", name_cstr); 423 424 const char *val_cstr = valobj->GetValueAsCString(exe_scope); 425 const char *err_cstr = valobj->GetError().AsCString(); 426 427 if (err_cstr) 428 { 429 s.Printf ("error: %s\n", err_cstr); 430 } 431 else 432 { 433 const char *sum_cstr = valobj->GetSummaryAsCString(exe_scope); 434 435 const bool is_aggregate = ClangASTContext::IsAggregateType (valobj->GetOpaqueClangQualType()); 436 437 if (val_cstr) 438 s.PutCString(val_cstr); 439 440 if (sum_cstr) 441 s.Printf(" %s", sum_cstr); 442 443 if (use_objc) 444 { 445 if (!ClangASTContext::IsPointerType (valobj->GetOpaqueClangQualType())) 446 return; 447 448 if (!valobj->GetValueIsValid()) 449 return; 450 451 Process *process = exe_scope->CalculateProcess(); 452 453 if (!process) 454 return; 455 456 Scalar scalar; 457 458 if (!ClangASTType::GetValueAsScalar (valobj->GetClangAST(), 459 valobj->GetOpaqueClangQualType(), 460 valobj->GetDataExtractor(), 461 0, 462 valobj->GetByteSize(), 463 scalar)) 464 return; 465 466 ConstString po_output; 467 468 ExecutionContext exe_ctx; 469 exe_scope->Calculate(exe_ctx); 470 471 Value val(scalar); 472 val.SetContext(Value::eContextTypeOpaqueClangQualType, 473 ClangASTContext::GetVoidPtrType(valobj->GetClangAST(), false)); 474 475 if (!process->GetObjCObjectPrinter().PrintObject(po_output, val, exe_ctx)) 476 return; 477 478 s.Printf("\n%s\n", po_output.GetCString()); 479 480 return; 481 } 482 483 484 if (curr_depth < max_depth) 485 { 486 if (is_aggregate) 487 s.PutChar('{'); 488 489 bool is_ptr_or_ref = ClangASTContext::IsPointerOrReferenceType (valobj->GetOpaqueClangQualType()); 490 491 if (is_ptr_or_ref && ptr_depth == 0) 492 return; 493 494 const uint32_t num_children = valobj->GetNumChildren(); 495 if (num_children) 496 { 497 s.IndentMore(); 498 for (uint32_t idx=0; idx<num_children; ++idx) 499 { 500 ValueObjectSP child_sp(valobj->GetChildAtIndex(idx, true)); 501 if (child_sp.get()) 502 { 503 s.EOL(); 504 DumpValueObject (result, 505 exe_scope, 506 child_sp.get(), 507 NULL, 508 is_ptr_or_ref ? ptr_depth - 1 : ptr_depth, 509 curr_depth + 1, 510 max_depth, 511 false); 512 if (idx + 1 < num_children) 513 s.PutChar(','); 514 } 515 } 516 s.IndentLess(); 517 } 518 if (is_aggregate) 519 { 520 s.EOL(); 521 s.Indent("}"); 522 } 523 } 524 else 525 { 526 if (is_aggregate) 527 { 528 s.PutCString("{...}"); 529 } 530 } 531 532 } 533 } 534 } 535 536 virtual bool 537 Execute 538 ( 539 CommandInterpreter &interpreter, 540 Args& command, 541 CommandReturnObject &result 542 ) 543 { 544 ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext()); 545 if (exe_ctx.frame == NULL) 546 { 547 result.AppendError ("invalid frame"); 548 result.SetStatus (eReturnStatusFailed); 549 return false; 550 } 551 else 552 { 553 VariableList variable_list; 554 555 bool show_inlined = true; // TODO: Get this from the process 556 SymbolContext frame_sc = exe_ctx.frame->GetSymbolContext (eSymbolContextEverything); 557 if (exe_ctx.frame && frame_sc.block) 558 frame_sc.block->AppendVariables(true, true, show_inlined, &variable_list); 559 VariableSP var_sp; 560 ValueObjectSP valobj_sp; 561 //ValueObjectList &valobj_list = exe_ctx.frame->GetValueObjectList(); 562 const char *name_cstr = NULL; 563 size_t idx; 564 if (!m_options.globals.empty()) 565 { 566 uint32_t fail_count = 0; 567 if (exe_ctx.target) 568 { 569 const size_t num_globals = m_options.globals.size(); 570 for (idx = 0; idx < num_globals; ++idx) 571 { 572 VariableList global_var_list; 573 const uint32_t num_matching_globals = exe_ctx.target->GetImages().FindGlobalVariables (m_options.globals[idx], true, UINT32_MAX, global_var_list); 574 575 if (num_matching_globals == 0) 576 { 577 ++fail_count; 578 result.GetErrorStream().Printf ("error: can't find global variable '%s'\n", m_options.globals[idx].AsCString()); 579 } 580 else 581 { 582 for (uint32_t global_idx=0; global_idx<num_matching_globals; ++global_idx) 583 { 584 var_sp = global_var_list.GetVariableAtIndex(global_idx); 585 if (var_sp) 586 { 587 valobj_sp = exe_ctx.frame->GetValueObjectList().FindValueObjectByValueName (m_options.globals[idx].AsCString()); 588 if (!valobj_sp) 589 valobj_sp.reset (new ValueObjectVariable (var_sp)); 590 591 if (valobj_sp) 592 { 593 exe_ctx.frame->GetValueObjectList().Append (valobj_sp); 594 DumpValueObject (result, exe_ctx.frame, valobj_sp.get(), name_cstr, m_options.ptr_depth, 0, m_options.max_depth, false); 595 result.GetOutputStream().EOL(); 596 } 597 } 598 } 599 } 600 } 601 } 602 if (fail_count) 603 { 604 result.SetStatus (eReturnStatusFailed); 605 } 606 } 607 608 if (command.GetArgumentCount() > 0) 609 { 610 // If we have any args to the variable command, we will make 611 // variable objects from them... 612 for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != NULL; ++idx) 613 { 614 uint32_t ptr_depth = m_options.ptr_depth; 615 // If first character is a '*', then show pointer contents 616 if (name_cstr[0] == '*') 617 { 618 ++ptr_depth; 619 name_cstr++; // Skip the '*' 620 } 621 622 std::string var_path (name_cstr); 623 size_t separator_idx = var_path.find_first_of(".-["); 624 625 ConstString name_const_string; 626 if (separator_idx == std::string::npos) 627 name_const_string.SetCString (var_path.c_str()); 628 else 629 name_const_string.SetCStringWithLength (var_path.c_str(), separator_idx); 630 631 var_sp = variable_list.FindVariable(name_const_string); 632 if (var_sp) 633 { 634 //DumpVariable (result, &exe_ctx, var_sp.get()); 635 // TODO: redo history variables using a different map 636 // if (var_path[0] == '$') 637 // valobj_sp = valobj_list.FindValueObjectByValueObjectName (name_const_string.GetCString()); 638 // else 639 valobj_sp = exe_ctx.frame->GetValueObjectList().FindValueObjectByValueName (name_const_string.GetCString()); 640 641 if (!valobj_sp) 642 { 643 valobj_sp.reset (new ValueObjectVariable (var_sp)); 644 exe_ctx.frame->GetValueObjectList().Append (valobj_sp); 645 } 646 647 var_path.erase (0, name_const_string.GetLength ()); 648 // We are dumping at least one child 649 while (separator_idx != std::string::npos) 650 { 651 // Calculate the next separator index ahead of time 652 ValueObjectSP child_valobj_sp; 653 const char separator_type = var_path[0]; 654 switch (separator_type) 655 { 656 657 case '-': 658 if (var_path.size() >= 2 && var_path[1] != '>') 659 { 660 result.GetErrorStream().Printf ("error: invalid character in variable path starting at '%s'\n", 661 var_path.c_str()); 662 var_path.clear(); 663 valobj_sp.reset(); 664 break; 665 } 666 var_path.erase (0, 1); // Remove the '-' 667 // Fall through 668 case '.': 669 { 670 var_path.erase (0, 1); // Remove the '.' or '>' 671 separator_idx = var_path.find_first_of(".-["); 672 ConstString child_name; 673 if (separator_idx == std::string::npos) 674 child_name.SetCString (var_path.c_str()); 675 else 676 child_name.SetCStringWithLength(var_path.c_str(), separator_idx); 677 678 child_valobj_sp = valobj_sp->GetChildMemberWithName (child_name, true); 679 if (!child_valobj_sp) 680 { 681 result.GetErrorStream().Printf ("error: can't find child of '%s' named '%s'\n", 682 valobj_sp->GetName().AsCString(), 683 child_name.GetCString()); 684 var_path.clear(); 685 valobj_sp.reset(); 686 break; 687 } 688 // Remove the child name from the path 689 var_path.erase(0, child_name.GetLength()); 690 } 691 break; 692 693 case '[': 694 // Array member access, or treating pointer as an array 695 if (var_path.size() > 2) // Need at least two brackets and a number 696 { 697 char *end = NULL; 698 int32_t child_index = ::strtol (&var_path[1], &end, 0); 699 if (end && *end == ']') 700 { 701 702 if (valobj_sp->IsPointerType ()) 703 { 704 child_valobj_sp = valobj_sp->GetSyntheticArrayMemberFromPointer (child_index, true); 705 } 706 else 707 { 708 child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true); 709 } 710 711 if (!child_valobj_sp) 712 { 713 result.GetErrorStream().Printf ("error: invalid array index %u in '%s'\n", 714 child_index, 715 valobj_sp->GetName().AsCString()); 716 var_path.clear(); 717 valobj_sp.reset(); 718 break; 719 } 720 721 // Erase the array member specification '[%i]' where %i is the array index 722 var_path.erase(0, (end - var_path.c_str()) + 1); 723 separator_idx = var_path.find_first_of(".-["); 724 725 // Break out early from the switch since we were able to find the child member 726 break; 727 } 728 } 729 result.GetErrorStream().Printf ("error: invalid array member specification for '%s' starting at '%s'\n", 730 valobj_sp->GetName().AsCString(), 731 var_path.c_str()); 732 var_path.clear(); 733 valobj_sp.reset(); 734 break; 735 736 break; 737 738 default: 739 result.GetErrorStream().Printf ("error: invalid character in variable path starting at '%s'\n", 740 var_path.c_str()); 741 var_path.clear(); 742 valobj_sp.reset(); 743 separator_idx = std::string::npos; 744 break; 745 } 746 747 if (child_valobj_sp) 748 valobj_sp = child_valobj_sp; 749 750 if (var_path.empty()) 751 break; 752 753 } 754 755 if (valobj_sp) 756 { 757 DumpValueObject (result, exe_ctx.frame, valobj_sp.get(), name_cstr, ptr_depth, 0, m_options.max_depth, m_options.use_objc); 758 result.GetOutputStream().EOL(); 759 } 760 } 761 else 762 { 763 result.GetErrorStream().Printf ("error: unable to find any variables named '%s'\n", name_cstr); 764 var_path.clear(); 765 } 766 } 767 } 768 else 769 { 770 771 if (m_options.show_globals) 772 { 773 if (frame_sc.comp_unit) 774 { 775 variable_list.AddVariables (frame_sc.comp_unit->GetVariableList(true).get()); 776 } 777 } 778 779 const uint32_t num_variables = variable_list.GetSize(); 780 781 if (num_variables > 0) 782 { 783 for (uint32_t i=0; i<num_variables; i++) 784 { 785 Variable *variable = variable_list.GetVariableAtIndex(i).get(); 786 bool dump_variable = true; 787 788 switch (variable->GetScope()) 789 { 790 case eValueTypeVariableGlobal: 791 dump_variable = m_options.show_globals; 792 if (dump_variable && m_options.show_scope) 793 result.GetOutputStream().PutCString("GLOBAL: "); 794 break; 795 796 case eValueTypeVariableStatic: 797 dump_variable = m_options.show_globals; 798 if (dump_variable && m_options.show_scope) 799 result.GetOutputStream().PutCString("STATIC: "); 800 break; 801 802 case eValueTypeVariableArgument: 803 dump_variable = m_options.show_args; 804 if (dump_variable && m_options.show_scope) 805 result.GetOutputStream().PutCString(" ARG: "); 806 break; 807 808 case eValueTypeVariableLocal: 809 dump_variable = m_options.show_locals; 810 if (dump_variable && m_options.show_scope) 811 result.GetOutputStream().PutCString(" LOCAL: "); 812 break; 813 814 default: 815 break; 816 } 817 818 if (dump_variable) 819 DumpVariable (result, &exe_ctx, variable); 820 } 821 } 822 } 823 result.SetStatus (eReturnStatusSuccessFinishResult); 824 } 825 return result.Succeeded(); 826 } 827 protected: 828 829 CommandOptions m_options; 830 }; 831 832 lldb::OptionDefinition 833 CommandObjectFrameVariable::CommandOptions::g_option_table[] = 834 { 835 { LLDB_OPT_SET_1, false, "debug", 'D', no_argument, NULL, 0, NULL, "Show verbose debug information."}, 836 { LLDB_OPT_SET_1, false, "depth", 'd', required_argument, NULL, 0, "<count>", "Set the max recurse depth when dumping aggregate types (default is infinity)."}, 837 { LLDB_OPT_SET_1, false, "globals", 'g', no_argument, NULL, 0, NULL, "List global and static variables for the current stack frame source file."}, 838 { LLDB_OPT_SET_1, false, "global", 'G', required_argument, NULL, 0, NULL, "Find a global variable by name (which might not be in the current stack frame source file)."}, 839 { LLDB_OPT_SET_1, false, "location", 'L', no_argument, NULL, 0, NULL, "Show variable location information."}, 840 { LLDB_OPT_SET_1, false, "name", 'n', required_argument, NULL, 0, "<name>", "Lookup a variable by name or regex (--regex) for the current execution context."}, 841 { LLDB_OPT_SET_1, false, "no-args", 'a', no_argument, NULL, 0, NULL, "Omit function arguments."}, 842 { LLDB_OPT_SET_1, false, "no-locals", 'l', no_argument, NULL, 0, NULL, "Omit local variables."}, 843 { LLDB_OPT_SET_1, false, "no-types", 't', no_argument, NULL, 0, NULL, "Omit variable type names."}, 844 { LLDB_OPT_SET_1, false, "no-summary", 'y', no_argument, NULL, 0, NULL, "Omit summary information."}, 845 { LLDB_OPT_SET_1, false, "scope", 's', no_argument, NULL, 0, NULL, "Show variable scope (argument, local, global, static)."}, 846 { LLDB_OPT_SET_1, false, "objc", 'o', no_argument, NULL, 0, NULL, "When looking up a variable by name (--name), print as an Objective-C object."}, 847 { LLDB_OPT_SET_1, false, "ptr-depth", 'p', required_argument, NULL, 0, "<count>", "The number of pointers to be traversed when dumping values (default is zero)."}, 848 { LLDB_OPT_SET_1, false, "regex", 'r', no_argument, NULL, 0, NULL, "The <name> argument for name lookups are regular expressions."}, 849 { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL } 850 }; 851 #pragma mark CommandObjectMultiwordFrame 852 853 //------------------------------------------------------------------------- 854 // CommandObjectMultiwordFrame 855 //------------------------------------------------------------------------- 856 857 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter &interpreter) : 858 CommandObjectMultiword ("frame", 859 "A set of commands for operating on the current thread's frames.", 860 "frame <subcommand> [<subcommand-options>]") 861 { 862 LoadSubCommand (interpreter, "info", CommandObjectSP (new CommandObjectFrameInfo ())); 863 LoadSubCommand (interpreter, "select", CommandObjectSP (new CommandObjectFrameSelect ())); 864 LoadSubCommand (interpreter, "variable", CommandObjectSP (new CommandObjectFrameVariable ())); 865 } 866 867 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame () 868 { 869 } 870 871