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