CommandObjectFrame.cpp revision 24a6bd9835ed1655984397b0cdf35127e47681e9
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#include <string> 15// Other libraries and framework includes 16// Project includes 17#include "lldb/Breakpoint/Watchpoint.h" 18#include "lldb/Core/DataVisualization.h" 19#include "lldb/Core/Debugger.h" 20#include "lldb/Core/Module.h" 21#include "lldb/Core/StreamFile.h" 22#include "lldb/Core/StreamString.h" 23#include "lldb/Core/Timer.h" 24#include "lldb/Core/Value.h" 25#include "lldb/Core/ValueObject.h" 26#include "lldb/Core/ValueObjectVariable.h" 27#include "lldb/Host/Host.h" 28#include "lldb/Interpreter/Args.h" 29#include "lldb/Interpreter/CommandInterpreter.h" 30#include "lldb/Interpreter/CommandReturnObject.h" 31#include "lldb/Interpreter/Options.h" 32#include "lldb/Interpreter/OptionGroupFormat.h" 33#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" 34#include "lldb/Interpreter/OptionGroupVariable.h" 35#include "lldb/Interpreter/OptionGroupWatchpoint.h" 36#include "lldb/Symbol/ClangASTType.h" 37#include "lldb/Symbol/ClangASTContext.h" 38#include "lldb/Symbol/ObjectFile.h" 39#include "lldb/Symbol/SymbolContext.h" 40#include "lldb/Symbol/Type.h" 41#include "lldb/Symbol/Variable.h" 42#include "lldb/Symbol/VariableList.h" 43#include "lldb/Target/Process.h" 44#include "lldb/Target/StackFrame.h" 45#include "lldb/Target/Thread.h" 46#include "lldb/Target/Target.h" 47 48using namespace lldb; 49using namespace lldb_private; 50 51#pragma mark CommandObjectFrameInfo 52 53//------------------------------------------------------------------------- 54// CommandObjectFrameInfo 55//------------------------------------------------------------------------- 56 57class CommandObjectFrameInfo : public CommandObject 58{ 59public: 60 61 CommandObjectFrameInfo (CommandInterpreter &interpreter) : 62 CommandObject (interpreter, 63 "frame info", 64 "List information about the currently selected frame in the current thread.", 65 "frame info", 66 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) 67 { 68 } 69 70 ~CommandObjectFrameInfo () 71 { 72 } 73 74 bool 75 Execute (Args& command, 76 CommandReturnObject &result) 77 { 78 ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); 79 StackFrame *frame = exe_ctx.GetFramePtr(); 80 if (frame) 81 { 82 frame->DumpUsingSettingsFormat (&result.GetOutputStream()); 83 result.SetStatus (eReturnStatusSuccessFinishResult); 84 } 85 else 86 { 87 result.AppendError ("no current frame"); 88 result.SetStatus (eReturnStatusFailed); 89 } 90 return result.Succeeded(); 91 } 92}; 93 94#pragma mark CommandObjectFrameSelect 95 96//------------------------------------------------------------------------- 97// CommandObjectFrameSelect 98//------------------------------------------------------------------------- 99 100class CommandObjectFrameSelect : public CommandObject 101{ 102public: 103 104 class CommandOptions : public Options 105 { 106 public: 107 108 CommandOptions (CommandInterpreter &interpreter) : 109 Options(interpreter) 110 { 111 OptionParsingStarting (); 112 } 113 114 virtual 115 ~CommandOptions () 116 { 117 } 118 119 virtual Error 120 SetOptionValue (uint32_t option_idx, const char *option_arg) 121 { 122 Error error; 123 bool success = false; 124 char short_option = (char) m_getopt_table[option_idx].val; 125 switch (short_option) 126 { 127 case 'r': 128 relative_frame_offset = Args::StringToSInt32 (option_arg, INT32_MIN, 0, &success); 129 if (!success) 130 error.SetErrorStringWithFormat ("invalid frame offset argument '%s'", option_arg); 131 break; 132 133 default: 134 error.SetErrorStringWithFormat ("invalid short option character '%c'", short_option); 135 break; 136 } 137 138 return error; 139 } 140 141 void 142 OptionParsingStarting () 143 { 144 relative_frame_offset = INT32_MIN; 145 } 146 147 const OptionDefinition* 148 GetDefinitions () 149 { 150 return g_option_table; 151 } 152 153 // Options table: Required for subclasses of Options. 154 155 static OptionDefinition g_option_table[]; 156 int32_t relative_frame_offset; 157 }; 158 159 CommandObjectFrameSelect (CommandInterpreter &interpreter) : 160 CommandObject (interpreter, 161 "frame select", 162 "Select a frame by index from within the current thread and make it the current frame.", 163 NULL, 164 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused), 165 m_options (interpreter) 166 { 167 CommandArgumentEntry arg; 168 CommandArgumentData index_arg; 169 170 // Define the first (and only) variant of this arg. 171 index_arg.arg_type = eArgTypeFrameIndex; 172 index_arg.arg_repetition = eArgRepeatOptional; 173 174 // There is only one variant this argument could be; put it into the argument entry. 175 arg.push_back (index_arg); 176 177 // Push the data for the first argument into the m_arguments vector. 178 m_arguments.push_back (arg); 179 } 180 181 ~CommandObjectFrameSelect () 182 { 183 } 184 185 virtual 186 Options * 187 GetOptions () 188 { 189 return &m_options; 190 } 191 192 193 bool 194 Execute (Args& command, 195 CommandReturnObject &result) 196 { 197 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 198 Thread *thread = exe_ctx.GetThreadPtr(); 199 if (thread) 200 { 201 const uint32_t num_frames = thread->GetStackFrameCount(); 202 uint32_t frame_idx = UINT32_MAX; 203 if (m_options.relative_frame_offset != INT32_MIN) 204 { 205 // The one and only argument is a signed relative frame index 206 frame_idx = thread->GetSelectedFrameIndex (); 207 if (frame_idx == UINT32_MAX) 208 frame_idx = 0; 209 210 if (m_options.relative_frame_offset < 0) 211 { 212 if (frame_idx >= -m_options.relative_frame_offset) 213 frame_idx += m_options.relative_frame_offset; 214 else 215 { 216 if (frame_idx == 0) 217 { 218 //If you are already at the bottom of the stack, then just warn and don't reset the frame. 219 result.AppendError("Already at the bottom of the stack"); 220 result.SetStatus(eReturnStatusFailed); 221 return false; 222 } 223 else 224 frame_idx = 0; 225 } 226 } 227 else if (m_options.relative_frame_offset > 0) 228 { 229 if (num_frames - frame_idx > m_options.relative_frame_offset) 230 frame_idx += m_options.relative_frame_offset; 231 else 232 { 233 if (frame_idx == num_frames - 1) 234 { 235 //If we are already at the top of the stack, just warn and don't reset the frame. 236 result.AppendError("Already at the top of the stack"); 237 result.SetStatus(eReturnStatusFailed); 238 return false; 239 } 240 else 241 frame_idx = num_frames - 1; 242 } 243 } 244 } 245 else 246 { 247 if (command.GetArgumentCount() == 1) 248 { 249 const char *frame_idx_cstr = command.GetArgumentAtIndex(0); 250 frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0); 251 } 252 else if (command.GetArgumentCount() == 0) 253 { 254 frame_idx = thread->GetSelectedFrameIndex (); 255 if (frame_idx == UINT32_MAX) 256 { 257 frame_idx = 0; 258 } 259 } 260 else 261 { 262 result.AppendError ("invalid arguments.\n"); 263 m_options.GenerateOptionUsage (result.GetErrorStream(), this); 264 } 265 } 266 267 if (frame_idx < num_frames) 268 { 269 thread->SetSelectedFrameByIndex (frame_idx); 270 exe_ctx.SetFrameSP(thread->GetSelectedFrame ()); 271 StackFrame *frame = exe_ctx.GetFramePtr(); 272 if (frame) 273 { 274 bool already_shown = false; 275 SymbolContext frame_sc(frame->GetSymbolContext(eSymbolContextLineEntry)); 276 if (m_interpreter.GetDebugger().GetUseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0) 277 { 278 already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line); 279 } 280 281 bool show_frame_info = true; 282 bool show_source = !already_shown; 283 uint32_t source_lines_before = 3; 284 uint32_t source_lines_after = 3; 285 if (frame->GetStatus (result.GetOutputStream(), 286 show_frame_info, 287 show_source, 288 source_lines_before, 289 source_lines_after)) 290 { 291 result.SetStatus (eReturnStatusSuccessFinishResult); 292 return result.Succeeded(); 293 } 294 } 295 } 296 result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx); 297 } 298 else 299 { 300 result.AppendError ("no current thread"); 301 } 302 result.SetStatus (eReturnStatusFailed); 303 return false; 304 } 305protected: 306 307 CommandOptions m_options; 308}; 309 310OptionDefinition 311CommandObjectFrameSelect::CommandOptions::g_option_table[] = 312{ 313{ LLDB_OPT_SET_1, false, "relative", 'r', required_argument, NULL, 0, eArgTypeOffset, "A relative frame index offset from the current frame index."}, 314{ 0, false, NULL, 0, 0, NULL, NULL, eArgTypeNone, NULL } 315}; 316 317#pragma mark CommandObjectFrameVariable 318//---------------------------------------------------------------------- 319// List images with associated information 320//---------------------------------------------------------------------- 321class CommandObjectFrameVariable : public CommandObject 322{ 323public: 324 325 CommandObjectFrameVariable (CommandInterpreter &interpreter) : 326 CommandObject (interpreter, 327 "frame variable", 328 "Show frame variables. All argument and local variables " 329 "that are in scope will be shown when no arguments are given. " 330 "If any arguments are specified, they can be names of " 331 "argument, local, file static and file global variables. " 332 "Children of aggregate variables can be specified such as " 333 "'var->child.x'. " 334 "You can choose to watch a variable with the '-w' option. " 335 "Note that hardware resources for watching are often limited.", 336 NULL, 337 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused), 338 m_option_group (interpreter), 339 m_option_variable(true), // Include the frame specific options by passing "true" 340 m_option_format (eFormatDefault), 341 m_option_watchpoint(), 342 m_varobj_options() 343 { 344 CommandArgumentEntry arg; 345 CommandArgumentData var_name_arg; 346 347 // Define the first (and only) variant of this arg. 348 var_name_arg.arg_type = eArgTypeVarName; 349 var_name_arg.arg_repetition = eArgRepeatStar; 350 351 // There is only one variant this argument could be; put it into the argument entry. 352 arg.push_back (var_name_arg); 353 354 // Push the data for the first argument into the m_arguments vector. 355 m_arguments.push_back (arg); 356 357 m_option_group.Append (&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 358 m_option_group.Append (&m_option_format, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1); 359 m_option_group.Append (&m_option_watchpoint, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 360 m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 361 m_option_group.Finalize(); 362 } 363 364 virtual 365 ~CommandObjectFrameVariable () 366 { 367 } 368 369 virtual 370 Options * 371 GetOptions () 372 { 373 return &m_option_group; 374 } 375 376 377 virtual bool 378 Execute 379 ( 380 Args& command, 381 CommandReturnObject &result 382 ) 383 { 384 ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); 385 StackFrame *frame = exe_ctx.GetFramePtr(); 386 if (frame == NULL) 387 { 388 result.AppendError ("you must be stopped in a valid stack frame to view frame variables."); 389 result.SetStatus (eReturnStatusFailed); 390 return false; 391 } 392 393 Stream &s = result.GetOutputStream(); 394 395 bool get_file_globals = true; 396 397 // Be careful about the stack frame, if any summary formatter runs code, it might clear the StackFrameList 398 // for the thread. So hold onto a shared pointer to the frame so it stays alive. 399 400 VariableList *variable_list = frame->GetVariableList (get_file_globals); 401 402 VariableSP var_sp; 403 ValueObjectSP valobj_sp; 404 405 const char *name_cstr = NULL; 406 size_t idx; 407 408 SummaryFormatSP summary_format_sp; 409 if (!m_option_variable.summary.empty()) 410 DataVisualization::NamedSummaryFormats::GetSummaryFormat(ConstString(m_option_variable.summary.c_str()), summary_format_sp); 411 412 ValueObject::DumpValueObjectOptions options; 413 414 options.SetPointerDepth(m_varobj_options.ptr_depth) 415 .SetMaximumDepth(m_varobj_options.max_depth) 416 .SetShowTypes(m_varobj_options.show_types) 417 .SetShowLocation(m_varobj_options.show_location) 418 .SetUseObjectiveC(m_varobj_options.use_objc) 419 .SetUseDynamicType(m_varobj_options.use_dynamic) 420 .SetUseSyntheticValue((lldb::SyntheticValueType)m_varobj_options.use_synth) 421 .SetFlatOutput(m_varobj_options.flat_output) 422 .SetOmitSummaryDepth(m_varobj_options.no_summary_depth) 423 .SetIgnoreCap(m_varobj_options.ignore_cap); 424 425 if (m_varobj_options.be_raw) 426 options.SetRawDisplay(true); 427 428 if (variable_list) 429 { 430 // If watching a variable, there are certain restrictions to be followed. 431 if (m_option_watchpoint.watch_variable) 432 { 433 if (command.GetArgumentCount() != 1) { 434 result.GetErrorStream().Printf("error: specify exactly one variable when using the '-w' option\n"); 435 result.SetStatus(eReturnStatusFailed); 436 return false; 437 } else if (m_option_variable.use_regex) { 438 result.GetErrorStream().Printf("error: specify your variable name exactly (no regex) when using the '-w' option\n"); 439 result.SetStatus(eReturnStatusFailed); 440 return false; 441 } 442 443 // Things have checked out ok... 444 // m_option_watchpoint.watch_type specifies the type of watching. 445 } 446 447 const Format format = m_option_format.GetFormat(); 448 449 if (command.GetArgumentCount() > 0) 450 { 451 VariableList regex_var_list; 452 453 // If we have any args to the variable command, we will make 454 // variable objects from them... 455 for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != NULL; ++idx) 456 { 457 if (m_option_variable.use_regex) 458 { 459 const uint32_t regex_start_index = regex_var_list.GetSize(); 460 RegularExpression regex (name_cstr); 461 if (regex.Compile(name_cstr)) 462 { 463 size_t num_matches = 0; 464 const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex, 465 regex_var_list, 466 num_matches); 467 if (num_new_regex_vars > 0) 468 { 469 for (uint32_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize(); 470 regex_idx < end_index; 471 ++regex_idx) 472 { 473 var_sp = regex_var_list.GetVariableAtIndex (regex_idx); 474 if (var_sp) 475 { 476 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic); 477 if (valobj_sp) 478 { 479 if (format != eFormatDefault) 480 valobj_sp->SetFormat (format); 481 482 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 483 { 484 bool show_fullpaths = false; 485 bool show_module = true; 486 if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module)) 487 s.PutCString (": "); 488 } 489 if (summary_format_sp) 490 valobj_sp->SetCustomSummaryFormat(summary_format_sp); 491 ValueObject::DumpValueObject (result.GetOutputStream(), 492 valobj_sp.get(), 493 options); 494 } 495 } 496 } 497 } 498 else if (num_matches == 0) 499 { 500 result.GetErrorStream().Printf ("error: no variables matched the regular expression '%s'.\n", name_cstr); 501 } 502 } 503 else 504 { 505 char regex_error[1024]; 506 if (regex.GetErrorAsCString(regex_error, sizeof(regex_error))) 507 result.GetErrorStream().Printf ("error: %s\n", regex_error); 508 else 509 result.GetErrorStream().Printf ("error: unkown regex error when compiling '%s'\n", name_cstr); 510 } 511 } 512 else // No regex, either exact variable names or variable expressions. 513 { 514 Error error; 515 uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember; 516 lldb::VariableSP var_sp; 517 valobj_sp = frame->GetValueForVariableExpressionPath (name_cstr, 518 m_varobj_options.use_dynamic, 519 expr_path_options, 520 var_sp, 521 error); 522 if (valobj_sp) 523 { 524 if (format != eFormatDefault) 525 valobj_sp->SetFormat (format); 526 if (m_option_variable.show_decl && var_sp && var_sp->GetDeclaration ().GetFile()) 527 { 528 var_sp->GetDeclaration ().DumpStopContext (&s, false); 529 s.PutCString (": "); 530 } 531 if (summary_format_sp) 532 valobj_sp->SetCustomSummaryFormat(summary_format_sp); 533 534 Stream &output_stream = result.GetOutputStream(); 535 ValueObject::DumpValueObject (output_stream, 536 valobj_sp.get(), 537 valobj_sp->GetParent() ? name_cstr : NULL, 538 options); 539 // Process watchpoint if necessary. 540 if (m_option_watchpoint.watch_variable) 541 { 542 AddressType addr_type; 543 lldb::addr_t addr = 0; 544 size_t size = 0; 545 if (m_option_watchpoint.watch_size == 0) { 546 addr = valobj_sp->GetAddressOf(false, &addr_type); 547 if (addr_type == eAddressTypeLoad) { 548 // We're in business. 549 // Find out the size of this variable. 550 size = valobj_sp->GetByteSize(); 551 } 552 } else { 553 // The '-xsize'/'-x' option means to treat the value object as 554 // a pointer and to watch the pointee with the specified size. 555 addr = valobj_sp->GetValueAsUnsigned(0); 556 size = m_option_watchpoint.watch_size; 557 } 558 uint32_t watch_type = m_option_watchpoint.watch_type; 559 Watchpoint *wp = exe_ctx.GetTargetRef().CreateWatchpoint(addr, size, watch_type).get(); 560 if (wp) 561 { 562 if (var_sp && var_sp->GetDeclaration().GetFile()) 563 { 564 StreamString ss; 565 // True to show fullpath for declaration file. 566 var_sp->GetDeclaration().DumpStopContext(&ss, true); 567 wp->SetDeclInfo(ss.GetString()); 568 } 569 StreamString ss; 570 output_stream.Printf("Watchpoint created: "); 571 wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull); 572 output_stream.EOL(); 573 result.SetStatus(eReturnStatusSuccessFinishResult); 574 } 575 else 576 { 577 result.AppendErrorWithFormat("Watchpoint creation failed.\n"); 578 result.SetStatus(eReturnStatusFailed); 579 } 580 return (wp != NULL); 581 } 582 } 583 else 584 { 585 const char *error_cstr = error.AsCString(NULL); 586 if (error_cstr) 587 result.GetErrorStream().Printf("error: %s\n", error_cstr); 588 else 589 result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n", name_cstr); 590 } 591 } 592 } 593 } 594 else // No command arg specified. Use variable_list, instead. 595 { 596 const uint32_t num_variables = variable_list->GetSize(); 597 if (num_variables > 0) 598 { 599 for (uint32_t i=0; i<num_variables; i++) 600 { 601 var_sp = variable_list->GetVariableAtIndex(i); 602 bool dump_variable = true; 603 switch (var_sp->GetScope()) 604 { 605 case eValueTypeVariableGlobal: 606 dump_variable = m_option_variable.show_globals; 607 if (dump_variable && m_option_variable.show_scope) 608 s.PutCString("GLOBAL: "); 609 break; 610 611 case eValueTypeVariableStatic: 612 dump_variable = m_option_variable.show_globals; 613 if (dump_variable && m_option_variable.show_scope) 614 s.PutCString("STATIC: "); 615 break; 616 617 case eValueTypeVariableArgument: 618 dump_variable = m_option_variable.show_args; 619 if (dump_variable && m_option_variable.show_scope) 620 s.PutCString(" ARG: "); 621 break; 622 623 case eValueTypeVariableLocal: 624 dump_variable = m_option_variable.show_locals; 625 if (dump_variable && m_option_variable.show_scope) 626 s.PutCString(" LOCAL: "); 627 break; 628 629 default: 630 break; 631 } 632 633 if (dump_variable) 634 { 635 // Use the variable object code to make sure we are 636 // using the same APIs as the the public API will be 637 // using... 638 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, 639 m_varobj_options.use_dynamic); 640 if (valobj_sp) 641 { 642 if (format != eFormatDefault) 643 valobj_sp->SetFormat (format); 644 645 // When dumping all variables, don't print any variables 646 // that are not in scope to avoid extra unneeded output 647 if (valobj_sp->IsInScope ()) 648 { 649 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 650 { 651 var_sp->GetDeclaration ().DumpStopContext (&s, false); 652 s.PutCString (": "); 653 } 654 if (summary_format_sp) 655 valobj_sp->SetCustomSummaryFormat(summary_format_sp); 656 ValueObject::DumpValueObject (result.GetOutputStream(), 657 valobj_sp.get(), 658 name_cstr, 659 options); 660 } 661 } 662 } 663 } 664 } 665 } 666 result.SetStatus (eReturnStatusSuccessFinishResult); 667 } 668 669 if (m_interpreter.TruncationWarningNecessary()) 670 { 671 result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 672 m_cmd_name.c_str()); 673 m_interpreter.TruncationWarningGiven(); 674 } 675 676 return result.Succeeded(); 677 } 678protected: 679 680 OptionGroupOptions m_option_group; 681 OptionGroupVariable m_option_variable; 682 OptionGroupFormat m_option_format; 683 OptionGroupWatchpoint m_option_watchpoint; 684 OptionGroupValueObjectDisplay m_varobj_options; 685}; 686 687 688#pragma mark CommandObjectMultiwordFrame 689 690//------------------------------------------------------------------------- 691// CommandObjectMultiwordFrame 692//------------------------------------------------------------------------- 693 694CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter &interpreter) : 695 CommandObjectMultiword (interpreter, 696 "frame", 697 "A set of commands for operating on the current thread's frames.", 698 "frame <subcommand> [<subcommand-options>]") 699{ 700 LoadSubCommand ("info", CommandObjectSP (new CommandObjectFrameInfo (interpreter))); 701 LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter))); 702 LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter))); 703} 704 705CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame () 706{ 707} 708 709