130fdc8d8SChris Lattner //===-- CommandObjectFrame.cpp ----------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 8c8ecc2a9SEugene Zelenko #include "CommandObjectFrame.h" 930fdc8d8SChris Lattner #include "lldb/Core/Debugger.h" 106d56d2ceSJim Ingham #include "lldb/Core/Module.h" 116d56d2ceSJim Ingham #include "lldb/Core/StreamFile.h" 126d56d2ceSJim Ingham #include "lldb/Core/Value.h" 136d56d2ceSJim Ingham #include "lldb/Core/ValueObject.h" 146d56d2ceSJim Ingham #include "lldb/Core/ValueObjectVariable.h" 155548cb50SEnrico Granata #include "lldb/DataFormatters/DataVisualization.h" 164d93b8cdSEnrico Granata #include "lldb/DataFormatters/ValueObjectPrinter.h" 177fb56d0aSGreg Clayton #include "lldb/Host/Host.h" 183eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h" 1941ae8e74SKuba Mracek #include "lldb/Host/StringConvert.h" 2030fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h" 2130fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h" 221deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h" 232837b766SJim Ingham #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" 24715c2365SGreg Clayton #include "lldb/Interpreter/OptionGroupVariable.h" 25b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h" 26b9c1b51eSKate Stone #include "lldb/Symbol/CompilerType.h" 276754e04fSEnrico Granata #include "lldb/Symbol/Function.h" 286d56d2ceSJim Ingham #include "lldb/Symbol/ObjectFile.h" 296d56d2ceSJim Ingham #include "lldb/Symbol/SymbolContext.h" 306d56d2ceSJim Ingham #include "lldb/Symbol/Type.h" 316d56d2ceSJim Ingham #include "lldb/Symbol/Variable.h" 326d56d2ceSJim Ingham #include "lldb/Symbol/VariableList.h" 3330fdc8d8SChris Lattner #include "lldb/Target/Process.h" 34b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h" 3541ae8e74SKuba Mracek #include "lldb/Target/StackFrameRecognizer.h" 364740a734SSean Callanan #include "lldb/Target/StopInfo.h" 376d56d2ceSJim Ingham #include "lldb/Target/Target.h" 38b9c1b51eSKate Stone #include "lldb/Target/Thread.h" 39145d95c9SPavel Labath #include "lldb/Utility/Args.h" 404740a734SSean Callanan #include "lldb/Utility/LLDBAssert.h" 41bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h" 4238d0632eSPavel Labath #include "lldb/Utility/Timer.h" 4330fdc8d8SChris Lattner 44796ac80bSJonas Devlieghere #include <memory> 45796ac80bSJonas Devlieghere #include <string> 46796ac80bSJonas Devlieghere 4730fdc8d8SChris Lattner using namespace lldb; 4830fdc8d8SChris Lattner using namespace lldb_private; 4930fdc8d8SChris Lattner 504740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose 514740a734SSean Callanan 524740a734SSean Callanan // CommandObjectFrameInfo 534740a734SSean Callanan 544740a734SSean Callanan // CommandObjectFrameDiagnose 554740a734SSean Callanan 56ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_diag 57ec67e734SRaphael Isemann #include "CommandOptions.inc" 581f0f5b5bSZachary Turner 59b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed { 604740a734SSean Callanan public: 61b9c1b51eSKate Stone class CommandOptions : public Options { 624740a734SSean Callanan public: 63b9c1b51eSKate Stone CommandOptions() : Options() { OptionParsingStarting(nullptr); } 644740a734SSean Callanan 654740a734SSean Callanan ~CommandOptions() override = default; 664740a734SSean Callanan 6797206d57SZachary Turner Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 68b9c1b51eSKate Stone ExecutionContext *execution_context) override { 6997206d57SZachary Turner Status error; 704740a734SSean Callanan const int short_option = m_getopt_table[option_idx].val; 71b9c1b51eSKate Stone switch (short_option) { 724740a734SSean Callanan case 'r': 734740a734SSean Callanan reg = ConstString(option_arg); 744740a734SSean Callanan break; 754740a734SSean Callanan 76b9c1b51eSKate Stone case 'a': { 77fe11483bSZachary Turner address.emplace(); 78fe11483bSZachary Turner if (option_arg.getAsInteger(0, *address)) { 794740a734SSean Callanan address.reset(); 80b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid address argument '%s'", 81fe11483bSZachary Turner option_arg.str().c_str()); 824740a734SSean Callanan } 83b9c1b51eSKate Stone } break; 844740a734SSean Callanan 85b9c1b51eSKate Stone case 'o': { 86fe11483bSZachary Turner offset.emplace(); 87fe11483bSZachary Turner if (option_arg.getAsInteger(0, *offset)) { 884740a734SSean Callanan offset.reset(); 89b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid offset argument '%s'", 90fe11483bSZachary Turner option_arg.str().c_str()); 914740a734SSean Callanan } 92b9c1b51eSKate Stone } break; 934740a734SSean Callanan 944740a734SSean Callanan default: 95b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid short option character '%c'", 96b9c1b51eSKate Stone short_option); 974740a734SSean Callanan break; 984740a734SSean Callanan } 994740a734SSean Callanan 1004740a734SSean Callanan return error; 1014740a734SSean Callanan } 1024740a734SSean Callanan 103b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 1044740a734SSean Callanan address.reset(); 1054740a734SSean Callanan reg.reset(); 1064740a734SSean Callanan offset.reset(); 1074740a734SSean Callanan } 1084740a734SSean Callanan 1091f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 11070602439SZachary Turner return llvm::makeArrayRef(g_frame_diag_options); 1111f0f5b5bSZachary Turner } 1124740a734SSean Callanan 1134740a734SSean Callanan // Options. 1144740a734SSean Callanan llvm::Optional<lldb::addr_t> address; 1154740a734SSean Callanan llvm::Optional<ConstString> reg; 1164740a734SSean Callanan llvm::Optional<int64_t> offset; 1174740a734SSean Callanan }; 1184740a734SSean Callanan 1194740a734SSean Callanan CommandObjectFrameDiagnose(CommandInterpreter &interpreter) 1204740a734SSean Callanan : CommandObjectParsed(interpreter, "frame diagnose", 121b9c1b51eSKate Stone "Try to determine what path path the current stop " 122b9c1b51eSKate Stone "location used to get to a register or address", 123b9c1b51eSKate Stone nullptr, 124b9c1b51eSKate Stone eCommandRequiresThread | eCommandTryTargetAPILock | 125b9c1b51eSKate Stone eCommandProcessMustBeLaunched | 1264740a734SSean Callanan eCommandProcessMustBePaused), 127b9c1b51eSKate Stone m_options() { 1284740a734SSean Callanan CommandArgumentEntry arg; 1294740a734SSean Callanan CommandArgumentData index_arg; 1304740a734SSean Callanan 1314740a734SSean Callanan // Define the first (and only) variant of this arg. 1324740a734SSean Callanan index_arg.arg_type = eArgTypeFrameIndex; 1334740a734SSean Callanan index_arg.arg_repetition = eArgRepeatOptional; 1344740a734SSean Callanan 135b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 136b9c1b51eSKate Stone // argument entry. 1374740a734SSean Callanan arg.push_back(index_arg); 1384740a734SSean Callanan 1394740a734SSean Callanan // Push the data for the first argument into the m_arguments vector. 1404740a734SSean Callanan m_arguments.push_back(arg); 1414740a734SSean Callanan } 1424740a734SSean Callanan 1434740a734SSean Callanan ~CommandObjectFrameDiagnose() override = default; 1444740a734SSean Callanan 145b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 1464740a734SSean Callanan 1474740a734SSean Callanan protected: 148b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 1494740a734SSean Callanan Thread *thread = m_exe_ctx.GetThreadPtr(); 1504740a734SSean Callanan StackFrameSP frame_sp = thread->GetSelectedFrame(); 1514740a734SSean Callanan 1524740a734SSean Callanan ValueObjectSP valobj_sp; 1534740a734SSean Callanan 154b9c1b51eSKate Stone if (m_options.address.hasValue()) { 155b9c1b51eSKate Stone if (m_options.reg.hasValue() || m_options.offset.hasValue()) { 156b9c1b51eSKate Stone result.AppendError( 157b9c1b51eSKate Stone "`frame diagnose --address` is incompatible with other arguments."); 1584740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1594740a734SSean Callanan return false; 1604740a734SSean Callanan } 1614740a734SSean Callanan valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue()); 162b9c1b51eSKate Stone } else if (m_options.reg.hasValue()) { 163b9c1b51eSKate Stone valobj_sp = frame_sp->GuessValueForRegisterAndOffset( 164b9c1b51eSKate Stone m_options.reg.getValue(), m_options.offset.getValueOr(0)); 165b9c1b51eSKate Stone } else { 1664740a734SSean Callanan StopInfoSP stop_info_sp = thread->GetStopInfo(); 167b9c1b51eSKate Stone if (!stop_info_sp) { 1684740a734SSean Callanan result.AppendError("No arguments provided, and no stop info."); 1694740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1704740a734SSean Callanan return false; 1714740a734SSean Callanan } 1724740a734SSean Callanan 1734740a734SSean Callanan valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp); 1744740a734SSean Callanan } 1754740a734SSean Callanan 176b9c1b51eSKate Stone if (!valobj_sp) { 1774740a734SSean Callanan result.AppendError("No diagnosis available."); 1784740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1794740a734SSean Callanan return false; 1804740a734SSean Callanan } 1814740a734SSean Callanan 1824740a734SSean Callanan 1833bc714b2SZachary Turner DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp]( 1843bc714b2SZachary Turner ConstString type, ConstString var, const DumpValueObjectOptions &opts, 1853bc714b2SZachary Turner Stream &stream) -> bool { 186b9c1b51eSKate Stone const ValueObject::GetExpressionPathFormat format = ValueObject:: 187b9c1b51eSKate Stone GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers; 1885d1f711aSPavel Labath const bool qualify_cxx_base_classes = false; 1894740a734SSean Callanan valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format); 1904740a734SSean Callanan stream.PutCString(" ="); 1914740a734SSean Callanan return true; 1924740a734SSean Callanan }; 1934740a734SSean Callanan 1944740a734SSean Callanan DumpValueObjectOptions options; 1954740a734SSean Callanan options.SetDeclPrintingHelper(helper); 196b9c1b51eSKate Stone ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), 197b9c1b51eSKate Stone options); 1984740a734SSean Callanan printer.PrintValueObject(); 1994740a734SSean Callanan 2004740a734SSean Callanan return true; 2014740a734SSean Callanan } 2024740a734SSean Callanan 2034740a734SSean Callanan protected: 2044740a734SSean Callanan CommandOptions m_options; 2054740a734SSean Callanan }; 2064740a734SSean Callanan 20730fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo 20830fdc8d8SChris Lattner 20930fdc8d8SChris Lattner // CommandObjectFrameInfo 21030fdc8d8SChris Lattner 211b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed { 21230fdc8d8SChris Lattner public: 2137428a18cSKate Stone CommandObjectFrameInfo(CommandInterpreter &interpreter) 214b9c1b51eSKate Stone : CommandObjectParsed( 215b9c1b51eSKate Stone interpreter, "frame info", "List information about the current " 216b9c1b51eSKate Stone "stack frame in the current thread.", 217b9c1b51eSKate Stone "frame info", 218b9c1b51eSKate Stone eCommandRequiresFrame | eCommandTryTargetAPILock | 219b9c1b51eSKate Stone eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 22030fdc8d8SChris Lattner 221c8ecc2a9SEugene Zelenko ~CommandObjectFrameInfo() override = default; 22230fdc8d8SChris Lattner 2235a988416SJim Ingham protected: 224b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 225f9fc609fSGreg Clayton m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream()); 22630fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 22730fdc8d8SChris Lattner return result.Succeeded(); 22830fdc8d8SChris Lattner } 22930fdc8d8SChris Lattner }; 23030fdc8d8SChris Lattner 23130fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect 23230fdc8d8SChris Lattner 23330fdc8d8SChris Lattner // CommandObjectFrameSelect 23430fdc8d8SChris Lattner 235ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_select 236ec67e734SRaphael Isemann #include "CommandOptions.inc" 2371f0f5b5bSZachary Turner 238b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed { 23930fdc8d8SChris Lattner public: 240b9c1b51eSKate Stone class CommandOptions : public Options { 241864174e1SGreg Clayton public: 242b9c1b51eSKate Stone CommandOptions() : Options() { OptionParsingStarting(nullptr); } 243864174e1SGreg Clayton 244c8ecc2a9SEugene Zelenko ~CommandOptions() override = default; 245864174e1SGreg Clayton 24697206d57SZachary Turner Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 247b9c1b51eSKate Stone ExecutionContext *execution_context) override { 24897206d57SZachary Turner Status error; 2493bcdfc0eSGreg Clayton const int short_option = m_getopt_table[option_idx].val; 250b9c1b51eSKate Stone switch (short_option) { 251864174e1SGreg Clayton case 'r': 252fe11483bSZachary Turner if (option_arg.getAsInteger(0, relative_frame_offset)) { 253fe11483bSZachary Turner relative_frame_offset = INT32_MIN; 254b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid frame offset argument '%s'", 255fe11483bSZachary Turner option_arg.str().c_str()); 256fe11483bSZachary Turner } 257864174e1SGreg Clayton break; 258864174e1SGreg Clayton 259864174e1SGreg Clayton default: 260b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid short option character '%c'", 261b9c1b51eSKate Stone short_option); 262864174e1SGreg Clayton break; 263864174e1SGreg Clayton } 264864174e1SGreg Clayton 265864174e1SGreg Clayton return error; 266864174e1SGreg Clayton } 267864174e1SGreg Clayton 268b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 269864174e1SGreg Clayton relative_frame_offset = INT32_MIN; 270864174e1SGreg Clayton } 271864174e1SGreg Clayton 2721f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 27370602439SZachary Turner return llvm::makeArrayRef(g_frame_select_options); 2741f0f5b5bSZachary Turner } 275864174e1SGreg Clayton 276864174e1SGreg Clayton int32_t relative_frame_offset; 277864174e1SGreg Clayton }; 278864174e1SGreg Clayton 2797428a18cSKate Stone CommandObjectFrameSelect(CommandInterpreter &interpreter) 2807428a18cSKate Stone : CommandObjectParsed( 281b9c1b51eSKate Stone interpreter, "frame select", "Select the current stack frame by " 282b9c1b51eSKate Stone "index from within the current thread " 283b9c1b51eSKate Stone "(see 'thread backtrace'.)", 284b9c1b51eSKate Stone nullptr, 285b9c1b51eSKate Stone eCommandRequiresThread | eCommandTryTargetAPILock | 286b9c1b51eSKate Stone eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 287b9c1b51eSKate Stone m_options() { 288405fe67fSCaroline Tice CommandArgumentEntry arg; 289405fe67fSCaroline Tice CommandArgumentData index_arg; 290405fe67fSCaroline Tice 291405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 292405fe67fSCaroline Tice index_arg.arg_type = eArgTypeFrameIndex; 293864174e1SGreg Clayton index_arg.arg_repetition = eArgRepeatOptional; 294405fe67fSCaroline Tice 295b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 296b9c1b51eSKate Stone // argument entry. 297405fe67fSCaroline Tice arg.push_back(index_arg); 298405fe67fSCaroline Tice 299405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 300405fe67fSCaroline Tice m_arguments.push_back(arg); 30130fdc8d8SChris Lattner } 30230fdc8d8SChris Lattner 303c8ecc2a9SEugene Zelenko ~CommandObjectFrameSelect() override = default; 30430fdc8d8SChris Lattner 305b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 306864174e1SGreg Clayton 3075a988416SJim Ingham protected: 308b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 309b9c1b51eSKate Stone // No need to check "thread" for validity as eCommandRequiresThread ensures 310b9c1b51eSKate Stone // it is valid 311f9fc609fSGreg Clayton Thread *thread = m_exe_ctx.GetThreadPtr(); 312f9fc609fSGreg Clayton 313864174e1SGreg Clayton uint32_t frame_idx = UINT32_MAX; 314b9c1b51eSKate Stone if (m_options.relative_frame_offset != INT32_MIN) { 315864174e1SGreg Clayton // The one and only argument is a signed relative frame index 316c14ee32dSGreg Clayton frame_idx = thread->GetSelectedFrameIndex(); 317864174e1SGreg Clayton if (frame_idx == UINT32_MAX) 318864174e1SGreg Clayton frame_idx = 0; 319864174e1SGreg Clayton 320b9c1b51eSKate Stone if (m_options.relative_frame_offset < 0) { 3213985c8c6SSaleem Abdulrasool if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset) 322864174e1SGreg Clayton frame_idx += m_options.relative_frame_offset; 323b9c1b51eSKate Stone else { 324b9c1b51eSKate Stone if (frame_idx == 0) { 32505097246SAdrian Prantl // If you are already at the bottom of the stack, then just warn 32605097246SAdrian Prantl // and don't reset the frame. 3277428a18cSKate Stone result.AppendError("Already at the bottom of the stack."); 328213b4546SJim Ingham result.SetStatus(eReturnStatusFailed); 329213b4546SJim Ingham return false; 330b9c1b51eSKate Stone } else 331864174e1SGreg Clayton frame_idx = 0; 332864174e1SGreg Clayton } 333b9c1b51eSKate Stone } else if (m_options.relative_frame_offset > 0) { 334b9c1b51eSKate Stone // I don't want "up 20" where "20" takes you past the top of the stack 335b9c1b51eSKate Stone // to produce 336b9c1b51eSKate Stone // an error, but rather to just go to the top. So I have to count the 337b9c1b51eSKate Stone // stack here... 338b0c72a5fSJim Ingham const uint32_t num_frames = thread->GetStackFrameCount(); 339b9c1b51eSKate Stone if (static_cast<int32_t>(num_frames - frame_idx) > 340b9c1b51eSKate Stone m_options.relative_frame_offset) 341864174e1SGreg Clayton frame_idx += m_options.relative_frame_offset; 342b9c1b51eSKate Stone else { 343b9c1b51eSKate Stone if (frame_idx == num_frames - 1) { 344b9c1b51eSKate Stone // If we are already at the top of the stack, just warn and don't 345b9c1b51eSKate Stone // reset the frame. 3467428a18cSKate Stone result.AppendError("Already at the top of the stack."); 347213b4546SJim Ingham result.SetStatus(eReturnStatusFailed); 348213b4546SJim Ingham return false; 349b9c1b51eSKate Stone } else 350864174e1SGreg Clayton frame_idx = num_frames - 1; 351864174e1SGreg Clayton } 352864174e1SGreg Clayton } 353b9c1b51eSKate Stone } else { 354f965cc86SZachary Turner if (command.GetArgumentCount() > 1) { 355f965cc86SZachary Turner result.AppendErrorWithFormat( 356f965cc86SZachary Turner "too many arguments; expected frame-index, saw '%s'.\n", 357867e7d17SZachary Turner command[0].c_str()); 358f965cc86SZachary Turner m_options.GenerateOptionUsage( 359f965cc86SZachary Turner result.GetErrorStream(), this, 360f965cc86SZachary Turner GetCommandInterpreter().GetDebugger().GetTerminalWidth()); 361f965cc86SZachary Turner return false; 362f965cc86SZachary Turner } 363f965cc86SZachary Turner 364b9c1b51eSKate Stone if (command.GetArgumentCount() == 1) { 365f965cc86SZachary Turner if (command[0].ref.getAsInteger(0, frame_idx)) { 366b9c1b51eSKate Stone result.AppendErrorWithFormat("invalid frame index argument '%s'.", 367f965cc86SZachary Turner command[0].c_str()); 368afbb0af8SJim Ingham result.SetStatus(eReturnStatusFailed); 369afbb0af8SJim Ingham return false; 370afbb0af8SJim Ingham } 371b9c1b51eSKate Stone } else if (command.GetArgumentCount() == 0) { 37282d4a2b9SJason Molenda frame_idx = thread->GetSelectedFrameIndex(); 373b9c1b51eSKate Stone if (frame_idx == UINT32_MAX) { 37482d4a2b9SJason Molenda frame_idx = 0; 37582d4a2b9SJason Molenda } 376864174e1SGreg Clayton } 377864174e1SGreg Clayton } 37830fdc8d8SChris Lattner 379b9c1b51eSKate Stone bool success = thread->SetSelectedFrameByIndexNoisily( 380b9c1b51eSKate Stone frame_idx, result.GetOutputStream()); 381b9c1b51eSKate Stone if (success) { 382f9fc609fSGreg Clayton m_exe_ctx.SetFrameSP(thread->GetSelectedFrame()); 38330fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 384b9c1b51eSKate Stone } else { 385b9c1b51eSKate Stone result.AppendErrorWithFormat("Frame index (%u) out of range.\n", 386b9c1b51eSKate Stone frame_idx); 38730fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 38893208b86SJim Ingham } 38993208b86SJim Ingham 39093208b86SJim Ingham return result.Succeeded(); 39130fdc8d8SChris Lattner } 392864174e1SGreg Clayton 393c8ecc2a9SEugene Zelenko protected: 394864174e1SGreg Clayton CommandOptions m_options; 395864174e1SGreg Clayton }; 396864174e1SGreg Clayton 3976d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable 3986d56d2ceSJim Ingham // List images with associated information 399b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed { 4006d56d2ceSJim Ingham public: 4017428a18cSKate Stone CommandObjectFrameVariable(CommandInterpreter &interpreter) 4027428a18cSKate Stone : CommandObjectParsed( 403b9c1b51eSKate Stone interpreter, "frame variable", 404b9c1b51eSKate Stone "Show variables for the current stack frame. Defaults to all " 4057428a18cSKate Stone "arguments and local variables in scope. Names of argument, " 4067428a18cSKate Stone "local, file static and file global variables can be specified. " 407ed8a705cSGreg Clayton "Children of aggregate variables can be specified such as " 408285ae0c0SJim Ingham "'var->child.x'. The -> and [] operators in 'frame variable' do " 409285ae0c0SJim Ingham "not invoke operator overloads if they exist, but directly access " 410285ae0c0SJim Ingham "the specified element. If you want to trigger operator overloads " 411285ae0c0SJim Ingham "use the expression command to print the variable instead." 412285ae0c0SJim Ingham "\nIt is worth noting that except for overloaded " 413285ae0c0SJim Ingham "operators, when printing local variables 'expr local_var' and " 414285ae0c0SJim Ingham "'frame var local_var' produce the same " 415285ae0c0SJim Ingham "results. However, 'frame variable' is more efficient, since it " 416285ae0c0SJim Ingham "uses debug information and memory reads directly, rather than " 417285ae0c0SJim Ingham "parsing and evaluating an expression, which may even involve " 418285ae0c0SJim Ingham "JITing and running code in the target program.", 419b9c1b51eSKate Stone nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock | 420b9c1b51eSKate Stone eCommandProcessMustBeLaunched | 4217428a18cSKate Stone eCommandProcessMustBePaused | eCommandRequiresProcess), 422e1cfbc79STodd Fiala m_option_group(), 423b9c1b51eSKate Stone m_option_variable( 424b9c1b51eSKate Stone true), // Include the frame specific options by passing "true" 4251deb7962SGreg Clayton m_option_format(eFormatDefault), 426b9c1b51eSKate Stone m_varobj_options() { 427405fe67fSCaroline Tice CommandArgumentEntry arg; 428405fe67fSCaroline Tice CommandArgumentData var_name_arg; 429405fe67fSCaroline Tice 430405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 431405fe67fSCaroline Tice var_name_arg.arg_type = eArgTypeVarName; 432405fe67fSCaroline Tice var_name_arg.arg_repetition = eArgRepeatStar; 433405fe67fSCaroline Tice 434b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 435b9c1b51eSKate Stone // argument entry. 436405fe67fSCaroline Tice arg.push_back(var_name_arg); 437405fe67fSCaroline Tice 438405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 439405fe67fSCaroline Tice m_arguments.push_back(arg); 4402837b766SJim Ingham 441715c2365SGreg Clayton m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 442b9c1b51eSKate Stone m_option_group.Append(&m_option_format, 443b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_FORMAT | 444b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_GDB_FMT, 445b9c1b51eSKate Stone LLDB_OPT_SET_1); 4462837b766SJim Ingham m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 4472837b766SJim Ingham m_option_group.Finalize(); 4486d56d2ceSJim Ingham } 4496d56d2ceSJim Ingham 450c8ecc2a9SEugene Zelenko ~CommandObjectFrameVariable() override = default; 4516d56d2ceSJim Ingham 452b9c1b51eSKate Stone Options *GetOptions() override { return &m_option_group; } 453f21feadcSGreg Clayton 4542443bbd4SRaphael Isemann int HandleArgumentCompletion( 4552443bbd4SRaphael Isemann CompletionRequest &request, 4562443bbd4SRaphael Isemann OptionElementVector &opt_element_vector) override { 457f21feadcSGreg Clayton // Arguments are the standard source file completer. 458b9c1b51eSKate Stone CommandCompletions::InvokeCommonCompletionCallbacks( 459b9c1b51eSKate Stone GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, 460a2e76c0bSRaphael Isemann request, nullptr); 4611a6d7ab5SRaphael Isemann return request.GetNumberOfMatches(); 462f21feadcSGreg Clayton } 4636d56d2ceSJim Ingham 4645a988416SJim Ingham protected: 46573418dfeSEnrico Granata llvm::StringRef GetScopeString(VariableSP var_sp) { 46673418dfeSEnrico Granata if (!var_sp) 46773418dfeSEnrico Granata return llvm::StringRef::withNullAsEmpty(nullptr); 46873418dfeSEnrico Granata 46973418dfeSEnrico Granata switch (var_sp->GetScope()) { 47073418dfeSEnrico Granata case eValueTypeVariableGlobal: 47173418dfeSEnrico Granata return "GLOBAL: "; 47273418dfeSEnrico Granata case eValueTypeVariableStatic: 47373418dfeSEnrico Granata return "STATIC: "; 47473418dfeSEnrico Granata case eValueTypeVariableArgument: 47573418dfeSEnrico Granata return "ARG: "; 47673418dfeSEnrico Granata case eValueTypeVariableLocal: 47773418dfeSEnrico Granata return "LOCAL: "; 47873418dfeSEnrico Granata case eValueTypeVariableThreadLocal: 47973418dfeSEnrico Granata return "THREAD: "; 48073418dfeSEnrico Granata default: 48173418dfeSEnrico Granata break; 48273418dfeSEnrico Granata } 48373418dfeSEnrico Granata 48473418dfeSEnrico Granata return llvm::StringRef::withNullAsEmpty(nullptr); 48573418dfeSEnrico Granata } 48673418dfeSEnrico Granata 487b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 48805097246SAdrian Prantl // No need to check "frame" for validity as eCommandRequiresFrame ensures 48905097246SAdrian Prantl // it is valid 490b57e4a1bSJason Molenda StackFrame *frame = m_exe_ctx.GetFramePtr(); 4911e49e5e7SJohnny Chen 492a134cc1bSGreg Clayton Stream &s = result.GetOutputStream(); 4936d56d2ceSJim Ingham 494b9c1b51eSKate Stone // Be careful about the stack frame, if any summary formatter runs code, it 49505097246SAdrian Prantl // might clear the StackFrameList for the thread. So hold onto a shared 49605097246SAdrian Prantl // pointer to the frame so it stays alive. 497650543f9SJim Ingham 498b9c1b51eSKate Stone VariableList *variable_list = 499b9c1b51eSKate Stone frame->GetVariableList(m_option_variable.show_globals); 500a134cc1bSGreg Clayton 5016d56d2ceSJim Ingham VariableSP var_sp; 5026d56d2ceSJim Ingham ValueObjectSP valobj_sp; 50378a685aaSJim Ingham 504061858ceSEnrico Granata TypeSummaryImplSP summary_format_sp; 50517b11749SEnrico Granata if (!m_option_variable.summary.IsCurrentValueEmpty()) 506b9c1b51eSKate Stone DataVisualization::NamedSummaryFormats::GetSummaryFormat( 507b9c1b51eSKate Stone ConstString(m_option_variable.summary.GetCurrentValue()), 508b9c1b51eSKate Stone summary_format_sp); 50917b11749SEnrico Granata else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 510796ac80bSJonas Devlieghere summary_format_sp = std::make_shared<StringSummaryFormat>( 511b9c1b51eSKate Stone TypeSummaryImpl::Flags(), 512796ac80bSJonas Devlieghere m_option_variable.summary_string.GetCurrentValue()); 513f9fa6ee5SEnrico Granata 514b9c1b51eSKate Stone DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( 515b9c1b51eSKate Stone eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault, 516b9c1b51eSKate Stone summary_format_sp)); 517379447a7SEnrico Granata 518b9c1b51eSKate Stone const SymbolContext &sym_ctx = 519b9c1b51eSKate Stone frame->GetSymbolContext(eSymbolContextFunction); 5206754e04fSEnrico Granata if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 5216754e04fSEnrico Granata m_option_variable.show_globals = true; 5226754e04fSEnrico Granata 523b9c1b51eSKate Stone if (variable_list) { 5241deb7962SGreg Clayton const Format format = m_option_format.GetFormat(); 5250c489f58SEnrico Granata options.SetFormat(format); 5261deb7962SGreg Clayton 52711eb9c64SZachary Turner if (!command.empty()) { 52846747022SGreg Clayton VariableList regex_var_list; 52946747022SGreg Clayton 53005097246SAdrian Prantl // If we have any args to the variable command, we will make variable 53105097246SAdrian Prantl // objects from them... 532f965cc86SZachary Turner for (auto &entry : command) { 533b9c1b51eSKate Stone if (m_option_variable.use_regex) { 534c7bece56SGreg Clayton const size_t regex_start_index = regex_var_list.GetSize(); 535f965cc86SZachary Turner llvm::StringRef name_str = entry.ref; 53695eae423SZachary Turner RegularExpression regex(name_str); 537*f9d90bc5SJan Kratochvil if (regex.IsValid()) { 53846747022SGreg Clayton size_t num_matches = 0; 539b9c1b51eSKate Stone const size_t num_new_regex_vars = 540b9c1b51eSKate Stone variable_list->AppendVariablesIfUnique(regex, regex_var_list, 54178a685aaSJim Ingham num_matches); 542b9c1b51eSKate Stone if (num_new_regex_vars > 0) { 543b9c1b51eSKate Stone for (size_t regex_idx = regex_start_index, 544b9c1b51eSKate Stone end_index = regex_var_list.GetSize(); 545b9c1b51eSKate Stone regex_idx < end_index; ++regex_idx) { 54646747022SGreg Clayton var_sp = regex_var_list.GetVariableAtIndex(regex_idx); 547b9c1b51eSKate Stone if (var_sp) { 548b9c1b51eSKate Stone valobj_sp = frame->GetValueObjectForFrameVariable( 549b9c1b51eSKate Stone var_sp, m_varobj_options.use_dynamic); 550b9c1b51eSKate Stone if (valobj_sp) { 55173418dfeSEnrico Granata std::string scope_string; 55273418dfeSEnrico Granata if (m_option_variable.show_scope) 55373418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 55473418dfeSEnrico Granata 55573418dfeSEnrico Granata if (!scope_string.empty()) 556771ef6d4SMalcolm Parsons s.PutCString(scope_string); 55773418dfeSEnrico Granata 558b9c1b51eSKate Stone if (m_option_variable.show_decl && 559b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 56045ba8543SGreg Clayton bool show_fullpaths = false; 56145ba8543SGreg Clayton bool show_module = true; 562b9c1b51eSKate Stone if (var_sp->DumpDeclaration(&s, show_fullpaths, 563b9c1b51eSKate Stone show_module)) 56446747022SGreg Clayton s.PutCString(": "); 56546747022SGreg Clayton } 5664d93b8cdSEnrico Granata valobj_sp->Dump(result.GetOutputStream(), options); 56746747022SGreg Clayton } 56846747022SGreg Clayton } 56946747022SGreg Clayton } 570b9c1b51eSKate Stone } else if (num_matches == 0) { 571b9c1b51eSKate Stone result.GetErrorStream().Printf("error: no variables matched " 572b9c1b51eSKate Stone "the regular expression '%s'.\n", 573f965cc86SZachary Turner entry.c_str()); 57446747022SGreg Clayton } 575b9c1b51eSKate Stone } else { 5763af3f1e8SJonas Devlieghere if (llvm::Error err = regex.GetError()) 5773af3f1e8SJonas Devlieghere result.GetErrorStream().Printf( 5783af3f1e8SJonas Devlieghere "error: %s\n", llvm::toString(std::move(err)).c_str()); 57946747022SGreg Clayton else 580b9c1b51eSKate Stone result.GetErrorStream().Printf( 581b9c1b51eSKate Stone "error: unknown regex error when compiling '%s'\n", 582f965cc86SZachary Turner entry.c_str()); 58346747022SGreg Clayton } 584b9c1b51eSKate Stone } else // No regex, either exact variable names or variable 585b9c1b51eSKate Stone // expressions. 58646747022SGreg Clayton { 58797206d57SZachary Turner Status error; 588b9c1b51eSKate Stone uint32_t expr_path_options = 589b9c1b51eSKate Stone StackFrame::eExpressionPathOptionCheckPtrVsMember | 59046252398SEnrico Granata StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 59146252398SEnrico Granata StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 5922837b766SJim Ingham lldb::VariableSP var_sp; 593b9c1b51eSKate Stone valobj_sp = frame->GetValueForVariableExpressionPath( 594f965cc86SZachary Turner entry.ref, m_varobj_options.use_dynamic, expr_path_options, 595b9c1b51eSKate Stone var_sp, error); 596b9c1b51eSKate Stone if (valobj_sp) { 59773418dfeSEnrico Granata std::string scope_string; 59873418dfeSEnrico Granata if (m_option_variable.show_scope) 59973418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 60073418dfeSEnrico Granata 60173418dfeSEnrico Granata if (!scope_string.empty()) 602771ef6d4SMalcolm Parsons s.PutCString(scope_string); 603b9c1b51eSKate Stone if (m_option_variable.show_decl && var_sp && 604b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 605a134cc1bSGreg Clayton var_sp->GetDeclaration().DumpStopContext(&s, false); 606a134cc1bSGreg Clayton s.PutCString(": "); 607a134cc1bSGreg Clayton } 6080c489f58SEnrico Granata 6090c489f58SEnrico Granata options.SetFormat(format); 610b9c1b51eSKate Stone options.SetVariableFormatDisplayLanguage( 611b9c1b51eSKate Stone valobj_sp->GetPreferredDisplayLanguage()); 612887062aeSJohnny Chen 613887062aeSJohnny Chen Stream &output_stream = result.GetOutputStream(); 614f965cc86SZachary Turner options.SetRootValueObjectName( 615f965cc86SZachary Turner valobj_sp->GetParent() ? entry.c_str() : nullptr); 6164d93b8cdSEnrico Granata valobj_sp->Dump(output_stream, options); 617b9c1b51eSKate Stone } else { 618c8ecc2a9SEugene Zelenko const char *error_cstr = error.AsCString(nullptr); 61954979cddSGreg Clayton if (error_cstr) 62054979cddSGreg Clayton result.GetErrorStream().Printf("error: %s\n", error_cstr); 62154979cddSGreg Clayton else 622b9c1b51eSKate Stone result.GetErrorStream().Printf("error: unable to find any " 623b9c1b51eSKate Stone "variable expression path that " 624b9c1b51eSKate Stone "matches '%s'.\n", 625f965cc86SZachary Turner entry.c_str()); 6266d56d2ceSJim Ingham } 6276d56d2ceSJim Ingham } 6286d56d2ceSJim Ingham } 629b9c1b51eSKate Stone } else // No command arg specified. Use variable_list, instead. 6306d56d2ceSJim Ingham { 631c7bece56SGreg Clayton const size_t num_variables = variable_list->GetSize(); 632b9c1b51eSKate Stone if (num_variables > 0) { 633b9c1b51eSKate Stone for (size_t i = 0; i < num_variables; i++) { 6341a65ae11SGreg Clayton var_sp = variable_list->GetVariableAtIndex(i); 635f955efc0SSylvestre Ledru switch (var_sp->GetScope()) { 636eb236735SJim Ingham case eValueTypeVariableGlobal: 637eb236735SJim Ingham if (!m_option_variable.show_globals) 638eb236735SJim Ingham continue; 639eb236735SJim Ingham break; 640eb236735SJim Ingham case eValueTypeVariableStatic: 641eb236735SJim Ingham if (!m_option_variable.show_globals) 642eb236735SJim Ingham continue; 643eb236735SJim Ingham break; 644eb236735SJim Ingham case eValueTypeVariableArgument: 645eb236735SJim Ingham if (!m_option_variable.show_args) 646eb236735SJim Ingham continue; 647eb236735SJim Ingham break; 648eb236735SJim Ingham case eValueTypeVariableLocal: 649eb236735SJim Ingham if (!m_option_variable.show_locals) 650eb236735SJim Ingham continue; 651eb236735SJim Ingham break; 652eb236735SJim Ingham default: 653eb236735SJim Ingham continue; 654eb236735SJim Ingham break; 655eb236735SJim Ingham } 656560558ebSEnrico Granata std::string scope_string; 657eb236735SJim Ingham if (m_option_variable.show_scope) 65873418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 6596d56d2ceSJim Ingham 66005097246SAdrian Prantl // Use the variable object code to make sure we are using the same 66105097246SAdrian Prantl // APIs as the public API will be using... 662b9c1b51eSKate Stone valobj_sp = frame->GetValueObjectForFrameVariable( 663b9c1b51eSKate Stone var_sp, m_varobj_options.use_dynamic); 664b9c1b51eSKate Stone if (valobj_sp) { 66505097246SAdrian Prantl // When dumping all variables, don't print any variables that are 66605097246SAdrian Prantl // not in scope to avoid extra unneeded output 667b9c1b51eSKate Stone if (valobj_sp->IsInScope()) { 668b9c1b51eSKate Stone if (!valobj_sp->GetTargetSP() 669b9c1b51eSKate Stone ->GetDisplayRuntimeSupportValues() && 670c8ecc2a9SEugene Zelenko valobj_sp->IsRuntimeSupportValue()) 671560558ebSEnrico Granata continue; 672560558ebSEnrico Granata 673560558ebSEnrico Granata if (!scope_string.empty()) 674771ef6d4SMalcolm Parsons s.PutCString(scope_string); 675560558ebSEnrico Granata 676b9c1b51eSKate Stone if (m_option_variable.show_decl && 677b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 678a134cc1bSGreg Clayton var_sp->GetDeclaration().DumpStopContext(&s, false); 679a134cc1bSGreg Clayton s.PutCString(": "); 680a134cc1bSGreg Clayton } 6810c489f58SEnrico Granata 6820c489f58SEnrico Granata options.SetFormat(format); 683b9c1b51eSKate Stone options.SetVariableFormatDisplayLanguage( 684b9c1b51eSKate Stone valobj_sp->GetPreferredDisplayLanguage()); 685f965cc86SZachary Turner options.SetRootValueObjectName( 686f965cc86SZachary Turner var_sp ? var_sp->GetName().AsCString() : nullptr); 6874d93b8cdSEnrico Granata valobj_sp->Dump(result.GetOutputStream(), options); 688a134cc1bSGreg Clayton } 689a134cc1bSGreg Clayton } 6906d56d2ceSJim Ingham } 6916d56d2ceSJim Ingham } 6926d56d2ceSJim Ingham } 6936d56d2ceSJim Ingham result.SetStatus(eReturnStatusSuccessFinishResult); 6946d56d2ceSJim Ingham } 69561a80ba6SEnrico Granata 69641ae8e74SKuba Mracek if (m_option_variable.show_recognized_args) { 69741ae8e74SKuba Mracek auto recognized_frame = frame->GetRecognizedFrame(); 69841ae8e74SKuba Mracek if (recognized_frame) { 69941ae8e74SKuba Mracek ValueObjectListSP recognized_arg_list = 70041ae8e74SKuba Mracek recognized_frame->GetRecognizedArguments(); 70141ae8e74SKuba Mracek if (recognized_arg_list) { 70241ae8e74SKuba Mracek for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { 70341ae8e74SKuba Mracek options.SetFormat(m_option_format.GetFormat()); 70441ae8e74SKuba Mracek options.SetVariableFormatDisplayLanguage( 70541ae8e74SKuba Mracek rec_value_sp->GetPreferredDisplayLanguage()); 70641ae8e74SKuba Mracek options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); 70741ae8e74SKuba Mracek rec_value_sp->Dump(result.GetOutputStream(), options); 70841ae8e74SKuba Mracek } 70941ae8e74SKuba Mracek } 71041ae8e74SKuba Mracek } 71141ae8e74SKuba Mracek } 71241ae8e74SKuba Mracek 713b9c1b51eSKate Stone if (m_interpreter.TruncationWarningNecessary()) { 71461a80ba6SEnrico Granata result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 71561a80ba6SEnrico Granata m_cmd_name.c_str()); 71661a80ba6SEnrico Granata m_interpreter.TruncationWarningGiven(); 71761a80ba6SEnrico Granata } 71861a80ba6SEnrico Granata 71924fff242SDavide Italiano // Increment statistics. 72024fff242SDavide Italiano bool res = result.Succeeded(); 7210df817aaSDavide Italiano Target *target = GetSelectedOrDummyTarget(); 72224fff242SDavide Italiano if (res) 72324fff242SDavide Italiano target->IncrementStats(StatisticKind::FrameVarSuccess); 72424fff242SDavide Italiano else 72524fff242SDavide Italiano target->IncrementStats(StatisticKind::FrameVarFailure); 72624fff242SDavide Italiano return res; 7276d56d2ceSJim Ingham } 7286d56d2ceSJim Ingham 729c8ecc2a9SEugene Zelenko protected: 7302837b766SJim Ingham OptionGroupOptions m_option_group; 731715c2365SGreg Clayton OptionGroupVariable m_option_variable; 7321deb7962SGreg Clayton OptionGroupFormat m_option_format; 7332837b766SJim Ingham OptionGroupValueObjectDisplay m_varobj_options; 7346d56d2ceSJim Ingham }; 7356d56d2ceSJim Ingham 73641ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer 73741ae8e74SKuba Mracek 738ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_recognizer_add 739ec67e734SRaphael Isemann #include "CommandOptions.inc" 74041ae8e74SKuba Mracek 74141ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { 74241ae8e74SKuba Mracek private: 74341ae8e74SKuba Mracek class CommandOptions : public Options { 74441ae8e74SKuba Mracek public: 74541ae8e74SKuba Mracek CommandOptions() : Options() {} 74641ae8e74SKuba Mracek ~CommandOptions() override = default; 74741ae8e74SKuba Mracek 74841ae8e74SKuba Mracek Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 74941ae8e74SKuba Mracek ExecutionContext *execution_context) override { 75041ae8e74SKuba Mracek Status error; 75141ae8e74SKuba Mracek const int short_option = m_getopt_table[option_idx].val; 75241ae8e74SKuba Mracek 75341ae8e74SKuba Mracek switch (short_option) { 75441ae8e74SKuba Mracek case 'l': 75541ae8e74SKuba Mracek m_class_name = std::string(option_arg); 75641ae8e74SKuba Mracek break; 75741ae8e74SKuba Mracek case 's': 75841ae8e74SKuba Mracek m_module = std::string(option_arg); 75941ae8e74SKuba Mracek break; 76041ae8e74SKuba Mracek case 'n': 76141ae8e74SKuba Mracek m_function = std::string(option_arg); 76241ae8e74SKuba Mracek break; 76341ae8e74SKuba Mracek case 'x': 76441ae8e74SKuba Mracek m_regex = true; 76541ae8e74SKuba Mracek break; 76641ae8e74SKuba Mracek default: 76741ae8e74SKuba Mracek error.SetErrorStringWithFormat("unrecognized option '%c'", 76841ae8e74SKuba Mracek short_option); 76941ae8e74SKuba Mracek break; 77041ae8e74SKuba Mracek } 77141ae8e74SKuba Mracek 77241ae8e74SKuba Mracek return error; 77341ae8e74SKuba Mracek } 77441ae8e74SKuba Mracek 77541ae8e74SKuba Mracek void OptionParsingStarting(ExecutionContext *execution_context) override { 77641ae8e74SKuba Mracek m_module = ""; 77741ae8e74SKuba Mracek m_function = ""; 77841ae8e74SKuba Mracek m_class_name = ""; 77941ae8e74SKuba Mracek m_regex = false; 78041ae8e74SKuba Mracek } 78141ae8e74SKuba Mracek 78241ae8e74SKuba Mracek llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 78341ae8e74SKuba Mracek return llvm::makeArrayRef(g_frame_recognizer_add_options); 78441ae8e74SKuba Mracek } 78541ae8e74SKuba Mracek 78641ae8e74SKuba Mracek // Instance variables to hold the values for command options. 78741ae8e74SKuba Mracek std::string m_class_name; 78841ae8e74SKuba Mracek std::string m_module; 78941ae8e74SKuba Mracek std::string m_function; 79041ae8e74SKuba Mracek bool m_regex; 79141ae8e74SKuba Mracek }; 79241ae8e74SKuba Mracek 79341ae8e74SKuba Mracek CommandOptions m_options; 79441ae8e74SKuba Mracek 79541ae8e74SKuba Mracek Options *GetOptions() override { return &m_options; } 79641ae8e74SKuba Mracek 79741ae8e74SKuba Mracek protected: 79841ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override; 79941ae8e74SKuba Mracek 80041ae8e74SKuba Mracek public: 80141ae8e74SKuba Mracek CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 80241ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer add", 80341ae8e74SKuba Mracek "Add a new frame recognizer.", nullptr), 80441ae8e74SKuba Mracek m_options() { 80541ae8e74SKuba Mracek SetHelpLong(R"( 80641ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on 80741ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source 80841ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments 80941ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments. 81041ae8e74SKuba Mracek 81141ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class 81241ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a 81341ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type 81441ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize. 81541ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that 81641ae8e74SKuba Mracek represent the recognized arguments. 81741ae8e74SKuba Mracek 81841ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc 81941ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows: 82041ae8e74SKuba Mracek 82141ae8e74SKuba Mracek class LibcFdRecognizer(object): 82241ae8e74SKuba Mracek def get_recognized_arguments(self, frame): 82341ae8e74SKuba Mracek if frame.name in ["read", "write", "close"]: 82441ae8e74SKuba Mracek fd = frame.EvaluateExpression("$arg1").unsigned 82541ae8e74SKuba Mracek value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) 82641ae8e74SKuba Mracek return [value] 82741ae8e74SKuba Mracek return [] 82841ae8e74SKuba Mracek 82941ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script 83041ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'. 83141ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is 83241ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 83341ae8e74SKuba Mracek in other modules: 83441ae8e74SKuba Mracek 83541ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py 83641ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 83741ae8e74SKuba Mracek 83841ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we 83941ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable': 84041ae8e74SKuba Mracek 84141ae8e74SKuba Mracek (lldb) b read 84241ae8e74SKuba Mracek (lldb) r 84341ae8e74SKuba Mracek Process 1234 stopped 84441ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 84541ae8e74SKuba Mracek frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 84641ae8e74SKuba Mracek (lldb) frame variable 84741ae8e74SKuba Mracek (int) fd = 3 84841ae8e74SKuba Mracek 84941ae8e74SKuba Mracek )"); 85041ae8e74SKuba Mracek } 85141ae8e74SKuba Mracek ~CommandObjectFrameRecognizerAdd() override = default; 85241ae8e74SKuba Mracek }; 85341ae8e74SKuba Mracek 85441ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 85541ae8e74SKuba Mracek CommandReturnObject &result) { 856f80d2655SKuba Mracek #ifndef LLDB_DISABLE_PYTHON 85741ae8e74SKuba Mracek if (m_options.m_class_name.empty()) { 85841ae8e74SKuba Mracek result.AppendErrorWithFormat( 85941ae8e74SKuba Mracek "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 86041ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 86141ae8e74SKuba Mracek return false; 86241ae8e74SKuba Mracek } 86341ae8e74SKuba Mracek 86441ae8e74SKuba Mracek if (m_options.m_module.empty()) { 86541ae8e74SKuba Mracek result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 86641ae8e74SKuba Mracek m_cmd_name.c_str()); 86741ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 86841ae8e74SKuba Mracek return false; 86941ae8e74SKuba Mracek } 87041ae8e74SKuba Mracek 87141ae8e74SKuba Mracek if (m_options.m_function.empty()) { 87241ae8e74SKuba Mracek result.AppendErrorWithFormat("%s needs a function name (-n argument).\n", 87341ae8e74SKuba Mracek m_cmd_name.c_str()); 87441ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 87541ae8e74SKuba Mracek return false; 87641ae8e74SKuba Mracek } 87741ae8e74SKuba Mracek 8782b29b432SJonas Devlieghere ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 87941ae8e74SKuba Mracek 88041ae8e74SKuba Mracek if (interpreter && 88141ae8e74SKuba Mracek !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 88241ae8e74SKuba Mracek result.AppendWarning( 88341ae8e74SKuba Mracek "The provided class does not exist - please define it " 88441ae8e74SKuba Mracek "before attempting to use this frame recognizer"); 88541ae8e74SKuba Mracek } 88641ae8e74SKuba Mracek 88741ae8e74SKuba Mracek StackFrameRecognizerSP recognizer_sp = 88841ae8e74SKuba Mracek StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 88941ae8e74SKuba Mracek interpreter, m_options.m_class_name.c_str())); 89041ae8e74SKuba Mracek if (m_options.m_regex) { 89141ae8e74SKuba Mracek auto module = 89241ae8e74SKuba Mracek RegularExpressionSP(new RegularExpression(m_options.m_module)); 89341ae8e74SKuba Mracek auto func = 89441ae8e74SKuba Mracek RegularExpressionSP(new RegularExpression(m_options.m_function)); 89541ae8e74SKuba Mracek StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); 89641ae8e74SKuba Mracek } else { 89741ae8e74SKuba Mracek auto module = ConstString(m_options.m_module); 89841ae8e74SKuba Mracek auto func = ConstString(m_options.m_function); 89941ae8e74SKuba Mracek StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); 90041ae8e74SKuba Mracek } 901f80d2655SKuba Mracek #endif 90241ae8e74SKuba Mracek 90341ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishNoResult); 90441ae8e74SKuba Mracek return result.Succeeded(); 90541ae8e74SKuba Mracek } 90641ae8e74SKuba Mracek 90741ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 90841ae8e74SKuba Mracek public: 90941ae8e74SKuba Mracek CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 91041ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer clear", 91141ae8e74SKuba Mracek "Delete all frame recognizers.", nullptr) {} 91241ae8e74SKuba Mracek 91341ae8e74SKuba Mracek ~CommandObjectFrameRecognizerClear() override = default; 91441ae8e74SKuba Mracek 91541ae8e74SKuba Mracek protected: 91641ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 91741ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveAllRecognizers(); 91841ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 91941ae8e74SKuba Mracek return result.Succeeded(); 92041ae8e74SKuba Mracek } 92141ae8e74SKuba Mracek }; 92241ae8e74SKuba Mracek 92341ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 92441ae8e74SKuba Mracek public: 92541ae8e74SKuba Mracek CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 92641ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer delete", 92741ae8e74SKuba Mracek "Delete an existing frame recognizer.", nullptr) {} 92841ae8e74SKuba Mracek 92941ae8e74SKuba Mracek ~CommandObjectFrameRecognizerDelete() override = default; 93041ae8e74SKuba Mracek 93141ae8e74SKuba Mracek protected: 93241ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 93341ae8e74SKuba Mracek if (command.GetArgumentCount() == 0) { 93441ae8e74SKuba Mracek if (!m_interpreter.Confirm( 93541ae8e74SKuba Mracek "About to delete all frame recognizers, do you want to do that?", 93641ae8e74SKuba Mracek true)) { 93741ae8e74SKuba Mracek result.AppendMessage("Operation cancelled..."); 93841ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 93941ae8e74SKuba Mracek return false; 94041ae8e74SKuba Mracek } 94141ae8e74SKuba Mracek 94241ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveAllRecognizers(); 94341ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 94441ae8e74SKuba Mracek return result.Succeeded(); 94541ae8e74SKuba Mracek } 94641ae8e74SKuba Mracek 94741ae8e74SKuba Mracek if (command.GetArgumentCount() != 1) { 94841ae8e74SKuba Mracek result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 94941ae8e74SKuba Mracek m_cmd_name.c_str()); 95041ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 95141ae8e74SKuba Mracek return false; 95241ae8e74SKuba Mracek } 95341ae8e74SKuba Mracek 95441ae8e74SKuba Mracek uint32_t recognizer_id = 95541ae8e74SKuba Mracek StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 95641ae8e74SKuba Mracek 95741ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id); 95841ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 95941ae8e74SKuba Mracek return result.Succeeded(); 96041ae8e74SKuba Mracek } 96141ae8e74SKuba Mracek }; 96241ae8e74SKuba Mracek 96341ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed { 96441ae8e74SKuba Mracek public: 96541ae8e74SKuba Mracek CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 96641ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer list", 96741ae8e74SKuba Mracek "Show a list of active frame recognizers.", 96841ae8e74SKuba Mracek nullptr) {} 96941ae8e74SKuba Mracek 97041ae8e74SKuba Mracek ~CommandObjectFrameRecognizerList() override = default; 97141ae8e74SKuba Mracek 97241ae8e74SKuba Mracek protected: 97341ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 97441ae8e74SKuba Mracek bool any_printed = false; 97541ae8e74SKuba Mracek StackFrameRecognizerManager::ForEach( 97641ae8e74SKuba Mracek [&result, &any_printed](uint32_t recognizer_id, std::string name, 97741ae8e74SKuba Mracek std::string function, std::string symbol, 97841ae8e74SKuba Mracek bool regexp) { 97941ae8e74SKuba Mracek if (name == "") name = "(internal)"; 98041ae8e74SKuba Mracek result.GetOutputStream().Printf( 98141ae8e74SKuba Mracek "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(), 98241ae8e74SKuba Mracek function.c_str(), symbol.c_str(), regexp ? " (regexp)" : ""); 98341ae8e74SKuba Mracek any_printed = true; 98441ae8e74SKuba Mracek }); 98541ae8e74SKuba Mracek 98641ae8e74SKuba Mracek if (any_printed) 98741ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 98841ae8e74SKuba Mracek else { 98941ae8e74SKuba Mracek result.GetOutputStream().PutCString("no matching results found.\n"); 99041ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishNoResult); 99141ae8e74SKuba Mracek } 99241ae8e74SKuba Mracek return result.Succeeded(); 99341ae8e74SKuba Mracek } 99441ae8e74SKuba Mracek }; 99541ae8e74SKuba Mracek 99641ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 99741ae8e74SKuba Mracek public: 99841ae8e74SKuba Mracek CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 99941ae8e74SKuba Mracek : CommandObjectParsed( 100041ae8e74SKuba Mracek interpreter, "frame recognizer info", 100141ae8e74SKuba Mracek "Show which frame recognizer is applied a stack frame (if any).", 100241ae8e74SKuba Mracek nullptr) { 100341ae8e74SKuba Mracek CommandArgumentEntry arg; 100441ae8e74SKuba Mracek CommandArgumentData index_arg; 100541ae8e74SKuba Mracek 100641ae8e74SKuba Mracek // Define the first (and only) variant of this arg. 100741ae8e74SKuba Mracek index_arg.arg_type = eArgTypeFrameIndex; 100841ae8e74SKuba Mracek index_arg.arg_repetition = eArgRepeatPlain; 100941ae8e74SKuba Mracek 101041ae8e74SKuba Mracek // There is only one variant this argument could be; put it into the 101141ae8e74SKuba Mracek // argument entry. 101241ae8e74SKuba Mracek arg.push_back(index_arg); 101341ae8e74SKuba Mracek 101441ae8e74SKuba Mracek // Push the data for the first argument into the m_arguments vector. 101541ae8e74SKuba Mracek m_arguments.push_back(arg); 101641ae8e74SKuba Mracek } 101741ae8e74SKuba Mracek 101841ae8e74SKuba Mracek ~CommandObjectFrameRecognizerInfo() override = default; 101941ae8e74SKuba Mracek 102041ae8e74SKuba Mracek protected: 102141ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 102241ae8e74SKuba Mracek Process *process = m_exe_ctx.GetProcessPtr(); 102341ae8e74SKuba Mracek if (process == nullptr) { 102441ae8e74SKuba Mracek result.AppendError("no process"); 102541ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 102641ae8e74SKuba Mracek return false; 102741ae8e74SKuba Mracek } 102841ae8e74SKuba Mracek Thread *thread = m_exe_ctx.GetThreadPtr(); 102941ae8e74SKuba Mracek if (thread == nullptr) { 103041ae8e74SKuba Mracek result.AppendError("no thread"); 103141ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 103241ae8e74SKuba Mracek return false; 103341ae8e74SKuba Mracek } 103441ae8e74SKuba Mracek if (command.GetArgumentCount() != 1) { 103541ae8e74SKuba Mracek result.AppendErrorWithFormat( 103641ae8e74SKuba Mracek "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 103741ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 103841ae8e74SKuba Mracek return false; 103941ae8e74SKuba Mracek } 104041ae8e74SKuba Mracek 104141ae8e74SKuba Mracek uint32_t frame_index = 104241ae8e74SKuba Mracek StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 104341ae8e74SKuba Mracek StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 104441ae8e74SKuba Mracek if (!frame_sp) { 104541ae8e74SKuba Mracek result.AppendErrorWithFormat("no frame with index %u", frame_index); 104641ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 104741ae8e74SKuba Mracek return false; 104841ae8e74SKuba Mracek } 104941ae8e74SKuba Mracek 105041ae8e74SKuba Mracek auto recognizer = 105141ae8e74SKuba Mracek StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp); 105241ae8e74SKuba Mracek 105341ae8e74SKuba Mracek Stream &output_stream = result.GetOutputStream(); 105441ae8e74SKuba Mracek output_stream.Printf("frame %d ", frame_index); 105541ae8e74SKuba Mracek if (recognizer) { 105641ae8e74SKuba Mracek output_stream << "is recognized by "; 105741ae8e74SKuba Mracek output_stream << recognizer->GetName(); 105841ae8e74SKuba Mracek } else { 105941ae8e74SKuba Mracek output_stream << "not recognized by any recognizer"; 106041ae8e74SKuba Mracek } 106141ae8e74SKuba Mracek output_stream.EOL(); 106241ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 106341ae8e74SKuba Mracek return result.Succeeded(); 106441ae8e74SKuba Mracek } 106541ae8e74SKuba Mracek }; 106641ae8e74SKuba Mracek 106741ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword { 106841ae8e74SKuba Mracek public: 106941ae8e74SKuba Mracek CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 107041ae8e74SKuba Mracek : CommandObjectMultiword( 107141ae8e74SKuba Mracek interpreter, "frame recognizer", 107241ae8e74SKuba Mracek "Commands for editing and viewing frame recognizers.", 107341ae8e74SKuba Mracek "frame recognizer [<sub-command-options>] ") { 107441ae8e74SKuba Mracek LoadSubCommand( 107541ae8e74SKuba Mracek "add", 107641ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter))); 107741ae8e74SKuba Mracek LoadSubCommand( 107841ae8e74SKuba Mracek "clear", 107941ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 108041ae8e74SKuba Mracek LoadSubCommand( 108141ae8e74SKuba Mracek "delete", 108241ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 108341ae8e74SKuba Mracek LoadSubCommand( 108441ae8e74SKuba Mracek "list", 108541ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter))); 108641ae8e74SKuba Mracek LoadSubCommand( 108741ae8e74SKuba Mracek "info", 108841ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerInfo(interpreter))); 108941ae8e74SKuba Mracek } 109041ae8e74SKuba Mracek 109141ae8e74SKuba Mracek ~CommandObjectFrameRecognizer() override = default; 109241ae8e74SKuba Mracek }; 109341ae8e74SKuba Mracek 109430fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame 109530fdc8d8SChris Lattner 109630fdc8d8SChris Lattner // CommandObjectMultiwordFrame 109730fdc8d8SChris Lattner 1098b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1099b9c1b51eSKate Stone CommandInterpreter &interpreter) 1100b9c1b51eSKate Stone : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and " 1101b9c1b51eSKate Stone "examing the current " 1102b9c1b51eSKate Stone "thread's stack frames.", 1103b9c1b51eSKate Stone "frame <subcommand> [<subcommand-options>]") { 1104b9c1b51eSKate Stone LoadSubCommand("diagnose", 1105b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1106b9c1b51eSKate Stone LoadSubCommand("info", 1107b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1108b9c1b51eSKate Stone LoadSubCommand("select", 1109b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1110b9c1b51eSKate Stone LoadSubCommand("variable", 1111b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 111241ae8e74SKuba Mracek #ifndef LLDB_DISABLE_PYTHON 111341ae8e74SKuba Mracek LoadSubCommand( 111441ae8e74SKuba Mracek "recognizer", 111541ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizer(interpreter))); 111641ae8e74SKuba Mracek #endif 111730fdc8d8SChris Lattner } 111830fdc8d8SChris Lattner 1119c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1120