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/WatchpointLocation.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 if (command.GetArgumentCount() == 0) 252 { 253 frame_idx = thread->GetSelectedFrameIndex (); 254 if (frame_idx == UINT32_MAX) 255 frame_idx = 0; 256 } 257 else 258 { 259 result.AppendError ("invalid arguments.\n"); 260 m_options.GenerateOptionUsage (result.GetErrorStream(), this); 261 } 262 } 263 264 if (frame_idx < num_frames) 265 { 266 thread->SetSelectedFrameByIndex (frame_idx); 267 exe_ctx.SetFrameSP(thread->GetSelectedFrame ()); 268 StackFrame *frame = exe_ctx.GetFramePtr(); 269 if (frame) 270 { 271 bool already_shown = false; 272 SymbolContext frame_sc(frame->GetSymbolContext(eSymbolContextLineEntry)); 273 if (m_interpreter.GetDebugger().GetUseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0) 274 { 275 already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line); 276 } 277 278 bool show_frame_info = true; 279 bool show_source = !already_shown; 280 uint32_t source_lines_before = 3; 281 uint32_t source_lines_after = 3; 282 if (frame->GetStatus (result.GetOutputStream(), 283 show_frame_info, 284 show_source, 285 source_lines_before, 286 source_lines_after)) 287 { 288 result.SetStatus (eReturnStatusSuccessFinishResult); 289 return result.Succeeded(); 290 } 291 } 292 } 293 result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx); 294 } 295 else 296 { 297 result.AppendError ("no current thread"); 298 } 299 result.SetStatus (eReturnStatusFailed); 300 return false; 301 } 302 protected: 303 304 CommandOptions m_options; 305 }; 306 307 OptionDefinition 308 CommandObjectFrameSelect::CommandOptions::g_option_table[] = 309 { 310 { LLDB_OPT_SET_1, false, "relative", 'r', required_argument, NULL, 0, eArgTypeOffset, "A relative frame index offset from the current frame index."}, 311 { 0, false, NULL, 0, 0, NULL, NULL, eArgTypeNone, NULL } 312 }; 313 314 #pragma mark CommandObjectFrameVariable 315 //---------------------------------------------------------------------- 316 // List images with associated information 317 //---------------------------------------------------------------------- 318 class CommandObjectFrameVariable : public CommandObject 319 { 320 public: 321 322 CommandObjectFrameVariable (CommandInterpreter &interpreter) : 323 CommandObject (interpreter, 324 "frame variable", 325 "Show frame variables. All argument and local variables " 326 "that are in scope will be shown when no arguments are given. " 327 "If any arguments are specified, they can be names of " 328 "argument, local, file static and file global variables. " 329 "Children of aggregate variables can be specified such as " 330 "'var->child.x'. " 331 "You can choose to watch a variable with the '-w' option. " 332 "Note that hardware resources for watching are often limited.", 333 NULL, 334 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused), 335 m_option_group (interpreter), 336 m_option_variable(true), // Include the frame specific options by passing "true" 337 m_option_watchpoint(), 338 m_varobj_options() 339 { 340 CommandArgumentEntry arg; 341 CommandArgumentData var_name_arg; 342 343 // Define the first (and only) variant of this arg. 344 var_name_arg.arg_type = eArgTypeVarName; 345 var_name_arg.arg_repetition = eArgRepeatStar; 346 347 // There is only one variant this argument could be; put it into the argument entry. 348 arg.push_back (var_name_arg); 349 350 // Push the data for the first argument into the m_arguments vector. 351 m_arguments.push_back (arg); 352 353 m_option_group.Append (&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 354 m_option_group.Append (&m_option_watchpoint, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 355 m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 356 m_option_group.Finalize(); 357 } 358 359 virtual 360 ~CommandObjectFrameVariable () 361 { 362 } 363 364 virtual 365 Options * 366 GetOptions () 367 { 368 return &m_option_group; 369 } 370 371 372 virtual bool 373 Execute 374 ( 375 Args& command, 376 CommandReturnObject &result 377 ) 378 { 379 ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); 380 StackFrame *frame = exe_ctx.GetFramePtr(); 381 if (frame == NULL) 382 { 383 result.AppendError ("you must be stopped in a valid stack frame to view frame variables."); 384 result.SetStatus (eReturnStatusFailed); 385 return false; 386 } 387 388 Stream &s = result.GetOutputStream(); 389 390 bool get_file_globals = true; 391 392 // Be careful about the stack frame, if any summary formatter runs code, it might clear the StackFrameList 393 // for the thread. So hold onto a shared pointer to the frame so it stays alive. 394 395 VariableList *variable_list = frame->GetVariableList (get_file_globals); 396 397 VariableSP var_sp; 398 ValueObjectSP valobj_sp; 399 400 const char *name_cstr = NULL; 401 size_t idx; 402 403 SummaryFormatSP summary_format_sp; 404 if (!m_option_variable.summary.empty()) 405 DataVisualization::NamedSummaryFormats::GetSummaryFormat(ConstString(m_option_variable.summary.c_str()), summary_format_sp); 406 407 ValueObject::DumpValueObjectOptions options; 408 409 options.SetPointerDepth(m_varobj_options.ptr_depth) 410 .SetMaximumDepth(m_varobj_options.max_depth) 411 .SetShowTypes(m_varobj_options.show_types) 412 .SetShowLocation(m_varobj_options.show_location) 413 .SetUseObjectiveC(m_varobj_options.use_objc) 414 .SetUseDynamicType(m_varobj_options.use_dynamic) 415 .SetUseSyntheticValue((lldb::SyntheticValueType)m_varobj_options.use_synth) 416 .SetFlatOutput(m_varobj_options.flat_output) 417 .SetOmitSummaryDepth(m_varobj_options.no_summary_depth) 418 .SetIgnoreCap(m_varobj_options.ignore_cap); 419 420 if (m_varobj_options.be_raw) 421 options.SetRawDisplay(true); 422 423 if (variable_list) 424 { 425 // If watching a variable, there are certain restrictions to be followed. 426 if (m_option_watchpoint.watch_variable) 427 { 428 if (command.GetArgumentCount() != 1) { 429 result.GetErrorStream().Printf("error: specify exactly one variable when using the '-w' option\n"); 430 result.SetStatus(eReturnStatusFailed); 431 return false; 432 } else if (m_option_variable.use_regex) { 433 result.GetErrorStream().Printf("error: specify your variable name exactly (no regex) when using the '-w' option\n"); 434 result.SetStatus(eReturnStatusFailed); 435 return false; 436 } 437 438 // Things have checked out ok... 439 // m_option_watchpoint.watch_mode specifies the mode for watching. 440 } 441 if (command.GetArgumentCount() > 0) 442 { 443 VariableList regex_var_list; 444 445 // If we have any args to the variable command, we will make 446 // variable objects from them... 447 for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != NULL; ++idx) 448 { 449 if (m_option_variable.use_regex) 450 { 451 const uint32_t regex_start_index = regex_var_list.GetSize(); 452 RegularExpression regex (name_cstr); 453 if (regex.Compile(name_cstr)) 454 { 455 size_t num_matches = 0; 456 const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex, 457 regex_var_list, 458 num_matches); 459 if (num_new_regex_vars > 0) 460 { 461 for (uint32_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize(); 462 regex_idx < end_index; 463 ++regex_idx) 464 { 465 var_sp = regex_var_list.GetVariableAtIndex (regex_idx); 466 if (var_sp) 467 { 468 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic); 469 if (valobj_sp) 470 { 471 if (m_option_variable.format != eFormatDefault) 472 valobj_sp->SetFormat (m_option_variable.format); 473 474 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 475 { 476 bool show_fullpaths = false; 477 bool show_module = true; 478 if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module)) 479 s.PutCString (": "); 480 } 481 if (summary_format_sp) 482 valobj_sp->SetCustomSummaryFormat(summary_format_sp); 483 ValueObject::DumpValueObject (result.GetOutputStream(), 484 valobj_sp.get(), 485 options); 486 } 487 } 488 } 489 } 490 else if (num_matches == 0) 491 { 492 result.GetErrorStream().Printf ("error: no variables matched the regular expression '%s'.\n", name_cstr); 493 } 494 } 495 else 496 { 497 char regex_error[1024]; 498 if (regex.GetErrorAsCString(regex_error, sizeof(regex_error))) 499 result.GetErrorStream().Printf ("error: %s\n", regex_error); 500 else 501 result.GetErrorStream().Printf ("error: unkown regex error when compiling '%s'\n", name_cstr); 502 } 503 } 504 else // No regex, either exact variable names or variable expressions. 505 { 506 Error error; 507 uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember; 508 lldb::VariableSP var_sp; 509 valobj_sp = frame->GetValueForVariableExpressionPath (name_cstr, 510 m_varobj_options.use_dynamic, 511 expr_path_options, 512 var_sp, 513 error); 514 if (valobj_sp) 515 { 516 if (m_option_variable.format != eFormatDefault) 517 valobj_sp->SetFormat (m_option_variable.format); 518 if (m_option_variable.show_decl && var_sp && var_sp->GetDeclaration ().GetFile()) 519 { 520 var_sp->GetDeclaration ().DumpStopContext (&s, false); 521 s.PutCString (": "); 522 } 523 if (summary_format_sp) 524 valobj_sp->SetCustomSummaryFormat(summary_format_sp); 525 526 Stream &output_stream = result.GetOutputStream(); 527 ValueObject::DumpValueObject (output_stream, 528 valobj_sp.get(), 529 valobj_sp->GetParent() ? name_cstr : NULL, 530 options); 531 // Process watchpoint if necessary. 532 if (m_option_watchpoint.watch_variable) 533 { 534 AddressType addr_type; 535 lldb::addr_t addr = valobj_sp->GetAddressOf(false, &addr_type); 536 size_t size = 0; 537 if (addr_type == eAddressTypeLoad) { 538 // We're in business. 539 // Find out the size of this variable. 540 size = valobj_sp->GetByteSize(); 541 } 542 uint32_t watch_type = m_option_watchpoint.watch_type; 543 WatchpointLocation *wp_loc = exe_ctx.GetTargetRef().CreateWatchpointLocation(addr, size, watch_type).get(); 544 if (wp_loc) 545 { 546 if (var_sp && var_sp->GetDeclaration().GetFile()) 547 { 548 StreamString ss; 549 // True to show fullpath for declaration file. 550 var_sp->GetDeclaration().DumpStopContext(&ss, true); 551 wp_loc->SetDeclInfo(ss.GetString()); 552 } 553 StreamString ss; 554 output_stream.Printf("Watchpoint created: "); 555 wp_loc->GetDescription(&output_stream, lldb::eDescriptionLevelFull); 556 output_stream.EOL(); 557 result.SetStatus(eReturnStatusSuccessFinishResult); 558 } 559 else 560 { 561 result.AppendErrorWithFormat("Watchpoint creation failed.\n"); 562 result.SetStatus(eReturnStatusFailed); 563 } 564 return (wp_loc != NULL); 565 } 566 } 567 else 568 { 569 const char *error_cstr = error.AsCString(NULL); 570 if (error_cstr) 571 result.GetErrorStream().Printf("error: %s\n", error_cstr); 572 else 573 result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n", name_cstr); 574 } 575 } 576 } 577 } 578 else // No command arg specified. Use variable_list, instead. 579 { 580 const uint32_t num_variables = variable_list->GetSize(); 581 if (num_variables > 0) 582 { 583 for (uint32_t i=0; i<num_variables; i++) 584 { 585 var_sp = variable_list->GetVariableAtIndex(i); 586 bool dump_variable = true; 587 switch (var_sp->GetScope()) 588 { 589 case eValueTypeVariableGlobal: 590 dump_variable = m_option_variable.show_globals; 591 if (dump_variable && m_option_variable.show_scope) 592 s.PutCString("GLOBAL: "); 593 break; 594 595 case eValueTypeVariableStatic: 596 dump_variable = m_option_variable.show_globals; 597 if (dump_variable && m_option_variable.show_scope) 598 s.PutCString("STATIC: "); 599 break; 600 601 case eValueTypeVariableArgument: 602 dump_variable = m_option_variable.show_args; 603 if (dump_variable && m_option_variable.show_scope) 604 s.PutCString(" ARG: "); 605 break; 606 607 case eValueTypeVariableLocal: 608 dump_variable = m_option_variable.show_locals; 609 if (dump_variable && m_option_variable.show_scope) 610 s.PutCString(" LOCAL: "); 611 break; 612 613 default: 614 break; 615 } 616 617 if (dump_variable) 618 { 619 // Use the variable object code to make sure we are 620 // using the same APIs as the the public API will be 621 // using... 622 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, 623 m_varobj_options.use_dynamic); 624 if (valobj_sp) 625 { 626 if (m_option_variable.format != eFormatDefault) 627 valobj_sp->SetFormat (m_option_variable.format); 628 629 // When dumping all variables, don't print any variables 630 // that are not in scope to avoid extra unneeded output 631 if (valobj_sp->IsInScope ()) 632 { 633 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 634 { 635 var_sp->GetDeclaration ().DumpStopContext (&s, false); 636 s.PutCString (": "); 637 } 638 if (summary_format_sp) 639 valobj_sp->SetCustomSummaryFormat(summary_format_sp); 640 ValueObject::DumpValueObject (result.GetOutputStream(), 641 valobj_sp.get(), 642 name_cstr, 643 options); 644 } 645 } 646 } 647 } 648 } 649 } 650 result.SetStatus (eReturnStatusSuccessFinishResult); 651 } 652 653 if (m_interpreter.TruncationWarningNecessary()) 654 { 655 result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 656 m_cmd_name.c_str()); 657 m_interpreter.TruncationWarningGiven(); 658 } 659 660 return result.Succeeded(); 661 } 662 protected: 663 664 OptionGroupOptions m_option_group; 665 OptionGroupVariable m_option_variable; 666 OptionGroupWatchpoint m_option_watchpoint; 667 OptionGroupValueObjectDisplay m_varobj_options; 668 }; 669 670 671 #pragma mark CommandObjectMultiwordFrame 672 673 //------------------------------------------------------------------------- 674 // CommandObjectMultiwordFrame 675 //------------------------------------------------------------------------- 676 677 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter &interpreter) : 678 CommandObjectMultiword (interpreter, 679 "frame", 680 "A set of commands for operating on the current thread's frames.", 681 "frame <subcommand> [<subcommand-options>]") 682 { 683 LoadSubCommand ("info", CommandObjectSP (new CommandObjectFrameInfo (interpreter))); 684 LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter))); 685 LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter))); 686 } 687 688 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame () 689 { 690 } 691 692