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 // clang-format off 282 {LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "A relative frame index offset from the current frame index."}, 283 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 284 // clang-format on 285 }; 286 287 #pragma mark CommandObjectFrameVariable 288 //---------------------------------------------------------------------- 289 // List images with associated information 290 //---------------------------------------------------------------------- 291 class CommandObjectFrameVariable : public CommandObjectParsed 292 { 293 public: 294 CommandObjectFrameVariable(CommandInterpreter &interpreter) 295 : CommandObjectParsed( 296 interpreter, "frame variable", "Show variables for the current stack frame. Defaults to all " 297 "arguments and local variables in scope. Names of argument, " 298 "local, file static and file global variables can be specified. " 299 "Children of aggregate variables can be specified such as " 300 "'var->child.x'.", 301 nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | 302 eCommandProcessMustBePaused | eCommandRequiresProcess), 303 m_option_group(), 304 m_option_variable(true), // Include the frame specific options by passing "true" 305 m_option_format(eFormatDefault), 306 m_varobj_options() 307 { 308 CommandArgumentEntry arg; 309 CommandArgumentData var_name_arg; 310 311 // Define the first (and only) variant of this arg. 312 var_name_arg.arg_type = eArgTypeVarName; 313 var_name_arg.arg_repetition = eArgRepeatStar; 314 315 // There is only one variant this argument could be; put it into the argument entry. 316 arg.push_back (var_name_arg); 317 318 // Push the data for the first argument into the m_arguments vector. 319 m_arguments.push_back (arg); 320 321 m_option_group.Append (&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 322 m_option_group.Append (&m_option_format, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1); 323 m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 324 m_option_group.Finalize(); 325 } 326 327 ~CommandObjectFrameVariable() override = default; 328 329 Options * 330 GetOptions () override 331 { 332 return &m_option_group; 333 } 334 335 int 336 HandleArgumentCompletion (Args &input, 337 int &cursor_index, 338 int &cursor_char_position, 339 OptionElementVector &opt_element_vector, 340 int match_start_point, 341 int max_return_elements, 342 bool &word_complete, 343 StringList &matches) override 344 { 345 // Arguments are the standard source file completer. 346 std::string completion_str (input.GetArgumentAtIndex(cursor_index)); 347 completion_str.erase (cursor_char_position); 348 349 CommandCompletions::InvokeCommonCompletionCallbacks(GetCommandInterpreter(), 350 CommandCompletions::eVariablePathCompletion, 351 completion_str.c_str(), 352 match_start_point, 353 max_return_elements, 354 nullptr, 355 word_complete, 356 matches); 357 return matches.GetSize(); 358 } 359 360 protected: 361 bool 362 DoExecute (Args& command, CommandReturnObject &result) override 363 { 364 // No need to check "frame" for validity as eCommandRequiresFrame ensures it is valid 365 StackFrame *frame = m_exe_ctx.GetFramePtr(); 366 367 Stream &s = result.GetOutputStream(); 368 369 // Be careful about the stack frame, if any summary formatter runs code, it might clear the StackFrameList 370 // for the thread. So hold onto a shared pointer to the frame so it stays alive. 371 372 VariableList *variable_list = frame->GetVariableList (m_option_variable.show_globals); 373 374 VariableSP var_sp; 375 ValueObjectSP valobj_sp; 376 377 const char *name_cstr = nullptr; 378 size_t idx; 379 380 TypeSummaryImplSP summary_format_sp; 381 if (!m_option_variable.summary.IsCurrentValueEmpty()) 382 DataVisualization::NamedSummaryFormats::GetSummaryFormat(ConstString(m_option_variable.summary.GetCurrentValue()), summary_format_sp); 383 else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 384 summary_format_sp.reset(new StringSummaryFormat(TypeSummaryImpl::Flags(),m_option_variable.summary_string.GetCurrentValue())); 385 386 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(eLanguageRuntimeDescriptionDisplayVerbosityFull,eFormatDefault,summary_format_sp)); 387 388 const SymbolContext& sym_ctx = frame->GetSymbolContext(eSymbolContextFunction); 389 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 390 m_option_variable.show_globals = true; 391 392 if (variable_list) 393 { 394 const Format format = m_option_format.GetFormat(); 395 options.SetFormat(format); 396 397 if (command.GetArgumentCount() > 0) 398 { 399 VariableList regex_var_list; 400 401 // If we have any args to the variable command, we will make 402 // variable objects from them... 403 for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != nullptr; ++idx) 404 { 405 if (m_option_variable.use_regex) 406 { 407 const size_t regex_start_index = regex_var_list.GetSize(); 408 RegularExpression regex (name_cstr); 409 if (regex.Compile(name_cstr)) 410 { 411 size_t num_matches = 0; 412 const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex, 413 regex_var_list, 414 num_matches); 415 if (num_new_regex_vars > 0) 416 { 417 for (size_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize(); 418 regex_idx < end_index; 419 ++regex_idx) 420 { 421 var_sp = regex_var_list.GetVariableAtIndex (regex_idx); 422 if (var_sp) 423 { 424 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic); 425 if (valobj_sp) 426 { 427 // if (format != eFormatDefault) 428 // valobj_sp->SetFormat (format); 429 430 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 431 { 432 bool show_fullpaths = false; 433 bool show_module = true; 434 if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module)) 435 s.PutCString (": "); 436 } 437 valobj_sp->Dump(result.GetOutputStream(),options); 438 } 439 } 440 } 441 } 442 else if (num_matches == 0) 443 { 444 result.GetErrorStream().Printf ("error: no variables matched the regular expression '%s'.\n", name_cstr); 445 } 446 } 447 else 448 { 449 char regex_error[1024]; 450 if (regex.GetErrorAsCString(regex_error, sizeof(regex_error))) 451 result.GetErrorStream().Printf ("error: %s\n", regex_error); 452 else 453 result.GetErrorStream().Printf ("error: unknown regex error when compiling '%s'\n", name_cstr); 454 } 455 } 456 else // No regex, either exact variable names or variable expressions. 457 { 458 Error error; 459 uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember | 460 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 461 StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 462 lldb::VariableSP var_sp; 463 valobj_sp = frame->GetValueForVariableExpressionPath (name_cstr, 464 m_varobj_options.use_dynamic, 465 expr_path_options, 466 var_sp, 467 error); 468 if (valobj_sp) 469 { 470 // if (format != eFormatDefault) 471 // valobj_sp->SetFormat (format); 472 if (m_option_variable.show_decl && var_sp && var_sp->GetDeclaration ().GetFile()) 473 { 474 var_sp->GetDeclaration ().DumpStopContext (&s, false); 475 s.PutCString (": "); 476 } 477 478 options.SetFormat(format); 479 options.SetVariableFormatDisplayLanguage(valobj_sp->GetPreferredDisplayLanguage()); 480 481 Stream &output_stream = result.GetOutputStream(); 482 options.SetRootValueObjectName(valobj_sp->GetParent() ? name_cstr : nullptr); 483 valobj_sp->Dump(output_stream,options); 484 } 485 else 486 { 487 const char *error_cstr = error.AsCString(nullptr); 488 if (error_cstr) 489 result.GetErrorStream().Printf("error: %s\n", error_cstr); 490 else 491 result.GetErrorStream().Printf( 492 "error: unable to find any variable expression path that matches '%s'.\n", 493 name_cstr); 494 } 495 } 496 } 497 } 498 else // No command arg specified. Use variable_list, instead. 499 { 500 const size_t num_variables = variable_list->GetSize(); 501 if (num_variables > 0) 502 { 503 for (size_t i=0; i<num_variables; i++) 504 { 505 var_sp = variable_list->GetVariableAtIndex(i); 506 bool dump_variable = true; 507 std::string scope_string; 508 switch (var_sp->GetScope()) 509 { 510 case eValueTypeVariableGlobal: 511 // Always dump globals since we only fetched them if 512 // m_option_variable.show_scope was true 513 if (dump_variable && m_option_variable.show_scope) 514 scope_string = "GLOBAL: "; 515 break; 516 517 case eValueTypeVariableStatic: 518 // Always dump globals since we only fetched them if 519 // m_option_variable.show_scope was true, or this is 520 // a static variable from a block in the current scope 521 if (dump_variable && m_option_variable.show_scope) 522 scope_string = "STATIC: "; 523 break; 524 525 case eValueTypeVariableArgument: 526 dump_variable = m_option_variable.show_args; 527 if (dump_variable && m_option_variable.show_scope) 528 scope_string = " ARG: "; 529 break; 530 531 case eValueTypeVariableLocal: 532 dump_variable = m_option_variable.show_locals; 533 if (dump_variable && m_option_variable.show_scope) 534 scope_string = " LOCAL: "; 535 break; 536 537 case eValueTypeVariableThreadLocal: 538 if (dump_variable && m_option_variable.show_scope) 539 scope_string = "THREAD: "; 540 break; 541 default: 542 break; 543 } 544 545 if (dump_variable) 546 { 547 // Use the variable object code to make sure we are 548 // using the same APIs as the public API will be 549 // using... 550 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, 551 m_varobj_options.use_dynamic); 552 if (valobj_sp) 553 { 554 // if (format != eFormatDefault) 555 // valobj_sp->SetFormat (format); 556 557 // When dumping all variables, don't print any variables 558 // that are not in scope to avoid extra unneeded output 559 if (valobj_sp->IsInScope ()) 560 { 561 if (!valobj_sp->GetTargetSP()->GetDisplayRuntimeSupportValues() && 562 valobj_sp->IsRuntimeSupportValue()) 563 continue; 564 565 if (!scope_string.empty()) 566 s.PutCString(scope_string.c_str()); 567 568 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 569 { 570 var_sp->GetDeclaration ().DumpStopContext (&s, false); 571 s.PutCString (": "); 572 } 573 574 options.SetFormat(format); 575 options.SetVariableFormatDisplayLanguage(valobj_sp->GetPreferredDisplayLanguage()); 576 options.SetRootValueObjectName(name_cstr); 577 valobj_sp->Dump(result.GetOutputStream(),options); 578 } 579 } 580 } 581 } 582 } 583 } 584 result.SetStatus (eReturnStatusSuccessFinishResult); 585 } 586 587 if (m_interpreter.TruncationWarningNecessary()) 588 { 589 result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 590 m_cmd_name.c_str()); 591 m_interpreter.TruncationWarningGiven(); 592 } 593 594 return result.Succeeded(); 595 } 596 597 protected: 598 OptionGroupOptions m_option_group; 599 OptionGroupVariable m_option_variable; 600 OptionGroupFormat m_option_format; 601 OptionGroupValueObjectDisplay m_varobj_options; 602 }; 603 604 #pragma mark CommandObjectMultiwordFrame 605 606 //------------------------------------------------------------------------- 607 // CommandObjectMultiwordFrame 608 //------------------------------------------------------------------------- 609 610 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(CommandInterpreter &interpreter) 611 : CommandObjectMultiword(interpreter, "frame", 612 "Commands for selecting and examing the current thread's stack frames.", 613 "frame <subcommand> [<subcommand-options>]") 614 { 615 LoadSubCommand ("info", CommandObjectSP (new CommandObjectFrameInfo (interpreter))); 616 LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter))); 617 LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter))); 618 } 619 620 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 621