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 // C Includes 11 // C++ Includes 12 #include <string> 13 14 // Other libraries and framework includes 15 // Project includes 16 #include "CommandObjectFrame.h" 17 #include "lldb/Core/Debugger.h" 18 #include "lldb/Core/Module.h" 19 #include "lldb/Core/StreamFile.h" 20 #include "lldb/Core/StreamString.h" 21 #include "lldb/Core/Timer.h" 22 #include "lldb/Core/Value.h" 23 #include "lldb/Core/ValueObject.h" 24 #include "lldb/Core/ValueObjectVariable.h" 25 #include "lldb/DataFormatters/DataVisualization.h" 26 #include "lldb/DataFormatters/ValueObjectPrinter.h" 27 #include "lldb/Host/Host.h" 28 #include "lldb/Host/StringConvert.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/CompilerType.h" 37 #include "lldb/Symbol/ClangASTContext.h" 38 #include "lldb/Symbol/Function.h" 39 #include "lldb/Symbol/ObjectFile.h" 40 #include "lldb/Symbol/SymbolContext.h" 41 #include "lldb/Symbol/Type.h" 42 #include "lldb/Symbol/Variable.h" 43 #include "lldb/Symbol/VariableList.h" 44 #include "lldb/Target/Process.h" 45 #include "lldb/Target/StackFrame.h" 46 #include "lldb/Target/Thread.h" 47 #include "lldb/Target/Target.h" 48 49 using namespace lldb; 50 using namespace lldb_private; 51 52 #pragma mark CommandObjectFrameInfo 53 54 //------------------------------------------------------------------------- 55 // CommandObjectFrameInfo 56 //------------------------------------------------------------------------- 57 58 class CommandObjectFrameInfo : public CommandObjectParsed 59 { 60 public: 61 CommandObjectFrameInfo(CommandInterpreter &interpreter) 62 : CommandObjectParsed(interpreter, "frame info", 63 "List information about the current stack frame in the current thread.", "frame info", 64 eCommandRequiresFrame | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 65 eCommandProcessMustBePaused) 66 { 67 } 68 69 ~CommandObjectFrameInfo() override = default; 70 71 protected: 72 bool 73 DoExecute (Args& command, CommandReturnObject &result) override 74 { 75 m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat (&result.GetOutputStream()); 76 result.SetStatus (eReturnStatusSuccessFinishResult); 77 return result.Succeeded(); 78 } 79 }; 80 81 #pragma mark CommandObjectFrameSelect 82 83 //------------------------------------------------------------------------- 84 // CommandObjectFrameSelect 85 //------------------------------------------------------------------------- 86 87 class CommandObjectFrameSelect : public CommandObjectParsed 88 { 89 public: 90 class CommandOptions : public Options 91 { 92 public: 93 CommandOptions() : 94 Options() 95 { 96 OptionParsingStarting(nullptr); 97 } 98 99 ~CommandOptions() override = default; 100 101 Error 102 SetOptionValue(uint32_t option_idx, const char *option_arg, 103 ExecutionContext *execution_context) override 104 { 105 Error error; 106 bool success = false; 107 const int short_option = m_getopt_table[option_idx].val; 108 switch (short_option) 109 { 110 case 'r': 111 relative_frame_offset = StringConvert::ToSInt32 (option_arg, INT32_MIN, 0, &success); 112 if (!success) 113 error.SetErrorStringWithFormat ("invalid frame offset argument '%s'", option_arg); 114 break; 115 116 default: 117 error.SetErrorStringWithFormat ("invalid short option character '%c'", short_option); 118 break; 119 } 120 121 return error; 122 } 123 124 void 125 OptionParsingStarting(ExecutionContext *execution_context) override 126 { 127 relative_frame_offset = INT32_MIN; 128 } 129 130 const OptionDefinition* 131 GetDefinitions () override 132 { 133 return g_option_table; 134 } 135 136 // Options table: Required for subclasses of Options. 137 138 static OptionDefinition g_option_table[]; 139 int32_t relative_frame_offset; 140 }; 141 142 CommandObjectFrameSelect(CommandInterpreter &interpreter) 143 : CommandObjectParsed( 144 interpreter, "frame select", 145 "Select the current stack frame by index from within the current thread (see 'thread backtrace'.)", 146 nullptr, eCommandRequiresThread | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 147 eCommandProcessMustBePaused), 148 m_options() 149 { 150 CommandArgumentEntry arg; 151 CommandArgumentData index_arg; 152 153 // Define the first (and only) variant of this arg. 154 index_arg.arg_type = eArgTypeFrameIndex; 155 index_arg.arg_repetition = eArgRepeatOptional; 156 157 // There is only one variant this argument could be; put it into the argument entry. 158 arg.push_back (index_arg); 159 160 // Push the data for the first argument into the m_arguments vector. 161 m_arguments.push_back (arg); 162 } 163 164 ~CommandObjectFrameSelect() override = default; 165 166 Options * 167 GetOptions () override 168 { 169 return &m_options; 170 } 171 172 protected: 173 bool 174 DoExecute (Args& command, CommandReturnObject &result) override 175 { 176 // No need to check "thread" for validity as eCommandRequiresThread ensures it is valid 177 Thread *thread = m_exe_ctx.GetThreadPtr(); 178 179 uint32_t frame_idx = UINT32_MAX; 180 if (m_options.relative_frame_offset != INT32_MIN) 181 { 182 // The one and only argument is a signed relative frame index 183 frame_idx = thread->GetSelectedFrameIndex (); 184 if (frame_idx == UINT32_MAX) 185 frame_idx = 0; 186 187 if (m_options.relative_frame_offset < 0) 188 { 189 if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset) 190 frame_idx += m_options.relative_frame_offset; 191 else 192 { 193 if (frame_idx == 0) 194 { 195 //If you are already at the bottom of the stack, then just warn and don't reset the frame. 196 result.AppendError("Already at the bottom of the stack."); 197 result.SetStatus(eReturnStatusFailed); 198 return false; 199 } 200 else 201 frame_idx = 0; 202 } 203 } 204 else if (m_options.relative_frame_offset > 0) 205 { 206 // I don't want "up 20" where "20" takes you past the top of the stack to produce 207 // an error, but rather to just go to the top. So I have to count the stack here... 208 const uint32_t num_frames = thread->GetStackFrameCount(); 209 if (static_cast<int32_t>(num_frames - frame_idx) > m_options.relative_frame_offset) 210 frame_idx += m_options.relative_frame_offset; 211 else 212 { 213 if (frame_idx == num_frames - 1) 214 { 215 //If we are already at the top of the stack, just warn and don't reset the frame. 216 result.AppendError("Already at the top of the stack."); 217 result.SetStatus(eReturnStatusFailed); 218 return false; 219 } 220 else 221 frame_idx = num_frames - 1; 222 } 223 } 224 } 225 else 226 { 227 if (command.GetArgumentCount() == 1) 228 { 229 const char *frame_idx_cstr = command.GetArgumentAtIndex(0); 230 bool success = false; 231 frame_idx = StringConvert::ToUInt32 (frame_idx_cstr, UINT32_MAX, 0, &success); 232 if (!success) 233 { 234 result.AppendErrorWithFormat("invalid frame index argument '%s'.", frame_idx_cstr); 235 result.SetStatus (eReturnStatusFailed); 236 return false; 237 } 238 } 239 else if (command.GetArgumentCount() == 0) 240 { 241 frame_idx = thread->GetSelectedFrameIndex (); 242 if (frame_idx == UINT32_MAX) 243 { 244 frame_idx = 0; 245 } 246 } 247 else 248 { 249 result.AppendErrorWithFormat ("too many arguments; expected frame-index, saw '%s'.\n", 250 command.GetArgumentAtIndex(0)); 251 m_options.GenerateOptionUsage(result.GetErrorStream(), this, 252 GetCommandInterpreter() 253 .GetDebugger() 254 .GetTerminalWidth()); 255 return false; 256 } 257 } 258 259 bool success = thread->SetSelectedFrameByIndexNoisily (frame_idx, result.GetOutputStream()); 260 if (success) 261 { 262 m_exe_ctx.SetFrameSP(thread->GetSelectedFrame ()); 263 result.SetStatus (eReturnStatusSuccessFinishResult); 264 } 265 else 266 { 267 result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx); 268 result.SetStatus (eReturnStatusFailed); 269 } 270 271 return result.Succeeded(); 272 } 273 274 protected: 275 CommandOptions m_options; 276 }; 277 278 OptionDefinition 279 CommandObjectFrameSelect::CommandOptions::g_option_table[] = 280 { 281 { LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "A relative frame index offset from the current frame index."}, 282 { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } 283 }; 284 285 #pragma mark CommandObjectFrameVariable 286 //---------------------------------------------------------------------- 287 // List images with associated information 288 //---------------------------------------------------------------------- 289 class CommandObjectFrameVariable : public CommandObjectParsed 290 { 291 public: 292 CommandObjectFrameVariable(CommandInterpreter &interpreter) 293 : CommandObjectParsed( 294 interpreter, "frame variable", "Show variables for the current stack frame. Defaults to all " 295 "arguments and local variables in scope. Names of argument, " 296 "local, file static and file global variables can be specified. " 297 "Children of aggregate variables can be specified such as " 298 "'var->child.x'.", 299 nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 300 eCommandProcessMustBePaused | eCommandRequiresProcess), 301 m_option_group(), 302 m_option_variable(true), // Include the frame specific options by passing "true" 303 m_option_format(eFormatDefault), 304 m_varobj_options() 305 { 306 CommandArgumentEntry arg; 307 CommandArgumentData var_name_arg; 308 309 // Define the first (and only) variant of this arg. 310 var_name_arg.arg_type = eArgTypeVarName; 311 var_name_arg.arg_repetition = eArgRepeatStar; 312 313 // There is only one variant this argument could be; put it into the argument entry. 314 arg.push_back (var_name_arg); 315 316 // Push the data for the first argument into the m_arguments vector. 317 m_arguments.push_back (arg); 318 319 m_option_group.Append (&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 320 m_option_group.Append (&m_option_format, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1); 321 m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 322 m_option_group.Finalize(); 323 } 324 325 ~CommandObjectFrameVariable() override = default; 326 327 Options * 328 GetOptions () override 329 { 330 return &m_option_group; 331 } 332 333 int 334 HandleArgumentCompletion (Args &input, 335 int &cursor_index, 336 int &cursor_char_position, 337 OptionElementVector &opt_element_vector, 338 int match_start_point, 339 int max_return_elements, 340 bool &word_complete, 341 StringList &matches) override 342 { 343 // Arguments are the standard source file completer. 344 std::string completion_str (input.GetArgumentAtIndex(cursor_index)); 345 completion_str.erase (cursor_char_position); 346 347 CommandCompletions::InvokeCommonCompletionCallbacks(GetCommandInterpreter(), 348 CommandCompletions::eVariablePathCompletion, 349 completion_str.c_str(), 350 match_start_point, 351 max_return_elements, 352 nullptr, 353 word_complete, 354 matches); 355 return matches.GetSize(); 356 } 357 358 protected: 359 bool 360 DoExecute (Args& command, CommandReturnObject &result) override 361 { 362 // No need to check "frame" for validity as eCommandRequiresFrame ensures it is valid 363 StackFrame *frame = m_exe_ctx.GetFramePtr(); 364 365 Stream &s = result.GetOutputStream(); 366 367 // Be careful about the stack frame, if any summary formatter runs code, it might clear the StackFrameList 368 // for the thread. So hold onto a shared pointer to the frame so it stays alive. 369 370 VariableList *variable_list = frame->GetVariableList (m_option_variable.show_globals); 371 372 VariableSP var_sp; 373 ValueObjectSP valobj_sp; 374 375 const char *name_cstr = nullptr; 376 size_t idx; 377 378 TypeSummaryImplSP summary_format_sp; 379 if (!m_option_variable.summary.IsCurrentValueEmpty()) 380 DataVisualization::NamedSummaryFormats::GetSummaryFormat(ConstString(m_option_variable.summary.GetCurrentValue()), summary_format_sp); 381 else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 382 summary_format_sp.reset(new StringSummaryFormat(TypeSummaryImpl::Flags(),m_option_variable.summary_string.GetCurrentValue())); 383 384 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(eLanguageRuntimeDescriptionDisplayVerbosityFull,eFormatDefault,summary_format_sp)); 385 386 const SymbolContext& sym_ctx = frame->GetSymbolContext(eSymbolContextFunction); 387 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 388 m_option_variable.show_globals = true; 389 390 if (variable_list) 391 { 392 const Format format = m_option_format.GetFormat(); 393 options.SetFormat(format); 394 395 if (command.GetArgumentCount() > 0) 396 { 397 VariableList regex_var_list; 398 399 // If we have any args to the variable command, we will make 400 // variable objects from them... 401 for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != nullptr; ++idx) 402 { 403 if (m_option_variable.use_regex) 404 { 405 const size_t regex_start_index = regex_var_list.GetSize(); 406 RegularExpression regex (name_cstr); 407 if (regex.Compile(name_cstr)) 408 { 409 size_t num_matches = 0; 410 const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex, 411 regex_var_list, 412 num_matches); 413 if (num_new_regex_vars > 0) 414 { 415 for (size_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize(); 416 regex_idx < end_index; 417 ++regex_idx) 418 { 419 var_sp = regex_var_list.GetVariableAtIndex (regex_idx); 420 if (var_sp) 421 { 422 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic); 423 if (valobj_sp) 424 { 425 // if (format != eFormatDefault) 426 // valobj_sp->SetFormat (format); 427 428 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 429 { 430 bool show_fullpaths = false; 431 bool show_module = true; 432 if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module)) 433 s.PutCString (": "); 434 } 435 valobj_sp->Dump(result.GetOutputStream(),options); 436 } 437 } 438 } 439 } 440 else if (num_matches == 0) 441 { 442 result.GetErrorStream().Printf ("error: no variables matched the regular expression '%s'.\n", name_cstr); 443 } 444 } 445 else 446 { 447 char regex_error[1024]; 448 if (regex.GetErrorAsCString(regex_error, sizeof(regex_error))) 449 result.GetErrorStream().Printf ("error: %s\n", regex_error); 450 else 451 result.GetErrorStream().Printf ("error: unknown regex error when compiling '%s'\n", name_cstr); 452 } 453 } 454 else // No regex, either exact variable names or variable expressions. 455 { 456 Error error; 457 uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember | 458 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 459 StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 460 lldb::VariableSP var_sp; 461 valobj_sp = frame->GetValueForVariableExpressionPath (name_cstr, 462 m_varobj_options.use_dynamic, 463 expr_path_options, 464 var_sp, 465 error); 466 if (valobj_sp) 467 { 468 // if (format != eFormatDefault) 469 // valobj_sp->SetFormat (format); 470 if (m_option_variable.show_decl && var_sp && var_sp->GetDeclaration ().GetFile()) 471 { 472 var_sp->GetDeclaration ().DumpStopContext (&s, false); 473 s.PutCString (": "); 474 } 475 476 options.SetFormat(format); 477 options.SetVariableFormatDisplayLanguage(valobj_sp->GetPreferredDisplayLanguage()); 478 479 Stream &output_stream = result.GetOutputStream(); 480 options.SetRootValueObjectName(valobj_sp->GetParent() ? name_cstr : nullptr); 481 valobj_sp->Dump(output_stream,options); 482 } 483 else 484 { 485 const char *error_cstr = error.AsCString(nullptr); 486 if (error_cstr) 487 result.GetErrorStream().Printf("error: %s\n", error_cstr); 488 else 489 result.GetErrorStream().Printf( 490 "error: unable to find any variable expression path that matches '%s'.\n", 491 name_cstr); 492 } 493 } 494 } 495 } 496 else // No command arg specified. Use variable_list, instead. 497 { 498 const size_t num_variables = variable_list->GetSize(); 499 if (num_variables > 0) 500 { 501 for (size_t i=0; i<num_variables; i++) 502 { 503 var_sp = variable_list->GetVariableAtIndex(i); 504 bool dump_variable = true; 505 std::string scope_string; 506 switch (var_sp->GetScope()) 507 { 508 case eValueTypeVariableGlobal: 509 // Always dump globals since we only fetched them if 510 // m_option_variable.show_scope was true 511 if (dump_variable && m_option_variable.show_scope) 512 scope_string = "GLOBAL: "; 513 break; 514 515 case eValueTypeVariableStatic: 516 // Always dump globals since we only fetched them if 517 // m_option_variable.show_scope was true, or this is 518 // a static variable from a block in the current scope 519 if (dump_variable && m_option_variable.show_scope) 520 scope_string = "STATIC: "; 521 break; 522 523 case eValueTypeVariableArgument: 524 dump_variable = m_option_variable.show_args; 525 if (dump_variable && m_option_variable.show_scope) 526 scope_string = " ARG: "; 527 break; 528 529 case eValueTypeVariableLocal: 530 dump_variable = m_option_variable.show_locals; 531 if (dump_variable && m_option_variable.show_scope) 532 scope_string = " LOCAL: "; 533 break; 534 535 case eValueTypeVariableThreadLocal: 536 if (dump_variable && m_option_variable.show_scope) 537 scope_string = "THREAD: "; 538 break; 539 default: 540 break; 541 } 542 543 if (dump_variable) 544 { 545 // Use the variable object code to make sure we are 546 // using the same APIs as the public API will be 547 // using... 548 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, 549 m_varobj_options.use_dynamic); 550 if (valobj_sp) 551 { 552 // if (format != eFormatDefault) 553 // valobj_sp->SetFormat (format); 554 555 // When dumping all variables, don't print any variables 556 // that are not in scope to avoid extra unneeded output 557 if (valobj_sp->IsInScope ()) 558 { 559 if (!valobj_sp->GetTargetSP()->GetDisplayRuntimeSupportValues() && 560 valobj_sp->IsRuntimeSupportValue()) 561 continue; 562 563 if (!scope_string.empty()) 564 s.PutCString(scope_string.c_str()); 565 566 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 567 { 568 var_sp->GetDeclaration ().DumpStopContext (&s, false); 569 s.PutCString (": "); 570 } 571 572 options.SetFormat(format); 573 options.SetVariableFormatDisplayLanguage(valobj_sp->GetPreferredDisplayLanguage()); 574 options.SetRootValueObjectName(name_cstr); 575 valobj_sp->Dump(result.GetOutputStream(),options); 576 } 577 } 578 } 579 } 580 } 581 } 582 result.SetStatus (eReturnStatusSuccessFinishResult); 583 } 584 585 if (m_interpreter.TruncationWarningNecessary()) 586 { 587 result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 588 m_cmd_name.c_str()); 589 m_interpreter.TruncationWarningGiven(); 590 } 591 592 return result.Succeeded(); 593 } 594 595 protected: 596 OptionGroupOptions m_option_group; 597 OptionGroupVariable m_option_variable; 598 OptionGroupFormat m_option_format; 599 OptionGroupValueObjectDisplay m_varobj_options; 600 }; 601 602 #pragma mark CommandObjectMultiwordFrame 603 604 //------------------------------------------------------------------------- 605 // CommandObjectMultiwordFrame 606 //------------------------------------------------------------------------- 607 608 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(CommandInterpreter &interpreter) 609 : CommandObjectMultiword(interpreter, "frame", 610 "Commands for selecting and examing the current thread's stack frames.", 611 "frame <subcommand> [<subcommand-options>]") 612 { 613 LoadSubCommand ("info", CommandObjectSP (new CommandObjectFrameInfo (interpreter))); 614 LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter))); 615 LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter))); 616 } 617 618 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 619