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