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 // Be careful about the stack frame, if any summary formatter runs code, it might clear the StackFrameList 377 // for the thread. So hold onto a shared pointer to the frame so it stays alive. 378 379 VariableList *variable_list = frame->GetVariableList (m_option_variable.show_globals); 380 381 VariableSP var_sp; 382 ValueObjectSP valobj_sp; 383 384 const char *name_cstr = nullptr; 385 size_t idx; 386 387 TypeSummaryImplSP summary_format_sp; 388 if (!m_option_variable.summary.IsCurrentValueEmpty()) 389 DataVisualization::NamedSummaryFormats::GetSummaryFormat(ConstString(m_option_variable.summary.GetCurrentValue()), summary_format_sp); 390 else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 391 summary_format_sp.reset(new StringSummaryFormat(TypeSummaryImpl::Flags(),m_option_variable.summary_string.GetCurrentValue())); 392 393 DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(eLanguageRuntimeDescriptionDisplayVerbosityFull,eFormatDefault,summary_format_sp)); 394 395 const SymbolContext& sym_ctx = frame->GetSymbolContext(eSymbolContextFunction); 396 if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 397 m_option_variable.show_globals = true; 398 399 if (variable_list) 400 { 401 const Format format = m_option_format.GetFormat(); 402 options.SetFormat(format); 403 404 if (command.GetArgumentCount() > 0) 405 { 406 VariableList regex_var_list; 407 408 // If we have any args to the variable command, we will make 409 // variable objects from them... 410 for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != nullptr; ++idx) 411 { 412 if (m_option_variable.use_regex) 413 { 414 const size_t regex_start_index = regex_var_list.GetSize(); 415 RegularExpression regex (name_cstr); 416 if (regex.Compile(name_cstr)) 417 { 418 size_t num_matches = 0; 419 const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex, 420 regex_var_list, 421 num_matches); 422 if (num_new_regex_vars > 0) 423 { 424 for (size_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize(); 425 regex_idx < end_index; 426 ++regex_idx) 427 { 428 var_sp = regex_var_list.GetVariableAtIndex (regex_idx); 429 if (var_sp) 430 { 431 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic); 432 if (valobj_sp) 433 { 434 // if (format != eFormatDefault) 435 // valobj_sp->SetFormat (format); 436 437 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 438 { 439 bool show_fullpaths = false; 440 bool show_module = true; 441 if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module)) 442 s.PutCString (": "); 443 } 444 valobj_sp->Dump(result.GetOutputStream(),options); 445 } 446 } 447 } 448 } 449 else if (num_matches == 0) 450 { 451 result.GetErrorStream().Printf ("error: no variables matched the regular expression '%s'.\n", name_cstr); 452 } 453 } 454 else 455 { 456 char regex_error[1024]; 457 if (regex.GetErrorAsCString(regex_error, sizeof(regex_error))) 458 result.GetErrorStream().Printf ("error: %s\n", regex_error); 459 else 460 result.GetErrorStream().Printf ("error: unknown regex error when compiling '%s'\n", name_cstr); 461 } 462 } 463 else // No regex, either exact variable names or variable expressions. 464 { 465 Error error; 466 uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember | 467 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 468 StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 469 lldb::VariableSP var_sp; 470 valobj_sp = frame->GetValueForVariableExpressionPath (name_cstr, 471 m_varobj_options.use_dynamic, 472 expr_path_options, 473 var_sp, 474 error); 475 if (valobj_sp) 476 { 477 // if (format != eFormatDefault) 478 // valobj_sp->SetFormat (format); 479 if (m_option_variable.show_decl && var_sp && var_sp->GetDeclaration ().GetFile()) 480 { 481 var_sp->GetDeclaration ().DumpStopContext (&s, false); 482 s.PutCString (": "); 483 } 484 485 options.SetFormat(format); 486 options.SetVariableFormatDisplayLanguage(valobj_sp->GetPreferredDisplayLanguage()); 487 488 Stream &output_stream = result.GetOutputStream(); 489 options.SetRootValueObjectName(valobj_sp->GetParent() ? name_cstr : nullptr); 490 valobj_sp->Dump(output_stream,options); 491 } 492 else 493 { 494 const char *error_cstr = error.AsCString(nullptr); 495 if (error_cstr) 496 result.GetErrorStream().Printf("error: %s\n", error_cstr); 497 else 498 result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n", name_cstr); 499 } 500 } 501 } 502 } 503 else // No command arg specified. Use variable_list, instead. 504 { 505 const size_t num_variables = variable_list->GetSize(); 506 if (num_variables > 0) 507 { 508 for (size_t i=0; i<num_variables; i++) 509 { 510 var_sp = variable_list->GetVariableAtIndex(i); 511 bool dump_variable = true; 512 std::string scope_string; 513 switch (var_sp->GetScope()) 514 { 515 case eValueTypeVariableGlobal: 516 // Always dump globals since we only fetched them if 517 // m_option_variable.show_scope was true 518 if (dump_variable && m_option_variable.show_scope) 519 scope_string = "GLOBAL: "; 520 break; 521 522 case eValueTypeVariableStatic: 523 // Always dump globals since we only fetched them if 524 // m_option_variable.show_scope was true, or this is 525 // a static variable from a block in the current scope 526 if (dump_variable && m_option_variable.show_scope) 527 scope_string = "STATIC: "; 528 break; 529 530 case eValueTypeVariableArgument: 531 dump_variable = m_option_variable.show_args; 532 if (dump_variable && m_option_variable.show_scope) 533 scope_string = " ARG: "; 534 break; 535 536 case eValueTypeVariableLocal: 537 dump_variable = m_option_variable.show_locals; 538 if (dump_variable && m_option_variable.show_scope) 539 scope_string = " LOCAL: "; 540 break; 541 542 default: 543 break; 544 } 545 546 if (dump_variable) 547 { 548 // Use the variable object code to make sure we are 549 // using the same APIs as the public API will be 550 // using... 551 valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, 552 m_varobj_options.use_dynamic); 553 if (valobj_sp) 554 { 555 // if (format != eFormatDefault) 556 // valobj_sp->SetFormat (format); 557 558 // When dumping all variables, don't print any variables 559 // that are not in scope to avoid extra unneeded output 560 if (valobj_sp->IsInScope ()) 561 { 562 if (!valobj_sp->GetTargetSP()->GetDisplayRuntimeSupportValues() && 563 valobj_sp->IsRuntimeSupportValue()) 564 continue; 565 566 if (!scope_string.empty()) 567 s.PutCString(scope_string.c_str()); 568 569 if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile()) 570 { 571 var_sp->GetDeclaration ().DumpStopContext (&s, false); 572 s.PutCString (": "); 573 } 574 575 options.SetFormat(format); 576 options.SetVariableFormatDisplayLanguage(valobj_sp->GetPreferredDisplayLanguage()); 577 options.SetRootValueObjectName(name_cstr); 578 valobj_sp->Dump(result.GetOutputStream(),options); 579 } 580 } 581 } 582 } 583 } 584 } 585 result.SetStatus (eReturnStatusSuccessFinishResult); 586 } 587 588 if (m_interpreter.TruncationWarningNecessary()) 589 { 590 result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 591 m_cmd_name.c_str()); 592 m_interpreter.TruncationWarningGiven(); 593 } 594 595 return result.Succeeded(); 596 } 597 598 protected: 599 OptionGroupOptions m_option_group; 600 OptionGroupVariable m_option_variable; 601 OptionGroupFormat m_option_format; 602 OptionGroupValueObjectDisplay m_varobj_options; 603 }; 604 605 #pragma mark CommandObjectMultiwordFrame 606 607 //------------------------------------------------------------------------- 608 // CommandObjectMultiwordFrame 609 //------------------------------------------------------------------------- 610 611 CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter &interpreter) : 612 CommandObjectMultiword (interpreter, 613 "frame", 614 "A set of commands for operating on the current thread's frames.", 615 "frame <subcommand> [<subcommand-options>]") 616 { 617 LoadSubCommand ("info", CommandObjectSP (new CommandObjectFrameInfo (interpreter))); 618 LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter))); 619 LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter))); 620 } 621 622 CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 623