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