CommandObjectFrame.cpp revision d891f9b872103235cfd2ed452c6f14a4394d9b3a
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 "lldb/lldb-python.h" 11 12#include "CommandObjectFrame.h" 13 14// C Includes 15// C++ Includes 16#include <string> 17// Other libraries and framework includes 18// Project includes 19#include "lldb/Core/DataVisualization.h" 20#include "lldb/Core/Debugger.h" 21#include "lldb/Core/Module.h" 22#include "lldb/Core/StreamFile.h" 23#include "lldb/Core/StreamString.h" 24#include "lldb/Core/Timer.h" 25#include "lldb/Core/Value.h" 26#include "lldb/Core/ValueObject.h" 27#include "lldb/Core/ValueObjectVariable.h" 28#include "lldb/Host/Host.h" 29#include "lldb/Interpreter/Args.h" 30#include "lldb/Interpreter/CommandInterpreter.h" 31#include "lldb/Interpreter/CommandReturnObject.h" 32#include "lldb/Interpreter/Options.h" 33#include "lldb/Interpreter/OptionGroupFormat.h" 34#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" 35#include "lldb/Interpreter/OptionGroupVariable.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 CommandObjectParsed 58{ 59public: 60 61 CommandObjectFrameInfo (CommandInterpreter &interpreter) : 62 CommandObjectParsed (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 74protected: 75 bool 76 DoExecute (Args& command, 77 CommandReturnObject &result) 78 { 79 ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); 80 StackFrame *frame = exe_ctx.GetFramePtr(); 81 if (frame) 82 { 83 frame->DumpUsingSettingsFormat (&result.GetOutputStream()); 84 result.SetStatus (eReturnStatusSuccessFinishResult); 85 } 86 else 87 { 88 result.AppendError ("no current frame"); 89 result.SetStatus (eReturnStatusFailed); 90 } 91 return result.Succeeded(); 92 } 93}; 94 95#pragma mark CommandObjectFrameSelect 96 97//------------------------------------------------------------------------- 98// CommandObjectFrameSelect 99//------------------------------------------------------------------------- 100 101class CommandObjectFrameSelect : public CommandObjectParsed 102{ 103public: 104 105 class CommandOptions : public Options 106 { 107 public: 108 109 CommandOptions (CommandInterpreter &interpreter) : 110 Options(interpreter) 111 { 112 OptionParsingStarting (); 113 } 114 115 virtual 116 ~CommandOptions () 117 { 118 } 119 120 virtual Error 121 SetOptionValue (uint32_t option_idx, const char *option_arg) 122 { 123 Error error; 124 bool success = false; 125 const int short_option = m_getopt_table[option_idx].val; 126 switch (short_option) 127 { 128 case 'r': 129 relative_frame_offset = Args::StringToSInt32 (option_arg, INT32_MIN, 0, &success); 130 if (!success) 131 error.SetErrorStringWithFormat ("invalid frame offset argument '%s'", option_arg); 132 break; 133 134 default: 135 error.SetErrorStringWithFormat ("invalid short option character '%c'", short_option); 136 break; 137 } 138 139 return error; 140 } 141 142 void 143 OptionParsingStarting () 144 { 145 relative_frame_offset = INT32_MIN; 146 } 147 148 const OptionDefinition* 149 GetDefinitions () 150 { 151 return g_option_table; 152 } 153 154 // Options table: Required for subclasses of Options. 155 156 static OptionDefinition g_option_table[]; 157 int32_t relative_frame_offset; 158 }; 159 160 CommandObjectFrameSelect (CommandInterpreter &interpreter) : 161 CommandObjectParsed (interpreter, 162 "frame select", 163 "Select a frame by index from within the current thread and make it the current frame.", 164 NULL, 165 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused), 166 m_options (interpreter) 167 { 168 CommandArgumentEntry arg; 169 CommandArgumentData index_arg; 170 171 // Define the first (and only) variant of this arg. 172 index_arg.arg_type = eArgTypeFrameIndex; 173 index_arg.arg_repetition = eArgRepeatOptional; 174 175 // There is only one variant this argument could be; put it into the argument entry. 176 arg.push_back (index_arg); 177 178 // Push the data for the first argument into the m_arguments vector. 179 m_arguments.push_back (arg); 180 } 181 182 ~CommandObjectFrameSelect () 183 { 184 } 185 186 virtual 187 Options * 188 GetOptions () 189 { 190 return &m_options; 191 } 192 193 194protected: 195 bool 196 DoExecute (Args& command, 197 CommandReturnObject &result) 198 { 199 ExecutionContext exe_ctx (m_interpreter.GetExecutionContext()); 200 Thread *thread = exe_ctx.GetThreadPtr(); 201 if (thread) 202 { 203 uint32_t frame_idx = UINT32_MAX; 204 if (m_options.relative_frame_offset != INT32_MIN) 205 { 206 // The one and only argument is a signed relative frame index 207 frame_idx = thread->GetSelectedFrameIndex (); 208 if (frame_idx == UINT32_MAX) 209 frame_idx = 0; 210 211 if (m_options.relative_frame_offset < 0) 212 { 213 if (frame_idx >= -m_options.relative_frame_offset) 214 frame_idx += m_options.relative_frame_offset; 215 else 216 { 217 if (frame_idx == 0) 218 { 219 //If you are already at the bottom of the stack, then just warn and don't reset the frame. 220 result.AppendError("Already at the bottom of the stack"); 221 result.SetStatus(eReturnStatusFailed); 222 return false; 223 } 224 else 225 frame_idx = 0; 226 } 227 } 228 else if (m_options.relative_frame_offset > 0) 229 { 230 // I don't want "up 20" where "20" takes you past the top of the stack to produce 231 // an error, but rather to just go to the top. So I have to count the stack here... 232 const uint32_t num_frames = thread->GetStackFrameCount(); 233 if (num_frames - frame_idx > m_options.relative_frame_offset) 234 frame_idx += m_options.relative_frame_offset; 235 else 236 { 237 if (frame_idx == num_frames - 1) 238 { 239 //If we are already at the top of the stack, just warn and don't reset the frame. 240 result.AppendError("Already at the top of the stack"); 241 result.SetStatus(eReturnStatusFailed); 242 return false; 243 } 244 else 245 frame_idx = num_frames - 1; 246 } 247 } 248 } 249 else 250 { 251 if (command.GetArgumentCount() == 1) 252 { 253 const char *frame_idx_cstr = command.GetArgumentAtIndex(0); 254 frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0); 255 } 256 else if (command.GetArgumentCount() == 0) 257 { 258 frame_idx = thread->GetSelectedFrameIndex (); 259 if (frame_idx == UINT32_MAX) 260 { 261 frame_idx = 0; 262 } 263 } 264 else 265 { 266 result.AppendError ("invalid arguments.\n"); 267 m_options.GenerateOptionUsage (result.GetErrorStream(), this); 268 } 269 } 270 271 const bool broadcast = true; 272 bool success = thread->SetSelectedFrameByIndex (frame_idx, broadcast); 273 if (success) 274 { 275 exe_ctx.SetFrameSP(thread->GetSelectedFrame ()); 276 StackFrame *frame = exe_ctx.GetFramePtr(); 277 if (frame) 278 { 279 bool already_shown = false; 280 SymbolContext frame_sc(frame->GetSymbolContext(eSymbolContextLineEntry)); 281 if (m_interpreter.GetDebugger().GetUseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0) 282 { 283 already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line); 284 } 285 286 bool show_frame_info = true; 287 bool show_source = !already_shown; 288 if (frame->GetStatus (result.GetOutputStream(), show_frame_info, show_source)) 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 } 304protected: 305 306 CommandOptions m_options; 307}; 308 309OptionDefinition 310CommandObjectFrameSelect::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, 0, eArgTypeNone, NULL } 314}; 315 316#pragma mark CommandObjectFrameVariable 317//---------------------------------------------------------------------- 318// List images with associated information 319//---------------------------------------------------------------------- 320class CommandObjectFrameVariable : public CommandObjectParsed 321{ 322public: 323 324 CommandObjectFrameVariable (CommandInterpreter &interpreter) : 325 CommandObjectParsed (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 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_format (eFormatDefault), 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_format, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, 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 371protected: 372 virtual bool 373 DoExecute (Args& command, CommandReturnObject &result) 374 { 375 ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); 376 StackFrame *frame = exe_ctx.GetFramePtr(); 377 if (frame == NULL) 378 { 379 result.AppendError ("you must be stopped in a valid stack frame to view frame variables."); 380 result.SetStatus (eReturnStatusFailed); 381 return false; 382 } 383 384 Stream &s = result.GetOutputStream(); 385 386 bool get_file_globals = true; 387 388 // Be careful about the stack frame, if any summary formatter runs code, it might clear the StackFrameList 389 // for the thread. So hold onto a shared pointer to the frame so it stays alive. 390 391 VariableList *variable_list = frame->GetVariableList (get_file_globals); 392 393 VariableSP var_sp; 394 ValueObjectSP valobj_sp; 395 396 const char *name_cstr = NULL; 397 size_t idx; 398 399 TypeSummaryImplSP summary_format_sp; 400 if (!m_option_variable.summary.IsCurrentValueEmpty()) 401 DataVisualization::NamedSummaryFormats::GetSummaryFormat(ConstString(m_option_variable.summary.GetCurrentValue()), summary_format_sp); 402 else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 403 summary_format_sp.reset(new StringSummaryFormat(TypeSummaryImpl::Flags(),m_option_variable.summary_string.GetCurrentValue())); 404 405 ValueObject::DumpValueObjectOptions options; 406 407 options.SetMaximumPointerDepth(m_varobj_options.ptr_depth) 408 .SetMaximumDepth(m_varobj_options.max_depth) 409 .SetShowTypes(m_varobj_options.show_types) 410 .SetShowLocation(m_varobj_options.show_location) 411 .SetUseObjectiveC(m_varobj_options.use_objc) 412 .SetUseDynamicType(m_varobj_options.use_dynamic) 413 .SetUseSyntheticValue(m_varobj_options.use_synth) 414 .SetFlatOutput(m_varobj_options.flat_output) 415 .SetOmitSummaryDepth(m_varobj_options.no_summary_depth) 416 .SetIgnoreCap(m_varobj_options.ignore_cap) 417 .SetSummary(summary_format_sp); 418 419 if (m_varobj_options.be_raw) 420 options.SetRawDisplay(true); 421 422 if (variable_list) 423 { 424 const Format format = m_option_format.GetFormat(); 425 options.SetFormat(format); 426 427 if (command.GetArgumentCount() > 0) 428 { 429 VariableList regex_var_list; 430 431 // If we have any args to the variable command, we will make 432 // variable objects from them... 433 for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != NULL; ++idx) 434 { 435 if (m_option_variable.use_regex) 436 { 437 const uint32_t regex_start_index = regex_var_list.GetSize(); 438 RegularExpression regex (name_cstr); 439 if (regex.Compile(name_cstr)) 440 { 441 size_t num_matches = 0; 442 const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex, 443 regex_var_list, 444 num_matches); 445 if (num_new_regex_vars > 0) 446 { 447 for (uint32_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize(); 448 regex_idx < end_index; 449 ++regex_idx) 450 { 451 var_sp = regex_var_list.GetVariableAtIndex (regex_idx); 452 if (var_sp) 453 { 454 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic); 455 if (valobj_sp) 456 { 457// if (format != eFormatDefault) 458// valobj_sp->SetFormat (format); 459 460 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 461 { 462 bool show_fullpaths = false; 463 bool show_module = true; 464 if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module)) 465 s.PutCString (": "); 466 } 467 ValueObject::DumpValueObject (result.GetOutputStream(), 468 valobj_sp.get(), 469 options); 470 } 471 } 472 } 473 } 474 else if (num_matches == 0) 475 { 476 result.GetErrorStream().Printf ("error: no variables matched the regular expression '%s'.\n", name_cstr); 477 } 478 } 479 else 480 { 481 char regex_error[1024]; 482 if (regex.GetErrorAsCString(regex_error, sizeof(regex_error))) 483 result.GetErrorStream().Printf ("error: %s\n", regex_error); 484 else 485 result.GetErrorStream().Printf ("error: unkown regex error when compiling '%s'\n", name_cstr); 486 } 487 } 488 else // No regex, either exact variable names or variable expressions. 489 { 490 Error error; 491 uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember | 492 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess; 493 lldb::VariableSP var_sp; 494 valobj_sp = frame->GetValueForVariableExpressionPath (name_cstr, 495 m_varobj_options.use_dynamic, 496 expr_path_options, 497 var_sp, 498 error); 499 if (valobj_sp) 500 { 501// if (format != eFormatDefault) 502// valobj_sp->SetFormat (format); 503 if (m_option_variable.show_decl && var_sp && var_sp->GetDeclaration ().GetFile()) 504 { 505 var_sp->GetDeclaration ().DumpStopContext (&s, false); 506 s.PutCString (": "); 507 } 508 509 options.SetFormat(format); 510 511 Stream &output_stream = result.GetOutputStream(); 512 options.SetRootValueObjectName(valobj_sp->GetParent() ? name_cstr : NULL); 513 ValueObject::DumpValueObject (output_stream, 514 valobj_sp.get(), 515 options); 516 } 517 else 518 { 519 const char *error_cstr = error.AsCString(NULL); 520 if (error_cstr) 521 result.GetErrorStream().Printf("error: %s\n", error_cstr); 522 else 523 result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n", name_cstr); 524 } 525 } 526 } 527 } 528 else // No command arg specified. Use variable_list, instead. 529 { 530 const uint32_t num_variables = variable_list->GetSize(); 531 if (num_variables > 0) 532 { 533 for (uint32_t i=0; i<num_variables; i++) 534 { 535 var_sp = variable_list->GetVariableAtIndex(i); 536 bool dump_variable = true; 537 switch (var_sp->GetScope()) 538 { 539 case eValueTypeVariableGlobal: 540 dump_variable = m_option_variable.show_globals; 541 if (dump_variable && m_option_variable.show_scope) 542 s.PutCString("GLOBAL: "); 543 break; 544 545 case eValueTypeVariableStatic: 546 dump_variable = m_option_variable.show_globals; 547 if (dump_variable && m_option_variable.show_scope) 548 s.PutCString("STATIC: "); 549 break; 550 551 case eValueTypeVariableArgument: 552 dump_variable = m_option_variable.show_args; 553 if (dump_variable && m_option_variable.show_scope) 554 s.PutCString(" ARG: "); 555 break; 556 557 case eValueTypeVariableLocal: 558 dump_variable = m_option_variable.show_locals; 559 if (dump_variable && m_option_variable.show_scope) 560 s.PutCString(" LOCAL: "); 561 break; 562 563 default: 564 break; 565 } 566 567 if (dump_variable) 568 { 569 // Use the variable object code to make sure we are 570 // using the same APIs as the the public API will be 571 // using... 572 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, 573 m_varobj_options.use_dynamic); 574 if (valobj_sp) 575 { 576// if (format != eFormatDefault) 577// valobj_sp->SetFormat (format); 578 579 // When dumping all variables, don't print any variables 580 // that are not in scope to avoid extra unneeded output 581 if (valobj_sp->IsInScope ()) 582 { 583 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 584 { 585 var_sp->GetDeclaration ().DumpStopContext (&s, false); 586 s.PutCString (": "); 587 } 588 589 options.SetFormat(format); 590 options.SetRootValueObjectName(name_cstr); 591 ValueObject::DumpValueObject (result.GetOutputStream(), 592 valobj_sp.get(), 593 options); 594 } 595 } 596 } 597 } 598 } 599 } 600 result.SetStatus (eReturnStatusSuccessFinishResult); 601 } 602 603 if (m_interpreter.TruncationWarningNecessary()) 604 { 605 result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 606 m_cmd_name.c_str()); 607 m_interpreter.TruncationWarningGiven(); 608 } 609 610 return result.Succeeded(); 611 } 612protected: 613 614 OptionGroupOptions m_option_group; 615 OptionGroupVariable m_option_variable; 616 OptionGroupFormat m_option_format; 617 OptionGroupValueObjectDisplay m_varobj_options; 618}; 619 620 621#pragma mark CommandObjectMultiwordFrame 622 623//------------------------------------------------------------------------- 624// CommandObjectMultiwordFrame 625//------------------------------------------------------------------------- 626 627CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter &interpreter) : 628 CommandObjectMultiword (interpreter, 629 "frame", 630 "A set of commands for operating on the current thread's frames.", 631 "frame <subcommand> [<subcommand-options>]") 632{ 633 LoadSubCommand ("info", CommandObjectSP (new CommandObjectFrameInfo (interpreter))); 634 LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter))); 635 LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter))); 636} 637 638CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame () 639{ 640} 641 642