130fdc8d8SChris Lattner //===-- CommandObjectFrame.cpp ----------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 330fdc8d8SChris Lattner // The LLVM Compiler Infrastructure 430fdc8d8SChris Lattner // 530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source 630fdc8d8SChris Lattner // License. See LICENSE.TXT for details. 730fdc8d8SChris Lattner // 830fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 930fdc8d8SChris Lattner 1030fdc8d8SChris Lattner // C Includes 1130fdc8d8SChris Lattner // C++ Includes 12de6bd243SJohnny Chen #include <string> 13c8ecc2a9SEugene Zelenko 1430fdc8d8SChris Lattner // Other libraries and framework includes 1530fdc8d8SChris Lattner // Project includes 16c8ecc2a9SEugene Zelenko #include "CommandObjectFrame.h" 1730fdc8d8SChris Lattner #include "lldb/Core/Debugger.h" 186d56d2ceSJim Ingham #include "lldb/Core/Module.h" 196d56d2ceSJim Ingham #include "lldb/Core/StreamFile.h" 206d56d2ceSJim Ingham #include "lldb/Core/Value.h" 216d56d2ceSJim Ingham #include "lldb/Core/ValueObject.h" 226d56d2ceSJim Ingham #include "lldb/Core/ValueObjectVariable.h" 235548cb50SEnrico Granata #include "lldb/DataFormatters/DataVisualization.h" 244d93b8cdSEnrico Granata #include "lldb/DataFormatters/ValueObjectPrinter.h" 257fb56d0aSGreg Clayton #include "lldb/Host/Host.h" 263eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h" 27*41ae8e74SKuba Mracek #include "lldb/Host/StringConvert.h" 2830fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h" 2930fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h" 301deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h" 312837b766SJim Ingham #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" 32715c2365SGreg Clayton #include "lldb/Interpreter/OptionGroupVariable.h" 33b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h" 346d56d2ceSJim Ingham #include "lldb/Symbol/ClangASTContext.h" 35b9c1b51eSKate Stone #include "lldb/Symbol/CompilerType.h" 366754e04fSEnrico Granata #include "lldb/Symbol/Function.h" 376d56d2ceSJim Ingham #include "lldb/Symbol/ObjectFile.h" 386d56d2ceSJim Ingham #include "lldb/Symbol/SymbolContext.h" 396d56d2ceSJim Ingham #include "lldb/Symbol/Type.h" 406d56d2ceSJim Ingham #include "lldb/Symbol/Variable.h" 416d56d2ceSJim Ingham #include "lldb/Symbol/VariableList.h" 4230fdc8d8SChris Lattner #include "lldb/Target/Process.h" 43b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h" 44*41ae8e74SKuba Mracek #include "lldb/Target/StackFrameRecognizer.h" 454740a734SSean Callanan #include "lldb/Target/StopInfo.h" 466d56d2ceSJim Ingham #include "lldb/Target/Target.h" 47b9c1b51eSKate Stone #include "lldb/Target/Thread.h" 48145d95c9SPavel Labath #include "lldb/Utility/Args.h" 494740a734SSean Callanan #include "lldb/Utility/LLDBAssert.h" 50bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h" 5138d0632eSPavel Labath #include "lldb/Utility/Timer.h" 5230fdc8d8SChris Lattner 5330fdc8d8SChris Lattner using namespace lldb; 5430fdc8d8SChris Lattner using namespace lldb_private; 5530fdc8d8SChris Lattner 564740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose 574740a734SSean Callanan 584740a734SSean Callanan //------------------------------------------------------------------------- 594740a734SSean Callanan // CommandObjectFrameInfo 604740a734SSean Callanan //------------------------------------------------------------------------- 614740a734SSean Callanan 624740a734SSean Callanan //------------------------------------------------------------------------- 634740a734SSean Callanan // CommandObjectFrameDiagnose 644740a734SSean Callanan //------------------------------------------------------------------------- 654740a734SSean Callanan 668fe53c49STatyana Krasnukha static constexpr OptionDefinition g_frame_diag_options[] = { 671f0f5b5bSZachary Turner // clang-format off 688fe53c49STatyana Krasnukha { LLDB_OPT_SET_1, false, "register", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeRegisterName, "A register to diagnose." }, 698fe53c49STatyana Krasnukha { LLDB_OPT_SET_1, false, "address", 'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddress, "An address to diagnose." }, 708fe53c49STatyana Krasnukha { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset, "An optional offset. Requires --register." } 711f0f5b5bSZachary Turner // clang-format on 721f0f5b5bSZachary Turner }; 731f0f5b5bSZachary Turner 74b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed { 754740a734SSean Callanan public: 76b9c1b51eSKate Stone class CommandOptions : public Options { 774740a734SSean Callanan public: 78b9c1b51eSKate Stone CommandOptions() : Options() { OptionParsingStarting(nullptr); } 794740a734SSean Callanan 804740a734SSean Callanan ~CommandOptions() override = default; 814740a734SSean Callanan 8297206d57SZachary Turner Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 83b9c1b51eSKate Stone ExecutionContext *execution_context) override { 8497206d57SZachary Turner Status error; 854740a734SSean Callanan const int short_option = m_getopt_table[option_idx].val; 86b9c1b51eSKate Stone switch (short_option) { 874740a734SSean Callanan case 'r': 884740a734SSean Callanan reg = ConstString(option_arg); 894740a734SSean Callanan break; 904740a734SSean Callanan 91b9c1b51eSKate Stone case 'a': { 92fe11483bSZachary Turner address.emplace(); 93fe11483bSZachary Turner if (option_arg.getAsInteger(0, *address)) { 944740a734SSean Callanan address.reset(); 95b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid address argument '%s'", 96fe11483bSZachary Turner option_arg.str().c_str()); 974740a734SSean Callanan } 98b9c1b51eSKate Stone } break; 994740a734SSean Callanan 100b9c1b51eSKate Stone case 'o': { 101fe11483bSZachary Turner offset.emplace(); 102fe11483bSZachary Turner if (option_arg.getAsInteger(0, *offset)) { 1034740a734SSean Callanan offset.reset(); 104b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid offset argument '%s'", 105fe11483bSZachary Turner option_arg.str().c_str()); 1064740a734SSean Callanan } 107b9c1b51eSKate Stone } break; 1084740a734SSean Callanan 1094740a734SSean Callanan default: 110b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid short option character '%c'", 111b9c1b51eSKate Stone short_option); 1124740a734SSean Callanan break; 1134740a734SSean Callanan } 1144740a734SSean Callanan 1154740a734SSean Callanan return error; 1164740a734SSean Callanan } 1174740a734SSean Callanan 118b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 1194740a734SSean Callanan address.reset(); 1204740a734SSean Callanan reg.reset(); 1214740a734SSean Callanan offset.reset(); 1224740a734SSean Callanan } 1234740a734SSean Callanan 1241f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 12570602439SZachary Turner return llvm::makeArrayRef(g_frame_diag_options); 1261f0f5b5bSZachary Turner } 1274740a734SSean Callanan 1284740a734SSean Callanan // Options. 1294740a734SSean Callanan llvm::Optional<lldb::addr_t> address; 1304740a734SSean Callanan llvm::Optional<ConstString> reg; 1314740a734SSean Callanan llvm::Optional<int64_t> offset; 1324740a734SSean Callanan }; 1334740a734SSean Callanan 1344740a734SSean Callanan CommandObjectFrameDiagnose(CommandInterpreter &interpreter) 1354740a734SSean Callanan : CommandObjectParsed(interpreter, "frame diagnose", 136b9c1b51eSKate Stone "Try to determine what path path the current stop " 137b9c1b51eSKate Stone "location used to get to a register or address", 138b9c1b51eSKate Stone nullptr, 139b9c1b51eSKate Stone eCommandRequiresThread | eCommandTryTargetAPILock | 140b9c1b51eSKate Stone eCommandProcessMustBeLaunched | 1414740a734SSean Callanan eCommandProcessMustBePaused), 142b9c1b51eSKate Stone m_options() { 1434740a734SSean Callanan CommandArgumentEntry arg; 1444740a734SSean Callanan CommandArgumentData index_arg; 1454740a734SSean Callanan 1464740a734SSean Callanan // Define the first (and only) variant of this arg. 1474740a734SSean Callanan index_arg.arg_type = eArgTypeFrameIndex; 1484740a734SSean Callanan index_arg.arg_repetition = eArgRepeatOptional; 1494740a734SSean Callanan 150b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 151b9c1b51eSKate Stone // argument entry. 1524740a734SSean Callanan arg.push_back(index_arg); 1534740a734SSean Callanan 1544740a734SSean Callanan // Push the data for the first argument into the m_arguments vector. 1554740a734SSean Callanan m_arguments.push_back(arg); 1564740a734SSean Callanan } 1574740a734SSean Callanan 1584740a734SSean Callanan ~CommandObjectFrameDiagnose() override = default; 1594740a734SSean Callanan 160b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 1614740a734SSean Callanan 1624740a734SSean Callanan protected: 163b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 1644740a734SSean Callanan Thread *thread = m_exe_ctx.GetThreadPtr(); 1654740a734SSean Callanan StackFrameSP frame_sp = thread->GetSelectedFrame(); 1664740a734SSean Callanan 1674740a734SSean Callanan ValueObjectSP valobj_sp; 1684740a734SSean Callanan 169b9c1b51eSKate Stone if (m_options.address.hasValue()) { 170b9c1b51eSKate Stone if (m_options.reg.hasValue() || m_options.offset.hasValue()) { 171b9c1b51eSKate Stone result.AppendError( 172b9c1b51eSKate Stone "`frame diagnose --address` is incompatible with other arguments."); 1734740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1744740a734SSean Callanan return false; 1754740a734SSean Callanan } 1764740a734SSean Callanan valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue()); 177b9c1b51eSKate Stone } else if (m_options.reg.hasValue()) { 178b9c1b51eSKate Stone valobj_sp = frame_sp->GuessValueForRegisterAndOffset( 179b9c1b51eSKate Stone m_options.reg.getValue(), m_options.offset.getValueOr(0)); 180b9c1b51eSKate Stone } else { 1814740a734SSean Callanan StopInfoSP stop_info_sp = thread->GetStopInfo(); 182b9c1b51eSKate Stone if (!stop_info_sp) { 1834740a734SSean Callanan result.AppendError("No arguments provided, and no stop info."); 1844740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1854740a734SSean Callanan return false; 1864740a734SSean Callanan } 1874740a734SSean Callanan 1884740a734SSean Callanan valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp); 1894740a734SSean Callanan } 1904740a734SSean Callanan 191b9c1b51eSKate Stone if (!valobj_sp) { 1924740a734SSean Callanan result.AppendError("No diagnosis available."); 1934740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1944740a734SSean Callanan return false; 1954740a734SSean Callanan } 1964740a734SSean Callanan 1974740a734SSean Callanan 1983bc714b2SZachary Turner DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp]( 1993bc714b2SZachary Turner ConstString type, ConstString var, const DumpValueObjectOptions &opts, 2003bc714b2SZachary Turner Stream &stream) -> bool { 201b9c1b51eSKate Stone const ValueObject::GetExpressionPathFormat format = ValueObject:: 202b9c1b51eSKate Stone GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers; 2035d1f711aSPavel Labath const bool qualify_cxx_base_classes = false; 2044740a734SSean Callanan valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format); 2054740a734SSean Callanan stream.PutCString(" ="); 2064740a734SSean Callanan return true; 2074740a734SSean Callanan }; 2084740a734SSean Callanan 2094740a734SSean Callanan DumpValueObjectOptions options; 2104740a734SSean Callanan options.SetDeclPrintingHelper(helper); 211b9c1b51eSKate Stone ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), 212b9c1b51eSKate Stone options); 2134740a734SSean Callanan printer.PrintValueObject(); 2144740a734SSean Callanan 2154740a734SSean Callanan return true; 2164740a734SSean Callanan } 2174740a734SSean Callanan 2184740a734SSean Callanan protected: 2194740a734SSean Callanan CommandOptions m_options; 2204740a734SSean Callanan }; 2214740a734SSean Callanan 22230fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo 22330fdc8d8SChris Lattner 22430fdc8d8SChris Lattner //------------------------------------------------------------------------- 22530fdc8d8SChris Lattner // CommandObjectFrameInfo 22630fdc8d8SChris Lattner //------------------------------------------------------------------------- 22730fdc8d8SChris Lattner 228b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed { 22930fdc8d8SChris Lattner public: 2307428a18cSKate Stone CommandObjectFrameInfo(CommandInterpreter &interpreter) 231b9c1b51eSKate Stone : CommandObjectParsed( 232b9c1b51eSKate Stone interpreter, "frame info", "List information about the current " 233b9c1b51eSKate Stone "stack frame in the current thread.", 234b9c1b51eSKate Stone "frame info", 235b9c1b51eSKate Stone eCommandRequiresFrame | eCommandTryTargetAPILock | 236b9c1b51eSKate Stone eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 23730fdc8d8SChris Lattner 238c8ecc2a9SEugene Zelenko ~CommandObjectFrameInfo() override = default; 23930fdc8d8SChris Lattner 2405a988416SJim Ingham protected: 241b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 242f9fc609fSGreg Clayton m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream()); 24330fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 24430fdc8d8SChris Lattner return result.Succeeded(); 24530fdc8d8SChris Lattner } 24630fdc8d8SChris Lattner }; 24730fdc8d8SChris Lattner 24830fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect 24930fdc8d8SChris Lattner 25030fdc8d8SChris Lattner //------------------------------------------------------------------------- 25130fdc8d8SChris Lattner // CommandObjectFrameSelect 25230fdc8d8SChris Lattner //------------------------------------------------------------------------- 25330fdc8d8SChris Lattner 2541f0f5b5bSZachary Turner static OptionDefinition g_frame_select_options[] = { 2551f0f5b5bSZachary Turner // clang-format off 2568fe53c49STatyana Krasnukha { LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset, "A relative frame index offset from the current frame index." }, 2571f0f5b5bSZachary Turner // clang-format on 2581f0f5b5bSZachary Turner }; 2591f0f5b5bSZachary Turner 260b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed { 26130fdc8d8SChris Lattner public: 262b9c1b51eSKate Stone class CommandOptions : public Options { 263864174e1SGreg Clayton public: 264b9c1b51eSKate Stone CommandOptions() : Options() { OptionParsingStarting(nullptr); } 265864174e1SGreg Clayton 266c8ecc2a9SEugene Zelenko ~CommandOptions() override = default; 267864174e1SGreg Clayton 26897206d57SZachary Turner Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 269b9c1b51eSKate Stone ExecutionContext *execution_context) override { 27097206d57SZachary Turner Status error; 2713bcdfc0eSGreg Clayton const int short_option = m_getopt_table[option_idx].val; 272b9c1b51eSKate Stone switch (short_option) { 273864174e1SGreg Clayton case 'r': 274fe11483bSZachary Turner if (option_arg.getAsInteger(0, relative_frame_offset)) { 275fe11483bSZachary Turner relative_frame_offset = INT32_MIN; 276b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid frame offset argument '%s'", 277fe11483bSZachary Turner option_arg.str().c_str()); 278fe11483bSZachary Turner } 279864174e1SGreg Clayton break; 280864174e1SGreg Clayton 281864174e1SGreg Clayton default: 282b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid short option character '%c'", 283b9c1b51eSKate Stone short_option); 284864174e1SGreg Clayton break; 285864174e1SGreg Clayton } 286864174e1SGreg Clayton 287864174e1SGreg Clayton return error; 288864174e1SGreg Clayton } 289864174e1SGreg Clayton 290b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 291864174e1SGreg Clayton relative_frame_offset = INT32_MIN; 292864174e1SGreg Clayton } 293864174e1SGreg Clayton 2941f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 29570602439SZachary Turner return llvm::makeArrayRef(g_frame_select_options); 2961f0f5b5bSZachary Turner } 297864174e1SGreg Clayton 298864174e1SGreg Clayton int32_t relative_frame_offset; 299864174e1SGreg Clayton }; 300864174e1SGreg Clayton 3017428a18cSKate Stone CommandObjectFrameSelect(CommandInterpreter &interpreter) 3027428a18cSKate Stone : CommandObjectParsed( 303b9c1b51eSKate Stone interpreter, "frame select", "Select the current stack frame by " 304b9c1b51eSKate Stone "index from within the current thread " 305b9c1b51eSKate Stone "(see 'thread backtrace'.)", 306b9c1b51eSKate Stone nullptr, 307b9c1b51eSKate Stone eCommandRequiresThread | eCommandTryTargetAPILock | 308b9c1b51eSKate Stone eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 309b9c1b51eSKate Stone m_options() { 310405fe67fSCaroline Tice CommandArgumentEntry arg; 311405fe67fSCaroline Tice CommandArgumentData index_arg; 312405fe67fSCaroline Tice 313405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 314405fe67fSCaroline Tice index_arg.arg_type = eArgTypeFrameIndex; 315864174e1SGreg Clayton index_arg.arg_repetition = eArgRepeatOptional; 316405fe67fSCaroline Tice 317b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 318b9c1b51eSKate Stone // argument entry. 319405fe67fSCaroline Tice arg.push_back(index_arg); 320405fe67fSCaroline Tice 321405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 322405fe67fSCaroline Tice m_arguments.push_back(arg); 32330fdc8d8SChris Lattner } 32430fdc8d8SChris Lattner 325c8ecc2a9SEugene Zelenko ~CommandObjectFrameSelect() override = default; 32630fdc8d8SChris Lattner 327b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 328864174e1SGreg Clayton 3295a988416SJim Ingham protected: 330b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 331b9c1b51eSKate Stone // No need to check "thread" for validity as eCommandRequiresThread ensures 332b9c1b51eSKate Stone // it is valid 333f9fc609fSGreg Clayton Thread *thread = m_exe_ctx.GetThreadPtr(); 334f9fc609fSGreg Clayton 335864174e1SGreg Clayton uint32_t frame_idx = UINT32_MAX; 336b9c1b51eSKate Stone if (m_options.relative_frame_offset != INT32_MIN) { 337864174e1SGreg Clayton // The one and only argument is a signed relative frame index 338c14ee32dSGreg Clayton frame_idx = thread->GetSelectedFrameIndex(); 339864174e1SGreg Clayton if (frame_idx == UINT32_MAX) 340864174e1SGreg Clayton frame_idx = 0; 341864174e1SGreg Clayton 342b9c1b51eSKate Stone if (m_options.relative_frame_offset < 0) { 3433985c8c6SSaleem Abdulrasool if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset) 344864174e1SGreg Clayton frame_idx += m_options.relative_frame_offset; 345b9c1b51eSKate Stone else { 346b9c1b51eSKate Stone if (frame_idx == 0) { 34705097246SAdrian Prantl // If you are already at the bottom of the stack, then just warn 34805097246SAdrian Prantl // and don't reset the frame. 3497428a18cSKate Stone result.AppendError("Already at the bottom of the stack."); 350213b4546SJim Ingham result.SetStatus(eReturnStatusFailed); 351213b4546SJim Ingham return false; 352b9c1b51eSKate Stone } else 353864174e1SGreg Clayton frame_idx = 0; 354864174e1SGreg Clayton } 355b9c1b51eSKate Stone } else if (m_options.relative_frame_offset > 0) { 356b9c1b51eSKate Stone // I don't want "up 20" where "20" takes you past the top of the stack 357b9c1b51eSKate Stone // to produce 358b9c1b51eSKate Stone // an error, but rather to just go to the top. So I have to count the 359b9c1b51eSKate Stone // stack here... 360b0c72a5fSJim Ingham const uint32_t num_frames = thread->GetStackFrameCount(); 361b9c1b51eSKate Stone if (static_cast<int32_t>(num_frames - frame_idx) > 362b9c1b51eSKate Stone m_options.relative_frame_offset) 363864174e1SGreg Clayton frame_idx += m_options.relative_frame_offset; 364b9c1b51eSKate Stone else { 365b9c1b51eSKate Stone if (frame_idx == num_frames - 1) { 366b9c1b51eSKate Stone // If we are already at the top of the stack, just warn and don't 367b9c1b51eSKate Stone // reset the frame. 3687428a18cSKate Stone result.AppendError("Already at the top of the stack."); 369213b4546SJim Ingham result.SetStatus(eReturnStatusFailed); 370213b4546SJim Ingham return false; 371b9c1b51eSKate Stone } else 372864174e1SGreg Clayton frame_idx = num_frames - 1; 373864174e1SGreg Clayton } 374864174e1SGreg Clayton } 375b9c1b51eSKate Stone } else { 376f965cc86SZachary Turner if (command.GetArgumentCount() > 1) { 377f965cc86SZachary Turner result.AppendErrorWithFormat( 378f965cc86SZachary Turner "too many arguments; expected frame-index, saw '%s'.\n", 379867e7d17SZachary Turner command[0].c_str()); 380f965cc86SZachary Turner m_options.GenerateOptionUsage( 381f965cc86SZachary Turner result.GetErrorStream(), this, 382f965cc86SZachary Turner GetCommandInterpreter().GetDebugger().GetTerminalWidth()); 383f965cc86SZachary Turner return false; 384f965cc86SZachary Turner } 385f965cc86SZachary Turner 386b9c1b51eSKate Stone if (command.GetArgumentCount() == 1) { 387f965cc86SZachary Turner if (command[0].ref.getAsInteger(0, frame_idx)) { 388b9c1b51eSKate Stone result.AppendErrorWithFormat("invalid frame index argument '%s'.", 389f965cc86SZachary Turner command[0].c_str()); 390afbb0af8SJim Ingham result.SetStatus(eReturnStatusFailed); 391afbb0af8SJim Ingham return false; 392afbb0af8SJim Ingham } 393b9c1b51eSKate Stone } else if (command.GetArgumentCount() == 0) { 39482d4a2b9SJason Molenda frame_idx = thread->GetSelectedFrameIndex(); 395b9c1b51eSKate Stone if (frame_idx == UINT32_MAX) { 39682d4a2b9SJason Molenda frame_idx = 0; 39782d4a2b9SJason Molenda } 398864174e1SGreg Clayton } 399864174e1SGreg Clayton } 40030fdc8d8SChris Lattner 401b9c1b51eSKate Stone bool success = thread->SetSelectedFrameByIndexNoisily( 402b9c1b51eSKate Stone frame_idx, result.GetOutputStream()); 403b9c1b51eSKate Stone if (success) { 404f9fc609fSGreg Clayton m_exe_ctx.SetFrameSP(thread->GetSelectedFrame()); 40530fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 406b9c1b51eSKate Stone } else { 407b9c1b51eSKate Stone result.AppendErrorWithFormat("Frame index (%u) out of range.\n", 408b9c1b51eSKate Stone frame_idx); 40930fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 41093208b86SJim Ingham } 41193208b86SJim Ingham 41293208b86SJim Ingham return result.Succeeded(); 41330fdc8d8SChris Lattner } 414864174e1SGreg Clayton 415c8ecc2a9SEugene Zelenko protected: 416864174e1SGreg Clayton CommandOptions m_options; 417864174e1SGreg Clayton }; 418864174e1SGreg Clayton 4196d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable 4206d56d2ceSJim Ingham //---------------------------------------------------------------------- 4216d56d2ceSJim Ingham // List images with associated information 4226d56d2ceSJim Ingham //---------------------------------------------------------------------- 423b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed { 4246d56d2ceSJim Ingham public: 4257428a18cSKate Stone CommandObjectFrameVariable(CommandInterpreter &interpreter) 4267428a18cSKate Stone : CommandObjectParsed( 427b9c1b51eSKate Stone interpreter, "frame variable", 428b9c1b51eSKate Stone "Show variables for the current stack frame. Defaults to all " 4297428a18cSKate Stone "arguments and local variables in scope. Names of argument, " 4307428a18cSKate Stone "local, file static and file global variables can be specified. " 431ed8a705cSGreg Clayton "Children of aggregate variables can be specified such as " 432285ae0c0SJim Ingham "'var->child.x'. The -> and [] operators in 'frame variable' do " 433285ae0c0SJim Ingham "not invoke operator overloads if they exist, but directly access " 434285ae0c0SJim Ingham "the specified element. If you want to trigger operator overloads " 435285ae0c0SJim Ingham "use the expression command to print the variable instead." 436285ae0c0SJim Ingham "\nIt is worth noting that except for overloaded " 437285ae0c0SJim Ingham "operators, when printing local variables 'expr local_var' and " 438285ae0c0SJim Ingham "'frame var local_var' produce the same " 439285ae0c0SJim Ingham "results. However, 'frame variable' is more efficient, since it " 440285ae0c0SJim Ingham "uses debug information and memory reads directly, rather than " 441285ae0c0SJim Ingham "parsing and evaluating an expression, which may even involve " 442285ae0c0SJim Ingham "JITing and running code in the target program.", 443b9c1b51eSKate Stone nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock | 444b9c1b51eSKate Stone eCommandProcessMustBeLaunched | 4457428a18cSKate Stone eCommandProcessMustBePaused | eCommandRequiresProcess), 446e1cfbc79STodd Fiala m_option_group(), 447b9c1b51eSKate Stone m_option_variable( 448b9c1b51eSKate Stone true), // Include the frame specific options by passing "true" 4491deb7962SGreg Clayton m_option_format(eFormatDefault), 450b9c1b51eSKate Stone m_varobj_options() { 451405fe67fSCaroline Tice CommandArgumentEntry arg; 452405fe67fSCaroline Tice CommandArgumentData var_name_arg; 453405fe67fSCaroline Tice 454405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 455405fe67fSCaroline Tice var_name_arg.arg_type = eArgTypeVarName; 456405fe67fSCaroline Tice var_name_arg.arg_repetition = eArgRepeatStar; 457405fe67fSCaroline Tice 458b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 459b9c1b51eSKate Stone // argument entry. 460405fe67fSCaroline Tice arg.push_back(var_name_arg); 461405fe67fSCaroline Tice 462405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 463405fe67fSCaroline Tice m_arguments.push_back(arg); 4642837b766SJim Ingham 465715c2365SGreg Clayton m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 466b9c1b51eSKate Stone m_option_group.Append(&m_option_format, 467b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_FORMAT | 468b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_GDB_FMT, 469b9c1b51eSKate Stone LLDB_OPT_SET_1); 4702837b766SJim Ingham m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 4712837b766SJim Ingham m_option_group.Finalize(); 4726d56d2ceSJim Ingham } 4736d56d2ceSJim Ingham 474c8ecc2a9SEugene Zelenko ~CommandObjectFrameVariable() override = default; 4756d56d2ceSJim Ingham 476b9c1b51eSKate Stone Options *GetOptions() override { return &m_option_group; } 477f21feadcSGreg Clayton 4782443bbd4SRaphael Isemann int HandleArgumentCompletion( 4792443bbd4SRaphael Isemann CompletionRequest &request, 4802443bbd4SRaphael Isemann OptionElementVector &opt_element_vector) override { 481f21feadcSGreg Clayton // Arguments are the standard source file completer. 482b9c1b51eSKate Stone CommandCompletions::InvokeCommonCompletionCallbacks( 483b9c1b51eSKate Stone GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, 484a2e76c0bSRaphael Isemann request, nullptr); 4851a6d7ab5SRaphael Isemann return request.GetNumberOfMatches(); 486f21feadcSGreg Clayton } 4876d56d2ceSJim Ingham 4885a988416SJim Ingham protected: 48973418dfeSEnrico Granata llvm::StringRef GetScopeString(VariableSP var_sp) { 49073418dfeSEnrico Granata if (!var_sp) 49173418dfeSEnrico Granata return llvm::StringRef::withNullAsEmpty(nullptr); 49273418dfeSEnrico Granata 49373418dfeSEnrico Granata switch (var_sp->GetScope()) { 49473418dfeSEnrico Granata case eValueTypeVariableGlobal: 49573418dfeSEnrico Granata return "GLOBAL: "; 49673418dfeSEnrico Granata case eValueTypeVariableStatic: 49773418dfeSEnrico Granata return "STATIC: "; 49873418dfeSEnrico Granata case eValueTypeVariableArgument: 49973418dfeSEnrico Granata return "ARG: "; 50073418dfeSEnrico Granata case eValueTypeVariableLocal: 50173418dfeSEnrico Granata return "LOCAL: "; 50273418dfeSEnrico Granata case eValueTypeVariableThreadLocal: 50373418dfeSEnrico Granata return "THREAD: "; 50473418dfeSEnrico Granata default: 50573418dfeSEnrico Granata break; 50673418dfeSEnrico Granata } 50773418dfeSEnrico Granata 50873418dfeSEnrico Granata return llvm::StringRef::withNullAsEmpty(nullptr); 50973418dfeSEnrico Granata } 51073418dfeSEnrico Granata 511b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 51205097246SAdrian Prantl // No need to check "frame" for validity as eCommandRequiresFrame ensures 51305097246SAdrian Prantl // it is valid 514b57e4a1bSJason Molenda StackFrame *frame = m_exe_ctx.GetFramePtr(); 5151e49e5e7SJohnny Chen 516a134cc1bSGreg Clayton Stream &s = result.GetOutputStream(); 5176d56d2ceSJim Ingham 518b9c1b51eSKate Stone // Be careful about the stack frame, if any summary formatter runs code, it 51905097246SAdrian Prantl // might clear the StackFrameList for the thread. So hold onto a shared 52005097246SAdrian Prantl // pointer to the frame so it stays alive. 521650543f9SJim Ingham 522b9c1b51eSKate Stone VariableList *variable_list = 523b9c1b51eSKate Stone frame->GetVariableList(m_option_variable.show_globals); 524a134cc1bSGreg Clayton 5256d56d2ceSJim Ingham VariableSP var_sp; 5266d56d2ceSJim Ingham ValueObjectSP valobj_sp; 52778a685aaSJim Ingham 528061858ceSEnrico Granata TypeSummaryImplSP summary_format_sp; 52917b11749SEnrico Granata if (!m_option_variable.summary.IsCurrentValueEmpty()) 530b9c1b51eSKate Stone DataVisualization::NamedSummaryFormats::GetSummaryFormat( 531b9c1b51eSKate Stone ConstString(m_option_variable.summary.GetCurrentValue()), 532b9c1b51eSKate Stone summary_format_sp); 53317b11749SEnrico Granata else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 534b9c1b51eSKate Stone summary_format_sp.reset(new StringSummaryFormat( 535b9c1b51eSKate Stone TypeSummaryImpl::Flags(), 536b9c1b51eSKate Stone m_option_variable.summary_string.GetCurrentValue())); 537f9fa6ee5SEnrico Granata 538b9c1b51eSKate Stone DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( 539b9c1b51eSKate Stone eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault, 540b9c1b51eSKate Stone summary_format_sp)); 541379447a7SEnrico Granata 542b9c1b51eSKate Stone const SymbolContext &sym_ctx = 543b9c1b51eSKate Stone frame->GetSymbolContext(eSymbolContextFunction); 5446754e04fSEnrico Granata if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 5456754e04fSEnrico Granata m_option_variable.show_globals = true; 5466754e04fSEnrico Granata 547b9c1b51eSKate Stone if (variable_list) { 5481deb7962SGreg Clayton const Format format = m_option_format.GetFormat(); 5490c489f58SEnrico Granata options.SetFormat(format); 5501deb7962SGreg Clayton 55111eb9c64SZachary Turner if (!command.empty()) { 55246747022SGreg Clayton VariableList regex_var_list; 55346747022SGreg Clayton 55405097246SAdrian Prantl // If we have any args to the variable command, we will make variable 55505097246SAdrian Prantl // objects from them... 556f965cc86SZachary Turner for (auto &entry : command) { 557b9c1b51eSKate Stone if (m_option_variable.use_regex) { 558c7bece56SGreg Clayton const size_t regex_start_index = regex_var_list.GetSize(); 559f965cc86SZachary Turner llvm::StringRef name_str = entry.ref; 56095eae423SZachary Turner RegularExpression regex(name_str); 56195eae423SZachary Turner if (regex.Compile(name_str)) { 56246747022SGreg Clayton size_t num_matches = 0; 563b9c1b51eSKate Stone const size_t num_new_regex_vars = 564b9c1b51eSKate Stone variable_list->AppendVariablesIfUnique(regex, regex_var_list, 56578a685aaSJim Ingham num_matches); 566b9c1b51eSKate Stone if (num_new_regex_vars > 0) { 567b9c1b51eSKate Stone for (size_t regex_idx = regex_start_index, 568b9c1b51eSKate Stone end_index = regex_var_list.GetSize(); 569b9c1b51eSKate Stone regex_idx < end_index; ++regex_idx) { 57046747022SGreg Clayton var_sp = regex_var_list.GetVariableAtIndex(regex_idx); 571b9c1b51eSKate Stone if (var_sp) { 572b9c1b51eSKate Stone valobj_sp = frame->GetValueObjectForFrameVariable( 573b9c1b51eSKate Stone var_sp, m_varobj_options.use_dynamic); 574b9c1b51eSKate Stone if (valobj_sp) { 57573418dfeSEnrico Granata std::string scope_string; 57673418dfeSEnrico Granata if (m_option_variable.show_scope) 57773418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 57873418dfeSEnrico Granata 57973418dfeSEnrico Granata if (!scope_string.empty()) 580771ef6d4SMalcolm Parsons s.PutCString(scope_string); 58173418dfeSEnrico Granata 582b9c1b51eSKate Stone if (m_option_variable.show_decl && 583b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 58445ba8543SGreg Clayton bool show_fullpaths = false; 58545ba8543SGreg Clayton bool show_module = true; 586b9c1b51eSKate Stone if (var_sp->DumpDeclaration(&s, show_fullpaths, 587b9c1b51eSKate Stone show_module)) 58846747022SGreg Clayton s.PutCString(": "); 58946747022SGreg Clayton } 5904d93b8cdSEnrico Granata valobj_sp->Dump(result.GetOutputStream(), options); 59146747022SGreg Clayton } 59246747022SGreg Clayton } 59346747022SGreg Clayton } 594b9c1b51eSKate Stone } else if (num_matches == 0) { 595b9c1b51eSKate Stone result.GetErrorStream().Printf("error: no variables matched " 596b9c1b51eSKate Stone "the regular expression '%s'.\n", 597f965cc86SZachary Turner entry.c_str()); 59846747022SGreg Clayton } 599b9c1b51eSKate Stone } else { 60046747022SGreg Clayton char regex_error[1024]; 60146747022SGreg Clayton if (regex.GetErrorAsCString(regex_error, sizeof(regex_error))) 60246747022SGreg Clayton result.GetErrorStream().Printf("error: %s\n", regex_error); 60346747022SGreg Clayton else 604b9c1b51eSKate Stone result.GetErrorStream().Printf( 605b9c1b51eSKate Stone "error: unknown regex error when compiling '%s'\n", 606f965cc86SZachary Turner entry.c_str()); 60746747022SGreg Clayton } 608b9c1b51eSKate Stone } else // No regex, either exact variable names or variable 609b9c1b51eSKate Stone // expressions. 61046747022SGreg Clayton { 61197206d57SZachary Turner Status error; 612b9c1b51eSKate Stone uint32_t expr_path_options = 613b9c1b51eSKate Stone StackFrame::eExpressionPathOptionCheckPtrVsMember | 61446252398SEnrico Granata StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 61546252398SEnrico Granata StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 6162837b766SJim Ingham lldb::VariableSP var_sp; 617b9c1b51eSKate Stone valobj_sp = frame->GetValueForVariableExpressionPath( 618f965cc86SZachary Turner entry.ref, m_varobj_options.use_dynamic, expr_path_options, 619b9c1b51eSKate Stone var_sp, error); 620b9c1b51eSKate Stone if (valobj_sp) { 62173418dfeSEnrico Granata std::string scope_string; 62273418dfeSEnrico Granata if (m_option_variable.show_scope) 62373418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 62473418dfeSEnrico Granata 62573418dfeSEnrico Granata if (!scope_string.empty()) 626771ef6d4SMalcolm Parsons s.PutCString(scope_string); 627b9c1b51eSKate Stone if (m_option_variable.show_decl && var_sp && 628b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 629a134cc1bSGreg Clayton var_sp->GetDeclaration().DumpStopContext(&s, false); 630a134cc1bSGreg Clayton s.PutCString(": "); 631a134cc1bSGreg Clayton } 6320c489f58SEnrico Granata 6330c489f58SEnrico Granata options.SetFormat(format); 634b9c1b51eSKate Stone options.SetVariableFormatDisplayLanguage( 635b9c1b51eSKate Stone valobj_sp->GetPreferredDisplayLanguage()); 636887062aeSJohnny Chen 637887062aeSJohnny Chen Stream &output_stream = result.GetOutputStream(); 638f965cc86SZachary Turner options.SetRootValueObjectName( 639f965cc86SZachary Turner valobj_sp->GetParent() ? entry.c_str() : nullptr); 6404d93b8cdSEnrico Granata valobj_sp->Dump(output_stream, options); 641b9c1b51eSKate Stone } else { 642c8ecc2a9SEugene Zelenko const char *error_cstr = error.AsCString(nullptr); 64354979cddSGreg Clayton if (error_cstr) 64454979cddSGreg Clayton result.GetErrorStream().Printf("error: %s\n", error_cstr); 64554979cddSGreg Clayton else 646b9c1b51eSKate Stone result.GetErrorStream().Printf("error: unable to find any " 647b9c1b51eSKate Stone "variable expression path that " 648b9c1b51eSKate Stone "matches '%s'.\n", 649f965cc86SZachary Turner entry.c_str()); 6506d56d2ceSJim Ingham } 6516d56d2ceSJim Ingham } 6526d56d2ceSJim Ingham } 653b9c1b51eSKate Stone } else // No command arg specified. Use variable_list, instead. 6546d56d2ceSJim Ingham { 655c7bece56SGreg Clayton const size_t num_variables = variable_list->GetSize(); 656b9c1b51eSKate Stone if (num_variables > 0) { 657b9c1b51eSKate Stone for (size_t i = 0; i < num_variables; i++) { 6581a65ae11SGreg Clayton var_sp = variable_list->GetVariableAtIndex(i); 659f955efc0SSylvestre Ledru switch (var_sp->GetScope()) { 660eb236735SJim Ingham case eValueTypeVariableGlobal: 661eb236735SJim Ingham if (!m_option_variable.show_globals) 662eb236735SJim Ingham continue; 663eb236735SJim Ingham break; 664eb236735SJim Ingham case eValueTypeVariableStatic: 665eb236735SJim Ingham if (!m_option_variable.show_globals) 666eb236735SJim Ingham continue; 667eb236735SJim Ingham break; 668eb236735SJim Ingham case eValueTypeVariableArgument: 669eb236735SJim Ingham if (!m_option_variable.show_args) 670eb236735SJim Ingham continue; 671eb236735SJim Ingham break; 672eb236735SJim Ingham case eValueTypeVariableLocal: 673eb236735SJim Ingham if (!m_option_variable.show_locals) 674eb236735SJim Ingham continue; 675eb236735SJim Ingham break; 676eb236735SJim Ingham default: 677eb236735SJim Ingham continue; 678eb236735SJim Ingham break; 679eb236735SJim Ingham } 680560558ebSEnrico Granata std::string scope_string; 681eb236735SJim Ingham if (m_option_variable.show_scope) 68273418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 6836d56d2ceSJim Ingham 68405097246SAdrian Prantl // Use the variable object code to make sure we are using the same 68505097246SAdrian Prantl // APIs as the public API will be using... 686b9c1b51eSKate Stone valobj_sp = frame->GetValueObjectForFrameVariable( 687b9c1b51eSKate Stone var_sp, m_varobj_options.use_dynamic); 688b9c1b51eSKate Stone if (valobj_sp) { 68905097246SAdrian Prantl // When dumping all variables, don't print any variables that are 69005097246SAdrian Prantl // not in scope to avoid extra unneeded output 691b9c1b51eSKate Stone if (valobj_sp->IsInScope()) { 692b9c1b51eSKate Stone if (!valobj_sp->GetTargetSP() 693b9c1b51eSKate Stone ->GetDisplayRuntimeSupportValues() && 694c8ecc2a9SEugene Zelenko valobj_sp->IsRuntimeSupportValue()) 695560558ebSEnrico Granata continue; 696560558ebSEnrico Granata 697560558ebSEnrico Granata if (!scope_string.empty()) 698771ef6d4SMalcolm Parsons s.PutCString(scope_string); 699560558ebSEnrico Granata 700b9c1b51eSKate Stone if (m_option_variable.show_decl && 701b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 702a134cc1bSGreg Clayton var_sp->GetDeclaration().DumpStopContext(&s, false); 703a134cc1bSGreg Clayton s.PutCString(": "); 704a134cc1bSGreg Clayton } 7050c489f58SEnrico Granata 7060c489f58SEnrico Granata options.SetFormat(format); 707b9c1b51eSKate Stone options.SetVariableFormatDisplayLanguage( 708b9c1b51eSKate Stone valobj_sp->GetPreferredDisplayLanguage()); 709f965cc86SZachary Turner options.SetRootValueObjectName( 710f965cc86SZachary Turner var_sp ? var_sp->GetName().AsCString() : nullptr); 7114d93b8cdSEnrico Granata valobj_sp->Dump(result.GetOutputStream(), options); 712a134cc1bSGreg Clayton } 713a134cc1bSGreg Clayton } 7146d56d2ceSJim Ingham } 7156d56d2ceSJim Ingham } 7166d56d2ceSJim Ingham } 7176d56d2ceSJim Ingham result.SetStatus(eReturnStatusSuccessFinishResult); 7186d56d2ceSJim Ingham } 71961a80ba6SEnrico Granata 720*41ae8e74SKuba Mracek if (m_option_variable.show_recognized_args) { 721*41ae8e74SKuba Mracek auto recognized_frame = frame->GetRecognizedFrame(); 722*41ae8e74SKuba Mracek if (recognized_frame) { 723*41ae8e74SKuba Mracek ValueObjectListSP recognized_arg_list = 724*41ae8e74SKuba Mracek recognized_frame->GetRecognizedArguments(); 725*41ae8e74SKuba Mracek if (recognized_arg_list) { 726*41ae8e74SKuba Mracek for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { 727*41ae8e74SKuba Mracek options.SetFormat(m_option_format.GetFormat()); 728*41ae8e74SKuba Mracek options.SetVariableFormatDisplayLanguage( 729*41ae8e74SKuba Mracek rec_value_sp->GetPreferredDisplayLanguage()); 730*41ae8e74SKuba Mracek options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); 731*41ae8e74SKuba Mracek rec_value_sp->Dump(result.GetOutputStream(), options); 732*41ae8e74SKuba Mracek } 733*41ae8e74SKuba Mracek } 734*41ae8e74SKuba Mracek } 735*41ae8e74SKuba Mracek } 736*41ae8e74SKuba Mracek 737b9c1b51eSKate Stone if (m_interpreter.TruncationWarningNecessary()) { 73861a80ba6SEnrico Granata result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 73961a80ba6SEnrico Granata m_cmd_name.c_str()); 74061a80ba6SEnrico Granata m_interpreter.TruncationWarningGiven(); 74161a80ba6SEnrico Granata } 74261a80ba6SEnrico Granata 74324fff242SDavide Italiano // Increment statistics. 74424fff242SDavide Italiano bool res = result.Succeeded(); 7450df817aaSDavide Italiano Target *target = GetSelectedOrDummyTarget(); 74624fff242SDavide Italiano if (res) 74724fff242SDavide Italiano target->IncrementStats(StatisticKind::FrameVarSuccess); 74824fff242SDavide Italiano else 74924fff242SDavide Italiano target->IncrementStats(StatisticKind::FrameVarFailure); 75024fff242SDavide Italiano return res; 7516d56d2ceSJim Ingham } 7526d56d2ceSJim Ingham 753c8ecc2a9SEugene Zelenko protected: 7542837b766SJim Ingham OptionGroupOptions m_option_group; 755715c2365SGreg Clayton OptionGroupVariable m_option_variable; 7561deb7962SGreg Clayton OptionGroupFormat m_option_format; 7572837b766SJim Ingham OptionGroupValueObjectDisplay m_varobj_options; 7586d56d2ceSJim Ingham }; 7596d56d2ceSJim Ingham 760*41ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer 761*41ae8e74SKuba Mracek 762*41ae8e74SKuba Mracek static OptionDefinition g_frame_recognizer_add_options[] = { 763*41ae8e74SKuba Mracek // clang-format off 764*41ae8e74SKuba Mracek { LLDB_OPT_SET_ALL, false, "shlib", 's', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Name of the module or shared library that this recognizer applies to." }, 765*41ae8e74SKuba Mracek { LLDB_OPT_SET_ALL, false, "function", 'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeName, "Name of the function that this recognizer applies to." }, 766*41ae8e74SKuba Mracek { LLDB_OPT_SET_2, false, "python-class", 'l', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePythonClass, "Give the name of a Python class to use for this frame recognizer." }, 767*41ae8e74SKuba Mracek { LLDB_OPT_SET_ALL, false, "regex", 'x', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Function name and module name are actually regular expressions." } 768*41ae8e74SKuba Mracek // clang-format on 769*41ae8e74SKuba Mracek }; 770*41ae8e74SKuba Mracek 771*41ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { 772*41ae8e74SKuba Mracek private: 773*41ae8e74SKuba Mracek class CommandOptions : public Options { 774*41ae8e74SKuba Mracek public: 775*41ae8e74SKuba Mracek CommandOptions() : Options() {} 776*41ae8e74SKuba Mracek ~CommandOptions() override = default; 777*41ae8e74SKuba Mracek 778*41ae8e74SKuba Mracek Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 779*41ae8e74SKuba Mracek ExecutionContext *execution_context) override { 780*41ae8e74SKuba Mracek Status error; 781*41ae8e74SKuba Mracek const int short_option = m_getopt_table[option_idx].val; 782*41ae8e74SKuba Mracek 783*41ae8e74SKuba Mracek switch (short_option) { 784*41ae8e74SKuba Mracek case 'l': 785*41ae8e74SKuba Mracek m_class_name = std::string(option_arg); 786*41ae8e74SKuba Mracek break; 787*41ae8e74SKuba Mracek case 's': 788*41ae8e74SKuba Mracek m_module = std::string(option_arg); 789*41ae8e74SKuba Mracek break; 790*41ae8e74SKuba Mracek case 'n': 791*41ae8e74SKuba Mracek m_function = std::string(option_arg); 792*41ae8e74SKuba Mracek break; 793*41ae8e74SKuba Mracek case 'x': 794*41ae8e74SKuba Mracek m_regex = true; 795*41ae8e74SKuba Mracek break; 796*41ae8e74SKuba Mracek default: 797*41ae8e74SKuba Mracek error.SetErrorStringWithFormat("unrecognized option '%c'", 798*41ae8e74SKuba Mracek short_option); 799*41ae8e74SKuba Mracek break; 800*41ae8e74SKuba Mracek } 801*41ae8e74SKuba Mracek 802*41ae8e74SKuba Mracek return error; 803*41ae8e74SKuba Mracek } 804*41ae8e74SKuba Mracek 805*41ae8e74SKuba Mracek void OptionParsingStarting(ExecutionContext *execution_context) override { 806*41ae8e74SKuba Mracek m_module = ""; 807*41ae8e74SKuba Mracek m_function = ""; 808*41ae8e74SKuba Mracek m_class_name = ""; 809*41ae8e74SKuba Mracek m_regex = false; 810*41ae8e74SKuba Mracek } 811*41ae8e74SKuba Mracek 812*41ae8e74SKuba Mracek llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 813*41ae8e74SKuba Mracek return llvm::makeArrayRef(g_frame_recognizer_add_options); 814*41ae8e74SKuba Mracek } 815*41ae8e74SKuba Mracek 816*41ae8e74SKuba Mracek // Instance variables to hold the values for command options. 817*41ae8e74SKuba Mracek std::string m_class_name; 818*41ae8e74SKuba Mracek std::string m_module; 819*41ae8e74SKuba Mracek std::string m_function; 820*41ae8e74SKuba Mracek bool m_regex; 821*41ae8e74SKuba Mracek }; 822*41ae8e74SKuba Mracek 823*41ae8e74SKuba Mracek CommandOptions m_options; 824*41ae8e74SKuba Mracek 825*41ae8e74SKuba Mracek Options *GetOptions() override { return &m_options; } 826*41ae8e74SKuba Mracek 827*41ae8e74SKuba Mracek protected: 828*41ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override; 829*41ae8e74SKuba Mracek 830*41ae8e74SKuba Mracek public: 831*41ae8e74SKuba Mracek CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 832*41ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer add", 833*41ae8e74SKuba Mracek "Add a new frame recognizer.", nullptr), 834*41ae8e74SKuba Mracek m_options() { 835*41ae8e74SKuba Mracek SetHelpLong(R"( 836*41ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on 837*41ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source 838*41ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments 839*41ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments. 840*41ae8e74SKuba Mracek 841*41ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class 842*41ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a 843*41ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type 844*41ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize. 845*41ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that 846*41ae8e74SKuba Mracek represent the recognized arguments. 847*41ae8e74SKuba Mracek 848*41ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc 849*41ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows: 850*41ae8e74SKuba Mracek 851*41ae8e74SKuba Mracek class LibcFdRecognizer(object): 852*41ae8e74SKuba Mracek def get_recognized_arguments(self, frame): 853*41ae8e74SKuba Mracek if frame.name in ["read", "write", "close"]: 854*41ae8e74SKuba Mracek fd = frame.EvaluateExpression("$arg1").unsigned 855*41ae8e74SKuba Mracek value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) 856*41ae8e74SKuba Mracek return [value] 857*41ae8e74SKuba Mracek return [] 858*41ae8e74SKuba Mracek 859*41ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script 860*41ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'. 861*41ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is 862*41ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 863*41ae8e74SKuba Mracek in other modules: 864*41ae8e74SKuba Mracek 865*41ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py 866*41ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 867*41ae8e74SKuba Mracek 868*41ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we 869*41ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable': 870*41ae8e74SKuba Mracek 871*41ae8e74SKuba Mracek (lldb) b read 872*41ae8e74SKuba Mracek (lldb) r 873*41ae8e74SKuba Mracek Process 1234 stopped 874*41ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 875*41ae8e74SKuba Mracek frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 876*41ae8e74SKuba Mracek (lldb) frame variable 877*41ae8e74SKuba Mracek (int) fd = 3 878*41ae8e74SKuba Mracek 879*41ae8e74SKuba Mracek )"); 880*41ae8e74SKuba Mracek } 881*41ae8e74SKuba Mracek ~CommandObjectFrameRecognizerAdd() override = default; 882*41ae8e74SKuba Mracek }; 883*41ae8e74SKuba Mracek 884*41ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 885*41ae8e74SKuba Mracek CommandReturnObject &result) { 886*41ae8e74SKuba Mracek if (m_options.m_class_name.empty()) { 887*41ae8e74SKuba Mracek result.AppendErrorWithFormat( 888*41ae8e74SKuba Mracek "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 889*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 890*41ae8e74SKuba Mracek return false; 891*41ae8e74SKuba Mracek } 892*41ae8e74SKuba Mracek 893*41ae8e74SKuba Mracek if (m_options.m_module.empty()) { 894*41ae8e74SKuba Mracek result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 895*41ae8e74SKuba Mracek m_cmd_name.c_str()); 896*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 897*41ae8e74SKuba Mracek return false; 898*41ae8e74SKuba Mracek } 899*41ae8e74SKuba Mracek 900*41ae8e74SKuba Mracek if (m_options.m_function.empty()) { 901*41ae8e74SKuba Mracek result.AppendErrorWithFormat("%s needs a function name (-n argument).\n", 902*41ae8e74SKuba Mracek m_cmd_name.c_str()); 903*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 904*41ae8e74SKuba Mracek return false; 905*41ae8e74SKuba Mracek } 906*41ae8e74SKuba Mracek 907*41ae8e74SKuba Mracek ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter(); 908*41ae8e74SKuba Mracek 909*41ae8e74SKuba Mracek if (interpreter && 910*41ae8e74SKuba Mracek !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 911*41ae8e74SKuba Mracek result.AppendWarning( 912*41ae8e74SKuba Mracek "The provided class does not exist - please define it " 913*41ae8e74SKuba Mracek "before attempting to use this frame recognizer"); 914*41ae8e74SKuba Mracek } 915*41ae8e74SKuba Mracek 916*41ae8e74SKuba Mracek StackFrameRecognizerSP recognizer_sp = 917*41ae8e74SKuba Mracek StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 918*41ae8e74SKuba Mracek interpreter, m_options.m_class_name.c_str())); 919*41ae8e74SKuba Mracek if (m_options.m_regex) { 920*41ae8e74SKuba Mracek auto module = 921*41ae8e74SKuba Mracek RegularExpressionSP(new RegularExpression(m_options.m_module)); 922*41ae8e74SKuba Mracek auto func = 923*41ae8e74SKuba Mracek RegularExpressionSP(new RegularExpression(m_options.m_function)); 924*41ae8e74SKuba Mracek StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); 925*41ae8e74SKuba Mracek } else { 926*41ae8e74SKuba Mracek auto module = ConstString(m_options.m_module); 927*41ae8e74SKuba Mracek auto func = ConstString(m_options.m_function); 928*41ae8e74SKuba Mracek StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); 929*41ae8e74SKuba Mracek } 930*41ae8e74SKuba Mracek 931*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishNoResult); 932*41ae8e74SKuba Mracek return result.Succeeded(); 933*41ae8e74SKuba Mracek } 934*41ae8e74SKuba Mracek 935*41ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 936*41ae8e74SKuba Mracek public: 937*41ae8e74SKuba Mracek CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 938*41ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer clear", 939*41ae8e74SKuba Mracek "Delete all frame recognizers.", nullptr) {} 940*41ae8e74SKuba Mracek 941*41ae8e74SKuba Mracek ~CommandObjectFrameRecognizerClear() override = default; 942*41ae8e74SKuba Mracek 943*41ae8e74SKuba Mracek protected: 944*41ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 945*41ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveAllRecognizers(); 946*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 947*41ae8e74SKuba Mracek return result.Succeeded(); 948*41ae8e74SKuba Mracek } 949*41ae8e74SKuba Mracek }; 950*41ae8e74SKuba Mracek 951*41ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 952*41ae8e74SKuba Mracek public: 953*41ae8e74SKuba Mracek CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 954*41ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer delete", 955*41ae8e74SKuba Mracek "Delete an existing frame recognizer.", nullptr) {} 956*41ae8e74SKuba Mracek 957*41ae8e74SKuba Mracek ~CommandObjectFrameRecognizerDelete() override = default; 958*41ae8e74SKuba Mracek 959*41ae8e74SKuba Mracek protected: 960*41ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 961*41ae8e74SKuba Mracek if (command.GetArgumentCount() == 0) { 962*41ae8e74SKuba Mracek if (!m_interpreter.Confirm( 963*41ae8e74SKuba Mracek "About to delete all frame recognizers, do you want to do that?", 964*41ae8e74SKuba Mracek true)) { 965*41ae8e74SKuba Mracek result.AppendMessage("Operation cancelled..."); 966*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 967*41ae8e74SKuba Mracek return false; 968*41ae8e74SKuba Mracek } 969*41ae8e74SKuba Mracek 970*41ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveAllRecognizers(); 971*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 972*41ae8e74SKuba Mracek return result.Succeeded(); 973*41ae8e74SKuba Mracek } 974*41ae8e74SKuba Mracek 975*41ae8e74SKuba Mracek if (command.GetArgumentCount() != 1) { 976*41ae8e74SKuba Mracek result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 977*41ae8e74SKuba Mracek m_cmd_name.c_str()); 978*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 979*41ae8e74SKuba Mracek return false; 980*41ae8e74SKuba Mracek } 981*41ae8e74SKuba Mracek 982*41ae8e74SKuba Mracek uint32_t recognizer_id = 983*41ae8e74SKuba Mracek StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 984*41ae8e74SKuba Mracek 985*41ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id); 986*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 987*41ae8e74SKuba Mracek return result.Succeeded(); 988*41ae8e74SKuba Mracek } 989*41ae8e74SKuba Mracek }; 990*41ae8e74SKuba Mracek 991*41ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed { 992*41ae8e74SKuba Mracek public: 993*41ae8e74SKuba Mracek CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 994*41ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer list", 995*41ae8e74SKuba Mracek "Show a list of active frame recognizers.", 996*41ae8e74SKuba Mracek nullptr) {} 997*41ae8e74SKuba Mracek 998*41ae8e74SKuba Mracek ~CommandObjectFrameRecognizerList() override = default; 999*41ae8e74SKuba Mracek 1000*41ae8e74SKuba Mracek protected: 1001*41ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 1002*41ae8e74SKuba Mracek bool any_printed = false; 1003*41ae8e74SKuba Mracek StackFrameRecognizerManager::ForEach( 1004*41ae8e74SKuba Mracek [&result, &any_printed](uint32_t recognizer_id, std::string name, 1005*41ae8e74SKuba Mracek std::string function, std::string symbol, 1006*41ae8e74SKuba Mracek bool regexp) { 1007*41ae8e74SKuba Mracek if (name == "") name = "(internal)"; 1008*41ae8e74SKuba Mracek result.GetOutputStream().Printf( 1009*41ae8e74SKuba Mracek "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(), 1010*41ae8e74SKuba Mracek function.c_str(), symbol.c_str(), regexp ? " (regexp)" : ""); 1011*41ae8e74SKuba Mracek any_printed = true; 1012*41ae8e74SKuba Mracek }); 1013*41ae8e74SKuba Mracek 1014*41ae8e74SKuba Mracek if (any_printed) 1015*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 1016*41ae8e74SKuba Mracek else { 1017*41ae8e74SKuba Mracek result.GetOutputStream().PutCString("no matching results found.\n"); 1018*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishNoResult); 1019*41ae8e74SKuba Mracek } 1020*41ae8e74SKuba Mracek return result.Succeeded(); 1021*41ae8e74SKuba Mracek } 1022*41ae8e74SKuba Mracek }; 1023*41ae8e74SKuba Mracek 1024*41ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 1025*41ae8e74SKuba Mracek public: 1026*41ae8e74SKuba Mracek CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 1027*41ae8e74SKuba Mracek : CommandObjectParsed( 1028*41ae8e74SKuba Mracek interpreter, "frame recognizer info", 1029*41ae8e74SKuba Mracek "Show which frame recognizer is applied a stack frame (if any).", 1030*41ae8e74SKuba Mracek nullptr) { 1031*41ae8e74SKuba Mracek CommandArgumentEntry arg; 1032*41ae8e74SKuba Mracek CommandArgumentData index_arg; 1033*41ae8e74SKuba Mracek 1034*41ae8e74SKuba Mracek // Define the first (and only) variant of this arg. 1035*41ae8e74SKuba Mracek index_arg.arg_type = eArgTypeFrameIndex; 1036*41ae8e74SKuba Mracek index_arg.arg_repetition = eArgRepeatPlain; 1037*41ae8e74SKuba Mracek 1038*41ae8e74SKuba Mracek // There is only one variant this argument could be; put it into the 1039*41ae8e74SKuba Mracek // argument entry. 1040*41ae8e74SKuba Mracek arg.push_back(index_arg); 1041*41ae8e74SKuba Mracek 1042*41ae8e74SKuba Mracek // Push the data for the first argument into the m_arguments vector. 1043*41ae8e74SKuba Mracek m_arguments.push_back(arg); 1044*41ae8e74SKuba Mracek } 1045*41ae8e74SKuba Mracek 1046*41ae8e74SKuba Mracek ~CommandObjectFrameRecognizerInfo() override = default; 1047*41ae8e74SKuba Mracek 1048*41ae8e74SKuba Mracek protected: 1049*41ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 1050*41ae8e74SKuba Mracek Process *process = m_exe_ctx.GetProcessPtr(); 1051*41ae8e74SKuba Mracek if (process == nullptr) { 1052*41ae8e74SKuba Mracek result.AppendError("no process"); 1053*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 1054*41ae8e74SKuba Mracek return false; 1055*41ae8e74SKuba Mracek } 1056*41ae8e74SKuba Mracek Thread *thread = m_exe_ctx.GetThreadPtr(); 1057*41ae8e74SKuba Mracek if (thread == nullptr) { 1058*41ae8e74SKuba Mracek result.AppendError("no thread"); 1059*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 1060*41ae8e74SKuba Mracek return false; 1061*41ae8e74SKuba Mracek } 1062*41ae8e74SKuba Mracek if (command.GetArgumentCount() != 1) { 1063*41ae8e74SKuba Mracek result.AppendErrorWithFormat( 1064*41ae8e74SKuba Mracek "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 1065*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 1066*41ae8e74SKuba Mracek return false; 1067*41ae8e74SKuba Mracek } 1068*41ae8e74SKuba Mracek 1069*41ae8e74SKuba Mracek uint32_t frame_index = 1070*41ae8e74SKuba Mracek StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 1071*41ae8e74SKuba Mracek StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 1072*41ae8e74SKuba Mracek if (!frame_sp) { 1073*41ae8e74SKuba Mracek result.AppendErrorWithFormat("no frame with index %u", frame_index); 1074*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 1075*41ae8e74SKuba Mracek return false; 1076*41ae8e74SKuba Mracek } 1077*41ae8e74SKuba Mracek 1078*41ae8e74SKuba Mracek auto recognizer = 1079*41ae8e74SKuba Mracek StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp); 1080*41ae8e74SKuba Mracek 1081*41ae8e74SKuba Mracek Stream &output_stream = result.GetOutputStream(); 1082*41ae8e74SKuba Mracek output_stream.Printf("frame %d ", frame_index); 1083*41ae8e74SKuba Mracek if (recognizer) { 1084*41ae8e74SKuba Mracek output_stream << "is recognized by "; 1085*41ae8e74SKuba Mracek output_stream << recognizer->GetName(); 1086*41ae8e74SKuba Mracek } else { 1087*41ae8e74SKuba Mracek output_stream << "not recognized by any recognizer"; 1088*41ae8e74SKuba Mracek } 1089*41ae8e74SKuba Mracek output_stream.EOL(); 1090*41ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 1091*41ae8e74SKuba Mracek return result.Succeeded(); 1092*41ae8e74SKuba Mracek } 1093*41ae8e74SKuba Mracek }; 1094*41ae8e74SKuba Mracek 1095*41ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword { 1096*41ae8e74SKuba Mracek public: 1097*41ae8e74SKuba Mracek CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 1098*41ae8e74SKuba Mracek : CommandObjectMultiword( 1099*41ae8e74SKuba Mracek interpreter, "frame recognizer", 1100*41ae8e74SKuba Mracek "Commands for editing and viewing frame recognizers.", 1101*41ae8e74SKuba Mracek "frame recognizer [<sub-command-options>] ") { 1102*41ae8e74SKuba Mracek LoadSubCommand( 1103*41ae8e74SKuba Mracek "add", 1104*41ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter))); 1105*41ae8e74SKuba Mracek LoadSubCommand( 1106*41ae8e74SKuba Mracek "clear", 1107*41ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 1108*41ae8e74SKuba Mracek LoadSubCommand( 1109*41ae8e74SKuba Mracek "delete", 1110*41ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 1111*41ae8e74SKuba Mracek LoadSubCommand( 1112*41ae8e74SKuba Mracek "list", 1113*41ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter))); 1114*41ae8e74SKuba Mracek LoadSubCommand( 1115*41ae8e74SKuba Mracek "info", 1116*41ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerInfo(interpreter))); 1117*41ae8e74SKuba Mracek } 1118*41ae8e74SKuba Mracek 1119*41ae8e74SKuba Mracek ~CommandObjectFrameRecognizer() override = default; 1120*41ae8e74SKuba Mracek }; 1121*41ae8e74SKuba Mracek 112230fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame 112330fdc8d8SChris Lattner 112430fdc8d8SChris Lattner //------------------------------------------------------------------------- 112530fdc8d8SChris Lattner // CommandObjectMultiwordFrame 112630fdc8d8SChris Lattner //------------------------------------------------------------------------- 112730fdc8d8SChris Lattner 1128b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1129b9c1b51eSKate Stone CommandInterpreter &interpreter) 1130b9c1b51eSKate Stone : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and " 1131b9c1b51eSKate Stone "examing the current " 1132b9c1b51eSKate Stone "thread's stack frames.", 1133b9c1b51eSKate Stone "frame <subcommand> [<subcommand-options>]") { 1134b9c1b51eSKate Stone LoadSubCommand("diagnose", 1135b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1136b9c1b51eSKate Stone LoadSubCommand("info", 1137b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1138b9c1b51eSKate Stone LoadSubCommand("select", 1139b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1140b9c1b51eSKate Stone LoadSubCommand("variable", 1141b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 1142*41ae8e74SKuba Mracek #ifndef LLDB_DISABLE_PYTHON 1143*41ae8e74SKuba Mracek LoadSubCommand( 1144*41ae8e74SKuba Mracek "recognizer", 1145*41ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizer(interpreter))); 1146*41ae8e74SKuba Mracek #endif 114730fdc8d8SChris Lattner } 114830fdc8d8SChris Lattner 1149c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1150