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