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