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: 9536162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 964740a734SSean Callanan } 974740a734SSean Callanan 984740a734SSean Callanan return error; 994740a734SSean Callanan } 1004740a734SSean Callanan 101b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 1024740a734SSean Callanan address.reset(); 1034740a734SSean Callanan reg.reset(); 1044740a734SSean Callanan offset.reset(); 1054740a734SSean Callanan } 1064740a734SSean Callanan 1071f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 10870602439SZachary Turner return llvm::makeArrayRef(g_frame_diag_options); 1091f0f5b5bSZachary Turner } 1104740a734SSean Callanan 1114740a734SSean Callanan // Options. 1124740a734SSean Callanan llvm::Optional<lldb::addr_t> address; 1134740a734SSean Callanan llvm::Optional<ConstString> reg; 1144740a734SSean Callanan llvm::Optional<int64_t> offset; 1154740a734SSean Callanan }; 1164740a734SSean Callanan 1174740a734SSean Callanan CommandObjectFrameDiagnose(CommandInterpreter &interpreter) 1184740a734SSean Callanan : CommandObjectParsed(interpreter, "frame diagnose", 119b9c1b51eSKate Stone "Try to determine what path path the current stop " 120b9c1b51eSKate Stone "location used to get to a register or address", 121b9c1b51eSKate Stone nullptr, 122b9c1b51eSKate Stone eCommandRequiresThread | eCommandTryTargetAPILock | 123b9c1b51eSKate Stone eCommandProcessMustBeLaunched | 1244740a734SSean Callanan eCommandProcessMustBePaused), 125b9c1b51eSKate Stone m_options() { 1264740a734SSean Callanan CommandArgumentEntry arg; 1274740a734SSean Callanan CommandArgumentData index_arg; 1284740a734SSean Callanan 1294740a734SSean Callanan // Define the first (and only) variant of this arg. 1304740a734SSean Callanan index_arg.arg_type = eArgTypeFrameIndex; 1314740a734SSean Callanan index_arg.arg_repetition = eArgRepeatOptional; 1324740a734SSean Callanan 133b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 134b9c1b51eSKate Stone // argument entry. 1354740a734SSean Callanan arg.push_back(index_arg); 1364740a734SSean Callanan 1374740a734SSean Callanan // Push the data for the first argument into the m_arguments vector. 1384740a734SSean Callanan m_arguments.push_back(arg); 1394740a734SSean Callanan } 1404740a734SSean Callanan 1414740a734SSean Callanan ~CommandObjectFrameDiagnose() override = default; 1424740a734SSean Callanan 143b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 1444740a734SSean Callanan 1454740a734SSean Callanan protected: 146b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 1474740a734SSean Callanan Thread *thread = m_exe_ctx.GetThreadPtr(); 1484740a734SSean Callanan StackFrameSP frame_sp = thread->GetSelectedFrame(); 1494740a734SSean Callanan 1504740a734SSean Callanan ValueObjectSP valobj_sp; 1514740a734SSean Callanan 152b9c1b51eSKate Stone if (m_options.address.hasValue()) { 153b9c1b51eSKate Stone if (m_options.reg.hasValue() || m_options.offset.hasValue()) { 154b9c1b51eSKate Stone result.AppendError( 155b9c1b51eSKate Stone "`frame diagnose --address` is incompatible with other arguments."); 1564740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1574740a734SSean Callanan return false; 1584740a734SSean Callanan } 1594740a734SSean Callanan valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue()); 160b9c1b51eSKate Stone } else if (m_options.reg.hasValue()) { 161b9c1b51eSKate Stone valobj_sp = frame_sp->GuessValueForRegisterAndOffset( 162b9c1b51eSKate Stone m_options.reg.getValue(), m_options.offset.getValueOr(0)); 163b9c1b51eSKate Stone } else { 1644740a734SSean Callanan StopInfoSP stop_info_sp = thread->GetStopInfo(); 165b9c1b51eSKate Stone if (!stop_info_sp) { 1664740a734SSean Callanan result.AppendError("No arguments provided, and no stop info."); 1674740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1684740a734SSean Callanan return false; 1694740a734SSean Callanan } 1704740a734SSean Callanan 1714740a734SSean Callanan valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp); 1724740a734SSean Callanan } 1734740a734SSean Callanan 174b9c1b51eSKate Stone if (!valobj_sp) { 1754740a734SSean Callanan result.AppendError("No diagnosis available."); 1764740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1774740a734SSean Callanan return false; 1784740a734SSean Callanan } 1794740a734SSean Callanan 1804740a734SSean Callanan 1813bc714b2SZachary Turner DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp]( 1823bc714b2SZachary Turner ConstString type, ConstString var, const DumpValueObjectOptions &opts, 1833bc714b2SZachary Turner Stream &stream) -> bool { 184b9c1b51eSKate Stone const ValueObject::GetExpressionPathFormat format = ValueObject:: 185b9c1b51eSKate Stone GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers; 1865d1f711aSPavel Labath const bool qualify_cxx_base_classes = false; 1874740a734SSean Callanan valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format); 1884740a734SSean Callanan stream.PutCString(" ="); 1894740a734SSean Callanan return true; 1904740a734SSean Callanan }; 1914740a734SSean Callanan 1924740a734SSean Callanan DumpValueObjectOptions options; 1934740a734SSean Callanan options.SetDeclPrintingHelper(helper); 194b9c1b51eSKate Stone ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), 195b9c1b51eSKate Stone options); 1964740a734SSean Callanan printer.PrintValueObject(); 1974740a734SSean Callanan 1984740a734SSean Callanan return true; 1994740a734SSean Callanan } 2004740a734SSean Callanan 2014740a734SSean Callanan protected: 2024740a734SSean Callanan CommandOptions m_options; 2034740a734SSean Callanan }; 2044740a734SSean Callanan 20530fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo 20630fdc8d8SChris Lattner 20730fdc8d8SChris Lattner // CommandObjectFrameInfo 20830fdc8d8SChris Lattner 209b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed { 21030fdc8d8SChris Lattner public: 2117428a18cSKate Stone CommandObjectFrameInfo(CommandInterpreter &interpreter) 212b9c1b51eSKate Stone : CommandObjectParsed( 213b9c1b51eSKate Stone interpreter, "frame info", "List information about the current " 214b9c1b51eSKate Stone "stack frame in the current thread.", 215b9c1b51eSKate Stone "frame info", 216b9c1b51eSKate Stone eCommandRequiresFrame | eCommandTryTargetAPILock | 217b9c1b51eSKate Stone eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {} 21830fdc8d8SChris Lattner 219c8ecc2a9SEugene Zelenko ~CommandObjectFrameInfo() override = default; 22030fdc8d8SChris Lattner 2215a988416SJim Ingham protected: 222b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 223f9fc609fSGreg Clayton m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream()); 22430fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 22530fdc8d8SChris Lattner return result.Succeeded(); 22630fdc8d8SChris Lattner } 22730fdc8d8SChris Lattner }; 22830fdc8d8SChris Lattner 22930fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect 23030fdc8d8SChris Lattner 23130fdc8d8SChris Lattner // CommandObjectFrameSelect 23230fdc8d8SChris Lattner 233ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_select 234ec67e734SRaphael Isemann #include "CommandOptions.inc" 2351f0f5b5bSZachary Turner 236b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed { 23730fdc8d8SChris Lattner public: 238b9c1b51eSKate Stone class CommandOptions : public Options { 239864174e1SGreg Clayton public: 240b9c1b51eSKate Stone CommandOptions() : Options() { OptionParsingStarting(nullptr); } 241864174e1SGreg Clayton 242c8ecc2a9SEugene Zelenko ~CommandOptions() override = default; 243864174e1SGreg Clayton 24497206d57SZachary Turner Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 245b9c1b51eSKate Stone ExecutionContext *execution_context) override { 24697206d57SZachary Turner Status error; 2473bcdfc0eSGreg Clayton const int short_option = m_getopt_table[option_idx].val; 248b9c1b51eSKate Stone switch (short_option) { 249*607c92afSRaphael Isemann case 'r': { 250*607c92afSRaphael Isemann int32_t offset = 0; 251*607c92afSRaphael Isemann if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) { 252b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid frame offset argument '%s'", 253fe11483bSZachary Turner option_arg.str().c_str()); 254*607c92afSRaphael Isemann } else 255*607c92afSRaphael Isemann relative_frame_offset = offset; 256864174e1SGreg Clayton break; 257*607c92afSRaphael Isemann } 258864174e1SGreg Clayton 259864174e1SGreg Clayton default: 26036162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 261864174e1SGreg Clayton } 262864174e1SGreg Clayton 263864174e1SGreg Clayton return error; 264864174e1SGreg Clayton } 265864174e1SGreg Clayton 266*607c92afSRaphael Isemann void OptionParsingStarting(ExecutionContext *execution_context) override {} 267864174e1SGreg Clayton 2681f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 26970602439SZachary Turner return llvm::makeArrayRef(g_frame_select_options); 2701f0f5b5bSZachary Turner } 271864174e1SGreg Clayton 272*607c92afSRaphael Isemann llvm::Optional<int32_t> relative_frame_offset; 273864174e1SGreg Clayton }; 274864174e1SGreg Clayton 2757428a18cSKate Stone CommandObjectFrameSelect(CommandInterpreter &interpreter) 2767428a18cSKate Stone : CommandObjectParsed( 277b9c1b51eSKate Stone interpreter, "frame select", "Select the current stack frame by " 278b9c1b51eSKate Stone "index from within the current thread " 279b9c1b51eSKate Stone "(see 'thread backtrace'.)", 280b9c1b51eSKate Stone nullptr, 281b9c1b51eSKate Stone eCommandRequiresThread | eCommandTryTargetAPILock | 282b9c1b51eSKate Stone eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), 283b9c1b51eSKate Stone m_options() { 284405fe67fSCaroline Tice CommandArgumentEntry arg; 285405fe67fSCaroline Tice CommandArgumentData index_arg; 286405fe67fSCaroline Tice 287405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 288405fe67fSCaroline Tice index_arg.arg_type = eArgTypeFrameIndex; 289864174e1SGreg Clayton index_arg.arg_repetition = eArgRepeatOptional; 290405fe67fSCaroline Tice 291b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 292b9c1b51eSKate Stone // argument entry. 293405fe67fSCaroline Tice arg.push_back(index_arg); 294405fe67fSCaroline Tice 295405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 296405fe67fSCaroline Tice m_arguments.push_back(arg); 29730fdc8d8SChris Lattner } 29830fdc8d8SChris Lattner 299c8ecc2a9SEugene Zelenko ~CommandObjectFrameSelect() override = default; 30030fdc8d8SChris Lattner 301b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 302864174e1SGreg Clayton 3035a988416SJim Ingham protected: 304b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 305b9c1b51eSKate Stone // No need to check "thread" for validity as eCommandRequiresThread ensures 306b9c1b51eSKate Stone // it is valid 307f9fc609fSGreg Clayton Thread *thread = m_exe_ctx.GetThreadPtr(); 308f9fc609fSGreg Clayton 309864174e1SGreg Clayton uint32_t frame_idx = UINT32_MAX; 310*607c92afSRaphael Isemann if (m_options.relative_frame_offset.hasValue()) { 311864174e1SGreg Clayton // The one and only argument is a signed relative frame index 312c14ee32dSGreg Clayton frame_idx = thread->GetSelectedFrameIndex(); 313864174e1SGreg Clayton if (frame_idx == UINT32_MAX) 314864174e1SGreg Clayton frame_idx = 0; 315864174e1SGreg Clayton 316*607c92afSRaphael Isemann if (*m_options.relative_frame_offset < 0) { 317*607c92afSRaphael Isemann if (static_cast<int32_t>(frame_idx) >= -*m_options.relative_frame_offset) 318*607c92afSRaphael Isemann frame_idx += *m_options.relative_frame_offset; 319b9c1b51eSKate Stone else { 320b9c1b51eSKate Stone if (frame_idx == 0) { 32105097246SAdrian Prantl // If you are already at the bottom of the stack, then just warn 32205097246SAdrian Prantl // and don't reset the frame. 3237428a18cSKate Stone result.AppendError("Already at the bottom of the stack."); 324213b4546SJim Ingham result.SetStatus(eReturnStatusFailed); 325213b4546SJim Ingham return false; 326b9c1b51eSKate Stone } else 327864174e1SGreg Clayton frame_idx = 0; 328864174e1SGreg Clayton } 329*607c92afSRaphael Isemann } else if (*m_options.relative_frame_offset > 0) { 330b9c1b51eSKate Stone // I don't want "up 20" where "20" takes you past the top of the stack 331b9c1b51eSKate Stone // to produce 332b9c1b51eSKate Stone // an error, but rather to just go to the top. So I have to count the 333b9c1b51eSKate Stone // stack here... 334b0c72a5fSJim Ingham const uint32_t num_frames = thread->GetStackFrameCount(); 335b9c1b51eSKate Stone if (static_cast<int32_t>(num_frames - frame_idx) > 336*607c92afSRaphael Isemann *m_options.relative_frame_offset) 337*607c92afSRaphael Isemann frame_idx += *m_options.relative_frame_offset; 338b9c1b51eSKate Stone else { 339b9c1b51eSKate Stone if (frame_idx == num_frames - 1) { 340b9c1b51eSKate Stone // If we are already at the top of the stack, just warn and don't 341b9c1b51eSKate Stone // reset the frame. 3427428a18cSKate Stone result.AppendError("Already at the top of the stack."); 343213b4546SJim Ingham result.SetStatus(eReturnStatusFailed); 344213b4546SJim Ingham return false; 345b9c1b51eSKate Stone } else 346864174e1SGreg Clayton frame_idx = num_frames - 1; 347864174e1SGreg Clayton } 348864174e1SGreg Clayton } 349b9c1b51eSKate Stone } else { 350f965cc86SZachary Turner if (command.GetArgumentCount() > 1) { 351f965cc86SZachary Turner result.AppendErrorWithFormat( 352f965cc86SZachary Turner "too many arguments; expected frame-index, saw '%s'.\n", 353867e7d17SZachary Turner command[0].c_str()); 354f965cc86SZachary Turner m_options.GenerateOptionUsage( 355f965cc86SZachary Turner result.GetErrorStream(), this, 356f965cc86SZachary Turner GetCommandInterpreter().GetDebugger().GetTerminalWidth()); 357f965cc86SZachary Turner return false; 358f965cc86SZachary Turner } 359f965cc86SZachary Turner 360b9c1b51eSKate Stone if (command.GetArgumentCount() == 1) { 361f965cc86SZachary Turner if (command[0].ref.getAsInteger(0, frame_idx)) { 362b9c1b51eSKate Stone result.AppendErrorWithFormat("invalid frame index argument '%s'.", 363f965cc86SZachary Turner command[0].c_str()); 364afbb0af8SJim Ingham result.SetStatus(eReturnStatusFailed); 365afbb0af8SJim Ingham return false; 366afbb0af8SJim Ingham } 367b9c1b51eSKate Stone } else if (command.GetArgumentCount() == 0) { 36882d4a2b9SJason Molenda frame_idx = thread->GetSelectedFrameIndex(); 369b9c1b51eSKate Stone if (frame_idx == UINT32_MAX) { 37082d4a2b9SJason Molenda frame_idx = 0; 37182d4a2b9SJason Molenda } 372864174e1SGreg Clayton } 373864174e1SGreg Clayton } 37430fdc8d8SChris Lattner 375b9c1b51eSKate Stone bool success = thread->SetSelectedFrameByIndexNoisily( 376b9c1b51eSKate Stone frame_idx, result.GetOutputStream()); 377b9c1b51eSKate Stone if (success) { 378f9fc609fSGreg Clayton m_exe_ctx.SetFrameSP(thread->GetSelectedFrame()); 37930fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 380b9c1b51eSKate Stone } else { 381b9c1b51eSKate Stone result.AppendErrorWithFormat("Frame index (%u) out of range.\n", 382b9c1b51eSKate Stone frame_idx); 38330fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 38493208b86SJim Ingham } 38593208b86SJim Ingham 38693208b86SJim Ingham return result.Succeeded(); 38730fdc8d8SChris Lattner } 388864174e1SGreg Clayton 389c8ecc2a9SEugene Zelenko protected: 390864174e1SGreg Clayton CommandOptions m_options; 391864174e1SGreg Clayton }; 392864174e1SGreg Clayton 3936d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable 3946d56d2ceSJim Ingham // List images with associated information 395b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed { 3966d56d2ceSJim Ingham public: 3977428a18cSKate Stone CommandObjectFrameVariable(CommandInterpreter &interpreter) 3987428a18cSKate Stone : CommandObjectParsed( 399b9c1b51eSKate Stone interpreter, "frame variable", 400b9c1b51eSKate Stone "Show variables for the current stack frame. Defaults to all " 4017428a18cSKate Stone "arguments and local variables in scope. Names of argument, " 4027428a18cSKate Stone "local, file static and file global variables can be specified. " 403ed8a705cSGreg Clayton "Children of aggregate variables can be specified such as " 404285ae0c0SJim Ingham "'var->child.x'. The -> and [] operators in 'frame variable' do " 405285ae0c0SJim Ingham "not invoke operator overloads if they exist, but directly access " 406285ae0c0SJim Ingham "the specified element. If you want to trigger operator overloads " 407285ae0c0SJim Ingham "use the expression command to print the variable instead." 408285ae0c0SJim Ingham "\nIt is worth noting that except for overloaded " 409285ae0c0SJim Ingham "operators, when printing local variables 'expr local_var' and " 410285ae0c0SJim Ingham "'frame var local_var' produce the same " 411285ae0c0SJim Ingham "results. However, 'frame variable' is more efficient, since it " 412285ae0c0SJim Ingham "uses debug information and memory reads directly, rather than " 413285ae0c0SJim Ingham "parsing and evaluating an expression, which may even involve " 414285ae0c0SJim Ingham "JITing and running code in the target program.", 415b9c1b51eSKate Stone nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock | 416b9c1b51eSKate Stone eCommandProcessMustBeLaunched | 4177428a18cSKate Stone eCommandProcessMustBePaused | eCommandRequiresProcess), 418e1cfbc79STodd Fiala m_option_group(), 419b9c1b51eSKate Stone m_option_variable( 420b9c1b51eSKate Stone true), // Include the frame specific options by passing "true" 4211deb7962SGreg Clayton m_option_format(eFormatDefault), 422b9c1b51eSKate Stone m_varobj_options() { 423405fe67fSCaroline Tice CommandArgumentEntry arg; 424405fe67fSCaroline Tice CommandArgumentData var_name_arg; 425405fe67fSCaroline Tice 426405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 427405fe67fSCaroline Tice var_name_arg.arg_type = eArgTypeVarName; 428405fe67fSCaroline Tice var_name_arg.arg_repetition = eArgRepeatStar; 429405fe67fSCaroline Tice 430b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 431b9c1b51eSKate Stone // argument entry. 432405fe67fSCaroline Tice arg.push_back(var_name_arg); 433405fe67fSCaroline Tice 434405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 435405fe67fSCaroline Tice m_arguments.push_back(arg); 4362837b766SJim Ingham 437715c2365SGreg Clayton m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 438b9c1b51eSKate Stone m_option_group.Append(&m_option_format, 439b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_FORMAT | 440b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_GDB_FMT, 441b9c1b51eSKate Stone LLDB_OPT_SET_1); 4422837b766SJim Ingham m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 4432837b766SJim Ingham m_option_group.Finalize(); 4446d56d2ceSJim Ingham } 4456d56d2ceSJim Ingham 446c8ecc2a9SEugene Zelenko ~CommandObjectFrameVariable() override = default; 4476d56d2ceSJim Ingham 448b9c1b51eSKate Stone Options *GetOptions() override { return &m_option_group; } 449f21feadcSGreg Clayton 450ae34ed2cSRaphael Isemann void 451ae34ed2cSRaphael Isemann HandleArgumentCompletion(CompletionRequest &request, 4522443bbd4SRaphael Isemann OptionElementVector &opt_element_vector) override { 453f21feadcSGreg Clayton // Arguments are the standard source file completer. 454b9c1b51eSKate Stone CommandCompletions::InvokeCommonCompletionCallbacks( 455b9c1b51eSKate Stone GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, 456a2e76c0bSRaphael Isemann request, nullptr); 457f21feadcSGreg Clayton } 4586d56d2ceSJim Ingham 4595a988416SJim Ingham protected: 46073418dfeSEnrico Granata llvm::StringRef GetScopeString(VariableSP var_sp) { 46173418dfeSEnrico Granata if (!var_sp) 46273418dfeSEnrico Granata return llvm::StringRef::withNullAsEmpty(nullptr); 46373418dfeSEnrico Granata 46473418dfeSEnrico Granata switch (var_sp->GetScope()) { 46573418dfeSEnrico Granata case eValueTypeVariableGlobal: 46673418dfeSEnrico Granata return "GLOBAL: "; 46773418dfeSEnrico Granata case eValueTypeVariableStatic: 46873418dfeSEnrico Granata return "STATIC: "; 46973418dfeSEnrico Granata case eValueTypeVariableArgument: 47073418dfeSEnrico Granata return "ARG: "; 47173418dfeSEnrico Granata case eValueTypeVariableLocal: 47273418dfeSEnrico Granata return "LOCAL: "; 47373418dfeSEnrico Granata case eValueTypeVariableThreadLocal: 47473418dfeSEnrico Granata return "THREAD: "; 47573418dfeSEnrico Granata default: 47673418dfeSEnrico Granata break; 47773418dfeSEnrico Granata } 47873418dfeSEnrico Granata 47973418dfeSEnrico Granata return llvm::StringRef::withNullAsEmpty(nullptr); 48073418dfeSEnrico Granata } 48173418dfeSEnrico Granata 482b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 48305097246SAdrian Prantl // No need to check "frame" for validity as eCommandRequiresFrame ensures 48405097246SAdrian Prantl // it is valid 485b57e4a1bSJason Molenda StackFrame *frame = m_exe_ctx.GetFramePtr(); 4861e49e5e7SJohnny Chen 487a134cc1bSGreg Clayton Stream &s = result.GetOutputStream(); 4886d56d2ceSJim Ingham 489b9c1b51eSKate Stone // Be careful about the stack frame, if any summary formatter runs code, it 49005097246SAdrian Prantl // might clear the StackFrameList for the thread. So hold onto a shared 49105097246SAdrian Prantl // pointer to the frame so it stays alive. 492650543f9SJim Ingham 493b9c1b51eSKate Stone VariableList *variable_list = 494b9c1b51eSKate Stone frame->GetVariableList(m_option_variable.show_globals); 495a134cc1bSGreg Clayton 4966d56d2ceSJim Ingham VariableSP var_sp; 4976d56d2ceSJim Ingham ValueObjectSP valobj_sp; 49878a685aaSJim Ingham 499061858ceSEnrico Granata TypeSummaryImplSP summary_format_sp; 50017b11749SEnrico Granata if (!m_option_variable.summary.IsCurrentValueEmpty()) 501b9c1b51eSKate Stone DataVisualization::NamedSummaryFormats::GetSummaryFormat( 502b9c1b51eSKate Stone ConstString(m_option_variable.summary.GetCurrentValue()), 503b9c1b51eSKate Stone summary_format_sp); 50417b11749SEnrico Granata else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 505796ac80bSJonas Devlieghere summary_format_sp = std::make_shared<StringSummaryFormat>( 506b9c1b51eSKate Stone TypeSummaryImpl::Flags(), 507796ac80bSJonas Devlieghere m_option_variable.summary_string.GetCurrentValue()); 508f9fa6ee5SEnrico Granata 509b9c1b51eSKate Stone DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( 510b9c1b51eSKate Stone eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault, 511b9c1b51eSKate Stone summary_format_sp)); 512379447a7SEnrico Granata 513b9c1b51eSKate Stone const SymbolContext &sym_ctx = 514b9c1b51eSKate Stone frame->GetSymbolContext(eSymbolContextFunction); 5156754e04fSEnrico Granata if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 5166754e04fSEnrico Granata m_option_variable.show_globals = true; 5176754e04fSEnrico Granata 518b9c1b51eSKate Stone if (variable_list) { 5191deb7962SGreg Clayton const Format format = m_option_format.GetFormat(); 5200c489f58SEnrico Granata options.SetFormat(format); 5211deb7962SGreg Clayton 52211eb9c64SZachary Turner if (!command.empty()) { 52346747022SGreg Clayton VariableList regex_var_list; 52446747022SGreg Clayton 52505097246SAdrian Prantl // If we have any args to the variable command, we will make variable 52605097246SAdrian Prantl // objects from them... 527f965cc86SZachary Turner for (auto &entry : command) { 528b9c1b51eSKate Stone if (m_option_variable.use_regex) { 529c7bece56SGreg Clayton const size_t regex_start_index = regex_var_list.GetSize(); 530f965cc86SZachary Turner llvm::StringRef name_str = entry.ref; 53195eae423SZachary Turner RegularExpression regex(name_str); 532f9d90bc5SJan Kratochvil if (regex.IsValid()) { 53346747022SGreg Clayton size_t num_matches = 0; 534b9c1b51eSKate Stone const size_t num_new_regex_vars = 535b9c1b51eSKate Stone variable_list->AppendVariablesIfUnique(regex, regex_var_list, 53678a685aaSJim Ingham num_matches); 537b9c1b51eSKate Stone if (num_new_regex_vars > 0) { 538b9c1b51eSKate Stone for (size_t regex_idx = regex_start_index, 539b9c1b51eSKate Stone end_index = regex_var_list.GetSize(); 540b9c1b51eSKate Stone regex_idx < end_index; ++regex_idx) { 54146747022SGreg Clayton var_sp = regex_var_list.GetVariableAtIndex(regex_idx); 542b9c1b51eSKate Stone if (var_sp) { 543b9c1b51eSKate Stone valobj_sp = frame->GetValueObjectForFrameVariable( 544b9c1b51eSKate Stone var_sp, m_varobj_options.use_dynamic); 545b9c1b51eSKate Stone if (valobj_sp) { 54673418dfeSEnrico Granata std::string scope_string; 54773418dfeSEnrico Granata if (m_option_variable.show_scope) 54873418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 54973418dfeSEnrico Granata 55073418dfeSEnrico Granata if (!scope_string.empty()) 551771ef6d4SMalcolm Parsons s.PutCString(scope_string); 55273418dfeSEnrico Granata 553b9c1b51eSKate Stone if (m_option_variable.show_decl && 554b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 55545ba8543SGreg Clayton bool show_fullpaths = false; 55645ba8543SGreg Clayton bool show_module = true; 557b9c1b51eSKate Stone if (var_sp->DumpDeclaration(&s, show_fullpaths, 558b9c1b51eSKate Stone show_module)) 55946747022SGreg Clayton s.PutCString(": "); 56046747022SGreg Clayton } 5614d93b8cdSEnrico Granata valobj_sp->Dump(result.GetOutputStream(), options); 56246747022SGreg Clayton } 56346747022SGreg Clayton } 56446747022SGreg Clayton } 565b9c1b51eSKate Stone } else if (num_matches == 0) { 566b9c1b51eSKate Stone result.GetErrorStream().Printf("error: no variables matched " 567b9c1b51eSKate Stone "the regular expression '%s'.\n", 568f965cc86SZachary Turner entry.c_str()); 56946747022SGreg Clayton } 570b9c1b51eSKate Stone } else { 5713af3f1e8SJonas Devlieghere if (llvm::Error err = regex.GetError()) 5723af3f1e8SJonas Devlieghere result.GetErrorStream().Printf( 5733af3f1e8SJonas Devlieghere "error: %s\n", llvm::toString(std::move(err)).c_str()); 57446747022SGreg Clayton else 575b9c1b51eSKate Stone result.GetErrorStream().Printf( 576b9c1b51eSKate Stone "error: unknown regex error when compiling '%s'\n", 577f965cc86SZachary Turner entry.c_str()); 57846747022SGreg Clayton } 579b9c1b51eSKate Stone } else // No regex, either exact variable names or variable 580b9c1b51eSKate Stone // expressions. 58146747022SGreg Clayton { 58297206d57SZachary Turner Status error; 583b9c1b51eSKate Stone uint32_t expr_path_options = 584b9c1b51eSKate Stone StackFrame::eExpressionPathOptionCheckPtrVsMember | 58546252398SEnrico Granata StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 58646252398SEnrico Granata StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 5872837b766SJim Ingham lldb::VariableSP var_sp; 588b9c1b51eSKate Stone valobj_sp = frame->GetValueForVariableExpressionPath( 589f965cc86SZachary Turner entry.ref, m_varobj_options.use_dynamic, expr_path_options, 590b9c1b51eSKate Stone var_sp, error); 591b9c1b51eSKate Stone if (valobj_sp) { 59273418dfeSEnrico Granata std::string scope_string; 59373418dfeSEnrico Granata if (m_option_variable.show_scope) 59473418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 59573418dfeSEnrico Granata 59673418dfeSEnrico Granata if (!scope_string.empty()) 597771ef6d4SMalcolm Parsons s.PutCString(scope_string); 598b9c1b51eSKate Stone if (m_option_variable.show_decl && var_sp && 599b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 600a134cc1bSGreg Clayton var_sp->GetDeclaration().DumpStopContext(&s, false); 601a134cc1bSGreg Clayton s.PutCString(": "); 602a134cc1bSGreg Clayton } 6030c489f58SEnrico Granata 6040c489f58SEnrico Granata options.SetFormat(format); 605b9c1b51eSKate Stone options.SetVariableFormatDisplayLanguage( 606b9c1b51eSKate Stone valobj_sp->GetPreferredDisplayLanguage()); 607887062aeSJohnny Chen 608887062aeSJohnny Chen Stream &output_stream = result.GetOutputStream(); 609f965cc86SZachary Turner options.SetRootValueObjectName( 610f965cc86SZachary Turner valobj_sp->GetParent() ? entry.c_str() : nullptr); 6114d93b8cdSEnrico Granata valobj_sp->Dump(output_stream, options); 612b9c1b51eSKate Stone } else { 613c8ecc2a9SEugene Zelenko const char *error_cstr = error.AsCString(nullptr); 61454979cddSGreg Clayton if (error_cstr) 61554979cddSGreg Clayton result.GetErrorStream().Printf("error: %s\n", error_cstr); 61654979cddSGreg Clayton else 617b9c1b51eSKate Stone result.GetErrorStream().Printf("error: unable to find any " 618b9c1b51eSKate Stone "variable expression path that " 619b9c1b51eSKate Stone "matches '%s'.\n", 620f965cc86SZachary Turner entry.c_str()); 6216d56d2ceSJim Ingham } 6226d56d2ceSJim Ingham } 6236d56d2ceSJim Ingham } 624b9c1b51eSKate Stone } else // No command arg specified. Use variable_list, instead. 6256d56d2ceSJim Ingham { 626c7bece56SGreg Clayton const size_t num_variables = variable_list->GetSize(); 627b9c1b51eSKate Stone if (num_variables > 0) { 628b9c1b51eSKate Stone for (size_t i = 0; i < num_variables; i++) { 6291a65ae11SGreg Clayton var_sp = variable_list->GetVariableAtIndex(i); 630f955efc0SSylvestre Ledru switch (var_sp->GetScope()) { 631eb236735SJim Ingham case eValueTypeVariableGlobal: 632eb236735SJim Ingham if (!m_option_variable.show_globals) 633eb236735SJim Ingham continue; 634eb236735SJim Ingham break; 635eb236735SJim Ingham case eValueTypeVariableStatic: 636eb236735SJim Ingham if (!m_option_variable.show_globals) 637eb236735SJim Ingham continue; 638eb236735SJim Ingham break; 639eb236735SJim Ingham case eValueTypeVariableArgument: 640eb236735SJim Ingham if (!m_option_variable.show_args) 641eb236735SJim Ingham continue; 642eb236735SJim Ingham break; 643eb236735SJim Ingham case eValueTypeVariableLocal: 644eb236735SJim Ingham if (!m_option_variable.show_locals) 645eb236735SJim Ingham continue; 646eb236735SJim Ingham break; 647eb236735SJim Ingham default: 648eb236735SJim Ingham continue; 649eb236735SJim Ingham break; 650eb236735SJim Ingham } 651560558ebSEnrico Granata std::string scope_string; 652eb236735SJim Ingham if (m_option_variable.show_scope) 65373418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 6546d56d2ceSJim Ingham 65505097246SAdrian Prantl // Use the variable object code to make sure we are using the same 65605097246SAdrian Prantl // APIs as the public API will be using... 657b9c1b51eSKate Stone valobj_sp = frame->GetValueObjectForFrameVariable( 658b9c1b51eSKate Stone var_sp, m_varobj_options.use_dynamic); 659b9c1b51eSKate Stone if (valobj_sp) { 66005097246SAdrian Prantl // When dumping all variables, don't print any variables that are 66105097246SAdrian Prantl // not in scope to avoid extra unneeded output 662b9c1b51eSKate Stone if (valobj_sp->IsInScope()) { 663b9c1b51eSKate Stone if (!valobj_sp->GetTargetSP() 664b9c1b51eSKate Stone ->GetDisplayRuntimeSupportValues() && 665c8ecc2a9SEugene Zelenko valobj_sp->IsRuntimeSupportValue()) 666560558ebSEnrico Granata continue; 667560558ebSEnrico Granata 668560558ebSEnrico Granata if (!scope_string.empty()) 669771ef6d4SMalcolm Parsons s.PutCString(scope_string); 670560558ebSEnrico Granata 671b9c1b51eSKate Stone if (m_option_variable.show_decl && 672b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 673a134cc1bSGreg Clayton var_sp->GetDeclaration().DumpStopContext(&s, false); 674a134cc1bSGreg Clayton s.PutCString(": "); 675a134cc1bSGreg Clayton } 6760c489f58SEnrico Granata 6770c489f58SEnrico Granata options.SetFormat(format); 678b9c1b51eSKate Stone options.SetVariableFormatDisplayLanguage( 679b9c1b51eSKate Stone valobj_sp->GetPreferredDisplayLanguage()); 680f965cc86SZachary Turner options.SetRootValueObjectName( 681f965cc86SZachary Turner var_sp ? var_sp->GetName().AsCString() : nullptr); 6824d93b8cdSEnrico Granata valobj_sp->Dump(result.GetOutputStream(), options); 683a134cc1bSGreg Clayton } 684a134cc1bSGreg Clayton } 6856d56d2ceSJim Ingham } 6866d56d2ceSJim Ingham } 6876d56d2ceSJim Ingham } 6886d56d2ceSJim Ingham result.SetStatus(eReturnStatusSuccessFinishResult); 6896d56d2ceSJim Ingham } 69061a80ba6SEnrico Granata 69141ae8e74SKuba Mracek if (m_option_variable.show_recognized_args) { 69241ae8e74SKuba Mracek auto recognized_frame = frame->GetRecognizedFrame(); 69341ae8e74SKuba Mracek if (recognized_frame) { 69441ae8e74SKuba Mracek ValueObjectListSP recognized_arg_list = 69541ae8e74SKuba Mracek recognized_frame->GetRecognizedArguments(); 69641ae8e74SKuba Mracek if (recognized_arg_list) { 69741ae8e74SKuba Mracek for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { 69841ae8e74SKuba Mracek options.SetFormat(m_option_format.GetFormat()); 69941ae8e74SKuba Mracek options.SetVariableFormatDisplayLanguage( 70041ae8e74SKuba Mracek rec_value_sp->GetPreferredDisplayLanguage()); 70141ae8e74SKuba Mracek options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); 70241ae8e74SKuba Mracek rec_value_sp->Dump(result.GetOutputStream(), options); 70341ae8e74SKuba Mracek } 70441ae8e74SKuba Mracek } 70541ae8e74SKuba Mracek } 70641ae8e74SKuba Mracek } 70741ae8e74SKuba Mracek 708b9c1b51eSKate Stone if (m_interpreter.TruncationWarningNecessary()) { 70961a80ba6SEnrico Granata result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 71061a80ba6SEnrico Granata m_cmd_name.c_str()); 71161a80ba6SEnrico Granata m_interpreter.TruncationWarningGiven(); 71261a80ba6SEnrico Granata } 71361a80ba6SEnrico Granata 71424fff242SDavide Italiano // Increment statistics. 71524fff242SDavide Italiano bool res = result.Succeeded(); 716cb2380c9SRaphael Isemann Target &target = GetSelectedOrDummyTarget(); 71724fff242SDavide Italiano if (res) 718cb2380c9SRaphael Isemann target.IncrementStats(StatisticKind::FrameVarSuccess); 71924fff242SDavide Italiano else 720cb2380c9SRaphael Isemann target.IncrementStats(StatisticKind::FrameVarFailure); 72124fff242SDavide Italiano return res; 7226d56d2ceSJim Ingham } 7236d56d2ceSJim Ingham 724c8ecc2a9SEugene Zelenko protected: 7252837b766SJim Ingham OptionGroupOptions m_option_group; 726715c2365SGreg Clayton OptionGroupVariable m_option_variable; 7271deb7962SGreg Clayton OptionGroupFormat m_option_format; 7282837b766SJim Ingham OptionGroupValueObjectDisplay m_varobj_options; 7296d56d2ceSJim Ingham }; 7306d56d2ceSJim Ingham 73141ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer 73241ae8e74SKuba Mracek 733ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_recognizer_add 734ec67e734SRaphael Isemann #include "CommandOptions.inc" 73541ae8e74SKuba Mracek 73641ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { 73741ae8e74SKuba Mracek private: 73841ae8e74SKuba Mracek class CommandOptions : public Options { 73941ae8e74SKuba Mracek public: 74041ae8e74SKuba Mracek CommandOptions() : Options() {} 74141ae8e74SKuba Mracek ~CommandOptions() override = default; 74241ae8e74SKuba Mracek 74341ae8e74SKuba Mracek Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 74441ae8e74SKuba Mracek ExecutionContext *execution_context) override { 74541ae8e74SKuba Mracek Status error; 74641ae8e74SKuba Mracek const int short_option = m_getopt_table[option_idx].val; 74741ae8e74SKuba Mracek 74841ae8e74SKuba Mracek switch (short_option) { 74941ae8e74SKuba Mracek case 'l': 75041ae8e74SKuba Mracek m_class_name = std::string(option_arg); 75141ae8e74SKuba Mracek break; 75241ae8e74SKuba Mracek case 's': 75341ae8e74SKuba Mracek m_module = std::string(option_arg); 75441ae8e74SKuba Mracek break; 75541ae8e74SKuba Mracek case 'n': 75641ae8e74SKuba Mracek m_function = std::string(option_arg); 75741ae8e74SKuba Mracek break; 75841ae8e74SKuba Mracek case 'x': 75941ae8e74SKuba Mracek m_regex = true; 76041ae8e74SKuba Mracek break; 76141ae8e74SKuba Mracek default: 76236162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 76341ae8e74SKuba Mracek } 76441ae8e74SKuba Mracek 76541ae8e74SKuba Mracek return error; 76641ae8e74SKuba Mracek } 76741ae8e74SKuba Mracek 76841ae8e74SKuba Mracek void OptionParsingStarting(ExecutionContext *execution_context) override { 76941ae8e74SKuba Mracek m_module = ""; 77041ae8e74SKuba Mracek m_function = ""; 77141ae8e74SKuba Mracek m_class_name = ""; 77241ae8e74SKuba Mracek m_regex = false; 77341ae8e74SKuba Mracek } 77441ae8e74SKuba Mracek 77541ae8e74SKuba Mracek llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 77641ae8e74SKuba Mracek return llvm::makeArrayRef(g_frame_recognizer_add_options); 77741ae8e74SKuba Mracek } 77841ae8e74SKuba Mracek 77941ae8e74SKuba Mracek // Instance variables to hold the values for command options. 78041ae8e74SKuba Mracek std::string m_class_name; 78141ae8e74SKuba Mracek std::string m_module; 78241ae8e74SKuba Mracek std::string m_function; 78341ae8e74SKuba Mracek bool m_regex; 78441ae8e74SKuba Mracek }; 78541ae8e74SKuba Mracek 78641ae8e74SKuba Mracek CommandOptions m_options; 78741ae8e74SKuba Mracek 78841ae8e74SKuba Mracek Options *GetOptions() override { return &m_options; } 78941ae8e74SKuba Mracek 79041ae8e74SKuba Mracek protected: 79141ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override; 79241ae8e74SKuba Mracek 79341ae8e74SKuba Mracek public: 79441ae8e74SKuba Mracek CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 79541ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer add", 79641ae8e74SKuba Mracek "Add a new frame recognizer.", nullptr), 79741ae8e74SKuba Mracek m_options() { 79841ae8e74SKuba Mracek SetHelpLong(R"( 79941ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on 80041ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source 80141ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments 80241ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments. 80341ae8e74SKuba Mracek 80441ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class 80541ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a 80641ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type 80741ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize. 80841ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that 80941ae8e74SKuba Mracek represent the recognized arguments. 81041ae8e74SKuba Mracek 81141ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc 81241ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows: 81341ae8e74SKuba Mracek 81441ae8e74SKuba Mracek class LibcFdRecognizer(object): 81541ae8e74SKuba Mracek def get_recognized_arguments(self, frame): 81641ae8e74SKuba Mracek if frame.name in ["read", "write", "close"]: 81741ae8e74SKuba Mracek fd = frame.EvaluateExpression("$arg1").unsigned 81841ae8e74SKuba Mracek value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) 81941ae8e74SKuba Mracek return [value] 82041ae8e74SKuba Mracek return [] 82141ae8e74SKuba Mracek 82241ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script 82341ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'. 82441ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is 82541ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 82641ae8e74SKuba Mracek in other modules: 82741ae8e74SKuba Mracek 82841ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py 82941ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 83041ae8e74SKuba Mracek 83141ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we 83241ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable': 83341ae8e74SKuba Mracek 83441ae8e74SKuba Mracek (lldb) b read 83541ae8e74SKuba Mracek (lldb) r 83641ae8e74SKuba Mracek Process 1234 stopped 83741ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 83841ae8e74SKuba Mracek frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 83941ae8e74SKuba Mracek (lldb) frame variable 84041ae8e74SKuba Mracek (int) fd = 3 84141ae8e74SKuba Mracek 84241ae8e74SKuba Mracek )"); 84341ae8e74SKuba Mracek } 84441ae8e74SKuba Mracek ~CommandObjectFrameRecognizerAdd() override = default; 84541ae8e74SKuba Mracek }; 84641ae8e74SKuba Mracek 84741ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 84841ae8e74SKuba Mracek CommandReturnObject &result) { 849f80d2655SKuba Mracek #ifndef LLDB_DISABLE_PYTHON 85041ae8e74SKuba Mracek if (m_options.m_class_name.empty()) { 85141ae8e74SKuba Mracek result.AppendErrorWithFormat( 85241ae8e74SKuba Mracek "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 85341ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 85441ae8e74SKuba Mracek return false; 85541ae8e74SKuba Mracek } 85641ae8e74SKuba Mracek 85741ae8e74SKuba Mracek if (m_options.m_module.empty()) { 85841ae8e74SKuba Mracek result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 85941ae8e74SKuba Mracek m_cmd_name.c_str()); 86041ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 86141ae8e74SKuba Mracek return false; 86241ae8e74SKuba Mracek } 86341ae8e74SKuba Mracek 86441ae8e74SKuba Mracek if (m_options.m_function.empty()) { 86541ae8e74SKuba Mracek result.AppendErrorWithFormat("%s needs a function name (-n argument).\n", 86641ae8e74SKuba Mracek m_cmd_name.c_str()); 86741ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 86841ae8e74SKuba Mracek return false; 86941ae8e74SKuba Mracek } 87041ae8e74SKuba Mracek 8712b29b432SJonas Devlieghere ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 87241ae8e74SKuba Mracek 87341ae8e74SKuba Mracek if (interpreter && 87441ae8e74SKuba Mracek !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 87541ae8e74SKuba Mracek result.AppendWarning( 87641ae8e74SKuba Mracek "The provided class does not exist - please define it " 87741ae8e74SKuba Mracek "before attempting to use this frame recognizer"); 87841ae8e74SKuba Mracek } 87941ae8e74SKuba Mracek 88041ae8e74SKuba Mracek StackFrameRecognizerSP recognizer_sp = 88141ae8e74SKuba Mracek StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 88241ae8e74SKuba Mracek interpreter, m_options.m_class_name.c_str())); 88341ae8e74SKuba Mracek if (m_options.m_regex) { 88441ae8e74SKuba Mracek auto module = 88541ae8e74SKuba Mracek RegularExpressionSP(new RegularExpression(m_options.m_module)); 88641ae8e74SKuba Mracek auto func = 88741ae8e74SKuba Mracek RegularExpressionSP(new RegularExpression(m_options.m_function)); 88841ae8e74SKuba Mracek StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); 88941ae8e74SKuba Mracek } else { 89041ae8e74SKuba Mracek auto module = ConstString(m_options.m_module); 89141ae8e74SKuba Mracek auto func = ConstString(m_options.m_function); 89241ae8e74SKuba Mracek StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); 89341ae8e74SKuba Mracek } 894f80d2655SKuba Mracek #endif 89541ae8e74SKuba Mracek 89641ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishNoResult); 89741ae8e74SKuba Mracek return result.Succeeded(); 89841ae8e74SKuba Mracek } 89941ae8e74SKuba Mracek 90041ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 90141ae8e74SKuba Mracek public: 90241ae8e74SKuba Mracek CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 90341ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer clear", 90441ae8e74SKuba Mracek "Delete all frame recognizers.", nullptr) {} 90541ae8e74SKuba Mracek 90641ae8e74SKuba Mracek ~CommandObjectFrameRecognizerClear() override = default; 90741ae8e74SKuba Mracek 90841ae8e74SKuba Mracek protected: 90941ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 91041ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveAllRecognizers(); 91141ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 91241ae8e74SKuba Mracek return result.Succeeded(); 91341ae8e74SKuba Mracek } 91441ae8e74SKuba Mracek }; 91541ae8e74SKuba Mracek 91641ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 91741ae8e74SKuba Mracek public: 91841ae8e74SKuba Mracek CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 91941ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer delete", 92041ae8e74SKuba Mracek "Delete an existing frame recognizer.", nullptr) {} 92141ae8e74SKuba Mracek 92241ae8e74SKuba Mracek ~CommandObjectFrameRecognizerDelete() override = default; 92341ae8e74SKuba Mracek 92441ae8e74SKuba Mracek protected: 92541ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 92641ae8e74SKuba Mracek if (command.GetArgumentCount() == 0) { 92741ae8e74SKuba Mracek if (!m_interpreter.Confirm( 92841ae8e74SKuba Mracek "About to delete all frame recognizers, do you want to do that?", 92941ae8e74SKuba Mracek true)) { 93041ae8e74SKuba Mracek result.AppendMessage("Operation cancelled..."); 93141ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 93241ae8e74SKuba Mracek return false; 93341ae8e74SKuba Mracek } 93441ae8e74SKuba Mracek 93541ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveAllRecognizers(); 93641ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 93741ae8e74SKuba Mracek return result.Succeeded(); 93841ae8e74SKuba Mracek } 93941ae8e74SKuba Mracek 94041ae8e74SKuba Mracek if (command.GetArgumentCount() != 1) { 94141ae8e74SKuba Mracek result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 94241ae8e74SKuba Mracek m_cmd_name.c_str()); 94341ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 94441ae8e74SKuba Mracek return false; 94541ae8e74SKuba Mracek } 94641ae8e74SKuba Mracek 94741ae8e74SKuba Mracek uint32_t recognizer_id = 94841ae8e74SKuba Mracek StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 94941ae8e74SKuba Mracek 95041ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id); 95141ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 95241ae8e74SKuba Mracek return result.Succeeded(); 95341ae8e74SKuba Mracek } 95441ae8e74SKuba Mracek }; 95541ae8e74SKuba Mracek 95641ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed { 95741ae8e74SKuba Mracek public: 95841ae8e74SKuba Mracek CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 95941ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer list", 96041ae8e74SKuba Mracek "Show a list of active frame recognizers.", 96141ae8e74SKuba Mracek nullptr) {} 96241ae8e74SKuba Mracek 96341ae8e74SKuba Mracek ~CommandObjectFrameRecognizerList() override = default; 96441ae8e74SKuba Mracek 96541ae8e74SKuba Mracek protected: 96641ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 96741ae8e74SKuba Mracek bool any_printed = false; 96841ae8e74SKuba Mracek StackFrameRecognizerManager::ForEach( 96941ae8e74SKuba Mracek [&result, &any_printed](uint32_t recognizer_id, std::string name, 97041ae8e74SKuba Mracek std::string function, std::string symbol, 97141ae8e74SKuba Mracek bool regexp) { 97241ae8e74SKuba Mracek if (name == "") name = "(internal)"; 97341ae8e74SKuba Mracek result.GetOutputStream().Printf( 97441ae8e74SKuba Mracek "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(), 97541ae8e74SKuba Mracek function.c_str(), symbol.c_str(), regexp ? " (regexp)" : ""); 97641ae8e74SKuba Mracek any_printed = true; 97741ae8e74SKuba Mracek }); 97841ae8e74SKuba Mracek 97941ae8e74SKuba Mracek if (any_printed) 98041ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 98141ae8e74SKuba Mracek else { 98241ae8e74SKuba Mracek result.GetOutputStream().PutCString("no matching results found.\n"); 98341ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishNoResult); 98441ae8e74SKuba Mracek } 98541ae8e74SKuba Mracek return result.Succeeded(); 98641ae8e74SKuba Mracek } 98741ae8e74SKuba Mracek }; 98841ae8e74SKuba Mracek 98941ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 99041ae8e74SKuba Mracek public: 99141ae8e74SKuba Mracek CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 99241ae8e74SKuba Mracek : CommandObjectParsed( 99341ae8e74SKuba Mracek interpreter, "frame recognizer info", 99441ae8e74SKuba Mracek "Show which frame recognizer is applied a stack frame (if any).", 99541ae8e74SKuba Mracek nullptr) { 99641ae8e74SKuba Mracek CommandArgumentEntry arg; 99741ae8e74SKuba Mracek CommandArgumentData index_arg; 99841ae8e74SKuba Mracek 99941ae8e74SKuba Mracek // Define the first (and only) variant of this arg. 100041ae8e74SKuba Mracek index_arg.arg_type = eArgTypeFrameIndex; 100141ae8e74SKuba Mracek index_arg.arg_repetition = eArgRepeatPlain; 100241ae8e74SKuba Mracek 100341ae8e74SKuba Mracek // There is only one variant this argument could be; put it into the 100441ae8e74SKuba Mracek // argument entry. 100541ae8e74SKuba Mracek arg.push_back(index_arg); 100641ae8e74SKuba Mracek 100741ae8e74SKuba Mracek // Push the data for the first argument into the m_arguments vector. 100841ae8e74SKuba Mracek m_arguments.push_back(arg); 100941ae8e74SKuba Mracek } 101041ae8e74SKuba Mracek 101141ae8e74SKuba Mracek ~CommandObjectFrameRecognizerInfo() override = default; 101241ae8e74SKuba Mracek 101341ae8e74SKuba Mracek protected: 101441ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 101541ae8e74SKuba Mracek Process *process = m_exe_ctx.GetProcessPtr(); 101641ae8e74SKuba Mracek if (process == nullptr) { 101741ae8e74SKuba Mracek result.AppendError("no process"); 101841ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 101941ae8e74SKuba Mracek return false; 102041ae8e74SKuba Mracek } 102141ae8e74SKuba Mracek Thread *thread = m_exe_ctx.GetThreadPtr(); 102241ae8e74SKuba Mracek if (thread == nullptr) { 102341ae8e74SKuba Mracek result.AppendError("no thread"); 102441ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 102541ae8e74SKuba Mracek return false; 102641ae8e74SKuba Mracek } 102741ae8e74SKuba Mracek if (command.GetArgumentCount() != 1) { 102841ae8e74SKuba Mracek result.AppendErrorWithFormat( 102941ae8e74SKuba Mracek "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 103041ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 103141ae8e74SKuba Mracek return false; 103241ae8e74SKuba Mracek } 103341ae8e74SKuba Mracek 103441ae8e74SKuba Mracek uint32_t frame_index = 103541ae8e74SKuba Mracek StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 103641ae8e74SKuba Mracek StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 103741ae8e74SKuba Mracek if (!frame_sp) { 103841ae8e74SKuba Mracek result.AppendErrorWithFormat("no frame with index %u", frame_index); 103941ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 104041ae8e74SKuba Mracek return false; 104141ae8e74SKuba Mracek } 104241ae8e74SKuba Mracek 104341ae8e74SKuba Mracek auto recognizer = 104441ae8e74SKuba Mracek StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp); 104541ae8e74SKuba Mracek 104641ae8e74SKuba Mracek Stream &output_stream = result.GetOutputStream(); 104741ae8e74SKuba Mracek output_stream.Printf("frame %d ", frame_index); 104841ae8e74SKuba Mracek if (recognizer) { 104941ae8e74SKuba Mracek output_stream << "is recognized by "; 105041ae8e74SKuba Mracek output_stream << recognizer->GetName(); 105141ae8e74SKuba Mracek } else { 105241ae8e74SKuba Mracek output_stream << "not recognized by any recognizer"; 105341ae8e74SKuba Mracek } 105441ae8e74SKuba Mracek output_stream.EOL(); 105541ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 105641ae8e74SKuba Mracek return result.Succeeded(); 105741ae8e74SKuba Mracek } 105841ae8e74SKuba Mracek }; 105941ae8e74SKuba Mracek 106041ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword { 106141ae8e74SKuba Mracek public: 106241ae8e74SKuba Mracek CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 106341ae8e74SKuba Mracek : CommandObjectMultiword( 106441ae8e74SKuba Mracek interpreter, "frame recognizer", 106541ae8e74SKuba Mracek "Commands for editing and viewing frame recognizers.", 106641ae8e74SKuba Mracek "frame recognizer [<sub-command-options>] ") { 106741ae8e74SKuba Mracek LoadSubCommand( 106841ae8e74SKuba Mracek "add", 106941ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter))); 107041ae8e74SKuba Mracek LoadSubCommand( 107141ae8e74SKuba Mracek "clear", 107241ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 107341ae8e74SKuba Mracek LoadSubCommand( 107441ae8e74SKuba Mracek "delete", 107541ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 107641ae8e74SKuba Mracek LoadSubCommand( 107741ae8e74SKuba Mracek "list", 107841ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter))); 107941ae8e74SKuba Mracek LoadSubCommand( 108041ae8e74SKuba Mracek "info", 108141ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerInfo(interpreter))); 108241ae8e74SKuba Mracek } 108341ae8e74SKuba Mracek 108441ae8e74SKuba Mracek ~CommandObjectFrameRecognizer() override = default; 108541ae8e74SKuba Mracek }; 108641ae8e74SKuba Mracek 108730fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame 108830fdc8d8SChris Lattner 108930fdc8d8SChris Lattner // CommandObjectMultiwordFrame 109030fdc8d8SChris Lattner 1091b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1092b9c1b51eSKate Stone CommandInterpreter &interpreter) 1093b9c1b51eSKate Stone : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and " 1094b9c1b51eSKate Stone "examing the current " 1095b9c1b51eSKate Stone "thread's stack frames.", 1096b9c1b51eSKate Stone "frame <subcommand> [<subcommand-options>]") { 1097b9c1b51eSKate Stone LoadSubCommand("diagnose", 1098b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1099b9c1b51eSKate Stone LoadSubCommand("info", 1100b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1101b9c1b51eSKate Stone LoadSubCommand("select", 1102b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1103b9c1b51eSKate Stone LoadSubCommand("variable", 1104b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 110541ae8e74SKuba Mracek #ifndef LLDB_DISABLE_PYTHON 110641ae8e74SKuba Mracek LoadSubCommand( 110741ae8e74SKuba Mracek "recognizer", 110841ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizer(interpreter))); 110941ae8e74SKuba Mracek #endif 111030fdc8d8SChris Lattner } 111130fdc8d8SChris Lattner 1112c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1113