180814287SRaphael Isemann //===-- CommandObjectFrame.cpp --------------------------------------------===// 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/ValueObject.h" 115548cb50SEnrico Granata #include "lldb/DataFormatters/DataVisualization.h" 124d93b8cdSEnrico Granata #include "lldb/DataFormatters/ValueObjectPrinter.h" 1359998b7bSJonas Devlieghere #include "lldb/Host/Config.h" 143eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h" 1530fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h" 1630fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h" 171deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h" 182837b766SJim Ingham #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" 19715c2365SGreg Clayton #include "lldb/Interpreter/OptionGroupVariable.h" 20b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h" 216754e04fSEnrico Granata #include "lldb/Symbol/Function.h" 226d56d2ceSJim Ingham #include "lldb/Symbol/SymbolContext.h" 236d56d2ceSJim Ingham #include "lldb/Symbol/Variable.h" 246d56d2ceSJim Ingham #include "lldb/Symbol/VariableList.h" 25b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h" 2641ae8e74SKuba Mracek #include "lldb/Target/StackFrameRecognizer.h" 274740a734SSean Callanan #include "lldb/Target/StopInfo.h" 286d56d2ceSJim Ingham #include "lldb/Target/Target.h" 29b9c1b51eSKate Stone #include "lldb/Target/Thread.h" 30145d95c9SPavel Labath #include "lldb/Utility/Args.h" 3130fdc8d8SChris Lattner 32796ac80bSJonas Devlieghere #include <memory> 33796ac80bSJonas Devlieghere #include <string> 34796ac80bSJonas Devlieghere 3530fdc8d8SChris Lattner using namespace lldb; 3630fdc8d8SChris Lattner using namespace lldb_private; 3730fdc8d8SChris Lattner 384740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose 394740a734SSean Callanan 404740a734SSean Callanan // CommandObjectFrameInfo 414740a734SSean Callanan 424740a734SSean Callanan // CommandObjectFrameDiagnose 434740a734SSean Callanan 44ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_diag 45ec67e734SRaphael Isemann #include "CommandOptions.inc" 461f0f5b5bSZachary Turner 47b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed { 484740a734SSean Callanan public: 49b9c1b51eSKate Stone class CommandOptions : public Options { 504740a734SSean Callanan public: 51b9c1b51eSKate Stone CommandOptions() : Options() { OptionParsingStarting(nullptr); } 524740a734SSean Callanan 534740a734SSean Callanan ~CommandOptions() override = default; 544740a734SSean Callanan 5597206d57SZachary Turner Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 56b9c1b51eSKate Stone ExecutionContext *execution_context) override { 5797206d57SZachary Turner Status error; 584740a734SSean Callanan const int short_option = m_getopt_table[option_idx].val; 59b9c1b51eSKate Stone switch (short_option) { 604740a734SSean Callanan case 'r': 614740a734SSean Callanan reg = ConstString(option_arg); 624740a734SSean Callanan break; 634740a734SSean Callanan 64b9c1b51eSKate Stone case 'a': { 65fe11483bSZachary Turner address.emplace(); 66fe11483bSZachary Turner if (option_arg.getAsInteger(0, *address)) { 674740a734SSean Callanan address.reset(); 68b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid address argument '%s'", 69fe11483bSZachary Turner option_arg.str().c_str()); 704740a734SSean Callanan } 71b9c1b51eSKate Stone } break; 724740a734SSean Callanan 73b9c1b51eSKate Stone case 'o': { 74fe11483bSZachary Turner offset.emplace(); 75fe11483bSZachary Turner if (option_arg.getAsInteger(0, *offset)) { 764740a734SSean Callanan offset.reset(); 77b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid offset argument '%s'", 78fe11483bSZachary Turner option_arg.str().c_str()); 794740a734SSean Callanan } 80b9c1b51eSKate Stone } break; 814740a734SSean Callanan 824740a734SSean Callanan default: 8336162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 844740a734SSean Callanan } 854740a734SSean Callanan 864740a734SSean Callanan return error; 874740a734SSean Callanan } 884740a734SSean Callanan 89b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 904740a734SSean Callanan address.reset(); 914740a734SSean Callanan reg.reset(); 924740a734SSean Callanan offset.reset(); 934740a734SSean Callanan } 944740a734SSean Callanan 951f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 9670602439SZachary Turner return llvm::makeArrayRef(g_frame_diag_options); 971f0f5b5bSZachary Turner } 984740a734SSean Callanan 994740a734SSean Callanan // Options. 1004740a734SSean Callanan llvm::Optional<lldb::addr_t> address; 1014740a734SSean Callanan llvm::Optional<ConstString> reg; 1024740a734SSean Callanan llvm::Optional<int64_t> offset; 1034740a734SSean Callanan }; 1044740a734SSean Callanan 1054740a734SSean Callanan CommandObjectFrameDiagnose(CommandInterpreter &interpreter) 1064740a734SSean Callanan : CommandObjectParsed(interpreter, "frame diagnose", 107b9c1b51eSKate Stone "Try to determine what path path the current stop " 108b9c1b51eSKate Stone "location used to get to a register or address", 109b9c1b51eSKate Stone nullptr, 110b9c1b51eSKate Stone eCommandRequiresThread | eCommandTryTargetAPILock | 111b9c1b51eSKate Stone eCommandProcessMustBeLaunched | 1124740a734SSean Callanan eCommandProcessMustBePaused), 113b9c1b51eSKate Stone m_options() { 1144740a734SSean Callanan CommandArgumentEntry arg; 1154740a734SSean Callanan CommandArgumentData index_arg; 1164740a734SSean Callanan 1174740a734SSean Callanan // Define the first (and only) variant of this arg. 1184740a734SSean Callanan index_arg.arg_type = eArgTypeFrameIndex; 1194740a734SSean Callanan index_arg.arg_repetition = eArgRepeatOptional; 1204740a734SSean Callanan 121b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 122b9c1b51eSKate Stone // argument entry. 1234740a734SSean Callanan arg.push_back(index_arg); 1244740a734SSean Callanan 1254740a734SSean Callanan // Push the data for the first argument into the m_arguments vector. 1264740a734SSean Callanan m_arguments.push_back(arg); 1274740a734SSean Callanan } 1284740a734SSean Callanan 1294740a734SSean Callanan ~CommandObjectFrameDiagnose() override = default; 1304740a734SSean Callanan 131b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 1324740a734SSean Callanan 1334740a734SSean Callanan protected: 134b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 1354740a734SSean Callanan Thread *thread = m_exe_ctx.GetThreadPtr(); 1364740a734SSean Callanan StackFrameSP frame_sp = thread->GetSelectedFrame(); 1374740a734SSean Callanan 1384740a734SSean Callanan ValueObjectSP valobj_sp; 1394740a734SSean Callanan 140b9c1b51eSKate Stone if (m_options.address.hasValue()) { 141b9c1b51eSKate Stone if (m_options.reg.hasValue() || m_options.offset.hasValue()) { 142b9c1b51eSKate Stone result.AppendError( 143b9c1b51eSKate Stone "`frame diagnose --address` is incompatible with other arguments."); 1444740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1454740a734SSean Callanan return false; 1464740a734SSean Callanan } 1474740a734SSean Callanan valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue()); 148b9c1b51eSKate Stone } else if (m_options.reg.hasValue()) { 149b9c1b51eSKate Stone valobj_sp = frame_sp->GuessValueForRegisterAndOffset( 150b9c1b51eSKate Stone m_options.reg.getValue(), m_options.offset.getValueOr(0)); 151b9c1b51eSKate Stone } else { 1524740a734SSean Callanan StopInfoSP stop_info_sp = thread->GetStopInfo(); 153b9c1b51eSKate Stone if (!stop_info_sp) { 1544740a734SSean Callanan result.AppendError("No arguments provided, and no stop info."); 1554740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1564740a734SSean Callanan return false; 1574740a734SSean Callanan } 1584740a734SSean Callanan 1594740a734SSean Callanan valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp); 1604740a734SSean Callanan } 1614740a734SSean Callanan 162b9c1b51eSKate Stone if (!valobj_sp) { 1634740a734SSean Callanan result.AppendError("No diagnosis available."); 1644740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1654740a734SSean Callanan return false; 1664740a734SSean Callanan } 1674740a734SSean Callanan 168a925974bSAdrian Prantl DumpValueObjectOptions::DeclPrintingHelper helper = 169a925974bSAdrian Prantl [&valobj_sp](ConstString type, ConstString var, 170a925974bSAdrian Prantl const DumpValueObjectOptions &opts, 1713bc714b2SZachary Turner Stream &stream) -> bool { 172b9c1b51eSKate Stone const ValueObject::GetExpressionPathFormat format = ValueObject:: 173b9c1b51eSKate Stone GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers; 1743014efe0SAlex Langford valobj_sp->GetExpressionPath(stream, format); 1754740a734SSean Callanan stream.PutCString(" ="); 1764740a734SSean Callanan return true; 1774740a734SSean Callanan }; 1784740a734SSean Callanan 1794740a734SSean Callanan DumpValueObjectOptions options; 1804740a734SSean Callanan options.SetDeclPrintingHelper(helper); 181b9c1b51eSKate Stone ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), 182b9c1b51eSKate Stone options); 1834740a734SSean Callanan printer.PrintValueObject(); 1844740a734SSean Callanan 1854740a734SSean Callanan return true; 1864740a734SSean Callanan } 1874740a734SSean Callanan 1884740a734SSean Callanan CommandOptions m_options; 1894740a734SSean Callanan }; 1904740a734SSean Callanan 19130fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo 19230fdc8d8SChris Lattner 19330fdc8d8SChris Lattner // CommandObjectFrameInfo 19430fdc8d8SChris Lattner 195b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed { 19630fdc8d8SChris Lattner public: 1977428a18cSKate Stone CommandObjectFrameInfo(CommandInterpreter &interpreter) 198a925974bSAdrian Prantl : CommandObjectParsed(interpreter, "frame info", 199a925974bSAdrian Prantl "List information about the current " 200b9c1b51eSKate Stone "stack frame in the current thread.", 201b9c1b51eSKate Stone "frame info", 202b9c1b51eSKate Stone eCommandRequiresFrame | eCommandTryTargetAPILock | 203a925974bSAdrian Prantl eCommandProcessMustBeLaunched | 204a925974bSAdrian Prantl eCommandProcessMustBePaused) {} 20530fdc8d8SChris Lattner 206c8ecc2a9SEugene Zelenko ~CommandObjectFrameInfo() override = default; 20730fdc8d8SChris Lattner 2085a988416SJim Ingham protected: 209b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 210f9fc609fSGreg Clayton m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream()); 21130fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 21230fdc8d8SChris Lattner return result.Succeeded(); 21330fdc8d8SChris Lattner } 21430fdc8d8SChris Lattner }; 21530fdc8d8SChris Lattner 21630fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect 21730fdc8d8SChris Lattner 21830fdc8d8SChris Lattner // CommandObjectFrameSelect 21930fdc8d8SChris Lattner 220ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_select 221ec67e734SRaphael Isemann #include "CommandOptions.inc" 2221f0f5b5bSZachary Turner 223b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed { 22430fdc8d8SChris Lattner public: 225b9c1b51eSKate Stone class CommandOptions : public Options { 226864174e1SGreg Clayton public: 227b9c1b51eSKate Stone CommandOptions() : Options() { OptionParsingStarting(nullptr); } 228864174e1SGreg Clayton 229c8ecc2a9SEugene Zelenko ~CommandOptions() override = default; 230864174e1SGreg Clayton 23197206d57SZachary Turner Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 232b9c1b51eSKate Stone ExecutionContext *execution_context) override { 23397206d57SZachary Turner Status error; 2343bcdfc0eSGreg Clayton const int short_option = m_getopt_table[option_idx].val; 235b9c1b51eSKate Stone switch (short_option) { 236dab6f074SRaphael Isemann case 'r': { 237dab6f074SRaphael Isemann int32_t offset = 0; 238dab6f074SRaphael Isemann if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) { 239b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid frame offset argument '%s'", 240fe11483bSZachary Turner option_arg.str().c_str()); 241dab6f074SRaphael Isemann } else 242dab6f074SRaphael Isemann relative_frame_offset = offset; 2435a039d55SRaphael Isemann break; 244dab6f074SRaphael Isemann } 245864174e1SGreg Clayton 246864174e1SGreg Clayton default: 24736162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 248864174e1SGreg Clayton } 249864174e1SGreg Clayton 250864174e1SGreg Clayton return error; 251864174e1SGreg Clayton } 252864174e1SGreg Clayton 2535a039d55SRaphael Isemann void OptionParsingStarting(ExecutionContext *execution_context) override { 254dab6f074SRaphael Isemann relative_frame_offset.reset(); 2555a039d55SRaphael Isemann } 256864174e1SGreg Clayton 2571f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 25870602439SZachary Turner return llvm::makeArrayRef(g_frame_select_options); 2591f0f5b5bSZachary Turner } 260864174e1SGreg Clayton 261dab6f074SRaphael Isemann llvm::Optional<int32_t> relative_frame_offset; 262864174e1SGreg Clayton }; 263864174e1SGreg Clayton 2647428a18cSKate Stone CommandObjectFrameSelect(CommandInterpreter &interpreter) 265a925974bSAdrian Prantl : CommandObjectParsed(interpreter, "frame select", 266a925974bSAdrian Prantl "Select the current stack frame by " 267b9c1b51eSKate Stone "index from within the current thread " 268b9c1b51eSKate Stone "(see 'thread backtrace'.)", 269b9c1b51eSKate Stone nullptr, 270b9c1b51eSKate Stone eCommandRequiresThread | eCommandTryTargetAPILock | 271a925974bSAdrian Prantl eCommandProcessMustBeLaunched | 272a925974bSAdrian Prantl eCommandProcessMustBePaused), 273b9c1b51eSKate Stone m_options() { 274405fe67fSCaroline Tice CommandArgumentEntry arg; 275405fe67fSCaroline Tice CommandArgumentData index_arg; 276405fe67fSCaroline Tice 277405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 278405fe67fSCaroline Tice index_arg.arg_type = eArgTypeFrameIndex; 279864174e1SGreg Clayton index_arg.arg_repetition = eArgRepeatOptional; 280405fe67fSCaroline Tice 281b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 282b9c1b51eSKate Stone // argument entry. 283405fe67fSCaroline Tice arg.push_back(index_arg); 284405fe67fSCaroline Tice 285405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 286405fe67fSCaroline Tice m_arguments.push_back(arg); 28730fdc8d8SChris Lattner } 28830fdc8d8SChris Lattner 289c8ecc2a9SEugene Zelenko ~CommandObjectFrameSelect() override = default; 29030fdc8d8SChris Lattner 29180eb4228SGongyu Deng void 29280eb4228SGongyu Deng HandleArgumentCompletion(CompletionRequest &request, 29380eb4228SGongyu Deng OptionElementVector &opt_element_vector) override { 29480eb4228SGongyu Deng if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0) 29580eb4228SGongyu Deng return; 29680eb4228SGongyu Deng 29780eb4228SGongyu Deng lldb::ThreadSP thread_sp = m_exe_ctx.GetThreadSP(); 29880eb4228SGongyu Deng const uint32_t frame_num = thread_sp->GetStackFrameCount(); 29980eb4228SGongyu Deng for (uint32_t i = 0; i < frame_num; ++i) { 30080eb4228SGongyu Deng lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i); 30180eb4228SGongyu Deng StreamString strm; 30280eb4228SGongyu Deng frame_sp->Dump(&strm, false, true); 30380eb4228SGongyu Deng request.TryCompleteCurrentArg(std::to_string(i), strm.GetString()); 30480eb4228SGongyu Deng } 30580eb4228SGongyu Deng } 30680eb4228SGongyu Deng 307b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 308864174e1SGreg Clayton 3095a988416SJim Ingham protected: 310b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 311b9c1b51eSKate Stone // No need to check "thread" for validity as eCommandRequiresThread ensures 312b9c1b51eSKate Stone // it is valid 313f9fc609fSGreg Clayton Thread *thread = m_exe_ctx.GetThreadPtr(); 314f9fc609fSGreg Clayton 315864174e1SGreg Clayton uint32_t frame_idx = UINT32_MAX; 316dab6f074SRaphael Isemann if (m_options.relative_frame_offset.hasValue()) { 317864174e1SGreg Clayton // The one and only argument is a signed relative frame index 318c14ee32dSGreg Clayton frame_idx = thread->GetSelectedFrameIndex(); 319864174e1SGreg Clayton if (frame_idx == UINT32_MAX) 320864174e1SGreg Clayton frame_idx = 0; 321864174e1SGreg Clayton 322dab6f074SRaphael Isemann if (*m_options.relative_frame_offset < 0) { 323dab6f074SRaphael Isemann if (static_cast<int32_t>(frame_idx) >= 324dab6f074SRaphael Isemann -*m_options.relative_frame_offset) 325dab6f074SRaphael Isemann frame_idx += *m_options.relative_frame_offset; 326b9c1b51eSKate Stone else { 327b9c1b51eSKate Stone if (frame_idx == 0) { 32805097246SAdrian Prantl // If you are already at the bottom of the stack, then just warn 32905097246SAdrian Prantl // and don't reset the frame. 3307428a18cSKate Stone result.AppendError("Already at the bottom of the stack."); 331213b4546SJim Ingham result.SetStatus(eReturnStatusFailed); 332213b4546SJim Ingham return false; 333b9c1b51eSKate Stone } else 334864174e1SGreg Clayton frame_idx = 0; 335864174e1SGreg Clayton } 336dab6f074SRaphael Isemann } else if (*m_options.relative_frame_offset > 0) { 337b9c1b51eSKate Stone // I don't want "up 20" where "20" takes you past the top of the stack 338b9c1b51eSKate Stone // to produce 339b9c1b51eSKate Stone // an error, but rather to just go to the top. So I have to count the 340b9c1b51eSKate Stone // stack here... 341b0c72a5fSJim Ingham const uint32_t num_frames = thread->GetStackFrameCount(); 342b9c1b51eSKate Stone if (static_cast<int32_t>(num_frames - frame_idx) > 343dab6f074SRaphael Isemann *m_options.relative_frame_offset) 344dab6f074SRaphael Isemann frame_idx += *m_options.relative_frame_offset; 345b9c1b51eSKate Stone else { 346b9c1b51eSKate Stone if (frame_idx == num_frames - 1) { 347b9c1b51eSKate Stone // If we are already at the top of the stack, just warn and don't 348b9c1b51eSKate Stone // reset the frame. 3497428a18cSKate Stone result.AppendError("Already at the top of the stack."); 350213b4546SJim Ingham result.SetStatus(eReturnStatusFailed); 351213b4546SJim Ingham return false; 352b9c1b51eSKate Stone } else 353864174e1SGreg Clayton frame_idx = num_frames - 1; 354864174e1SGreg Clayton } 355864174e1SGreg Clayton } 356b9c1b51eSKate Stone } else { 357f965cc86SZachary Turner if (command.GetArgumentCount() > 1) { 358f965cc86SZachary Turner result.AppendErrorWithFormat( 359f965cc86SZachary Turner "too many arguments; expected frame-index, saw '%s'.\n", 360867e7d17SZachary Turner command[0].c_str()); 361f965cc86SZachary Turner m_options.GenerateOptionUsage( 362f965cc86SZachary Turner result.GetErrorStream(), this, 363f965cc86SZachary Turner GetCommandInterpreter().GetDebugger().GetTerminalWidth()); 364f965cc86SZachary Turner return false; 365f965cc86SZachary Turner } 366f965cc86SZachary Turner 367b9c1b51eSKate Stone if (command.GetArgumentCount() == 1) { 3680d9a201eSRaphael Isemann if (command[0].ref().getAsInteger(0, frame_idx)) { 369b9c1b51eSKate Stone result.AppendErrorWithFormat("invalid frame index argument '%s'.", 370f965cc86SZachary Turner command[0].c_str()); 371afbb0af8SJim Ingham result.SetStatus(eReturnStatusFailed); 372afbb0af8SJim Ingham return false; 373afbb0af8SJim Ingham } 374b9c1b51eSKate Stone } else if (command.GetArgumentCount() == 0) { 37582d4a2b9SJason Molenda frame_idx = thread->GetSelectedFrameIndex(); 376b9c1b51eSKate Stone if (frame_idx == UINT32_MAX) { 37782d4a2b9SJason Molenda frame_idx = 0; 37882d4a2b9SJason Molenda } 379864174e1SGreg Clayton } 380864174e1SGreg Clayton } 38130fdc8d8SChris Lattner 382b9c1b51eSKate Stone bool success = thread->SetSelectedFrameByIndexNoisily( 383b9c1b51eSKate Stone frame_idx, result.GetOutputStream()); 384b9c1b51eSKate Stone if (success) { 385f9fc609fSGreg Clayton m_exe_ctx.SetFrameSP(thread->GetSelectedFrame()); 38630fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 387b9c1b51eSKate Stone } else { 388b9c1b51eSKate Stone result.AppendErrorWithFormat("Frame index (%u) out of range.\n", 389b9c1b51eSKate Stone frame_idx); 39030fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 39193208b86SJim Ingham } 39293208b86SJim Ingham 39393208b86SJim Ingham return result.Succeeded(); 39430fdc8d8SChris Lattner } 395864174e1SGreg Clayton 396864174e1SGreg Clayton CommandOptions m_options; 397864174e1SGreg Clayton }; 398864174e1SGreg Clayton 3996d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable 4006d56d2ceSJim Ingham // List images with associated information 401b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed { 4026d56d2ceSJim Ingham public: 4037428a18cSKate Stone CommandObjectFrameVariable(CommandInterpreter &interpreter) 4047428a18cSKate Stone : CommandObjectParsed( 405b9c1b51eSKate Stone interpreter, "frame variable", 406b9c1b51eSKate Stone "Show variables for the current stack frame. Defaults to all " 4077428a18cSKate Stone "arguments and local variables in scope. Names of argument, " 4087428a18cSKate Stone "local, file static and file global variables can be specified. " 409ed8a705cSGreg Clayton "Children of aggregate variables can be specified such as " 410285ae0c0SJim Ingham "'var->child.x'. The -> and [] operators in 'frame variable' do " 411285ae0c0SJim Ingham "not invoke operator overloads if they exist, but directly access " 412285ae0c0SJim Ingham "the specified element. If you want to trigger operator overloads " 413285ae0c0SJim Ingham "use the expression command to print the variable instead." 414285ae0c0SJim Ingham "\nIt is worth noting that except for overloaded " 415285ae0c0SJim Ingham "operators, when printing local variables 'expr local_var' and " 416285ae0c0SJim Ingham "'frame var local_var' produce the same " 417285ae0c0SJim Ingham "results. However, 'frame variable' is more efficient, since it " 418285ae0c0SJim Ingham "uses debug information and memory reads directly, rather than " 419285ae0c0SJim Ingham "parsing and evaluating an expression, which may even involve " 420285ae0c0SJim Ingham "JITing and running code in the target program.", 421a925974bSAdrian Prantl nullptr, 422a925974bSAdrian Prantl eCommandRequiresFrame | eCommandTryTargetAPILock | 423a925974bSAdrian Prantl eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | 424a925974bSAdrian Prantl eCommandRequiresProcess), 425e1cfbc79STodd Fiala m_option_group(), 426b9c1b51eSKate Stone m_option_variable( 427b9c1b51eSKate Stone true), // Include the frame specific options by passing "true" 428a925974bSAdrian Prantl m_option_format(eFormatDefault), m_varobj_options() { 429405fe67fSCaroline Tice CommandArgumentEntry arg; 430405fe67fSCaroline Tice CommandArgumentData var_name_arg; 431405fe67fSCaroline Tice 432405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 433405fe67fSCaroline Tice var_name_arg.arg_type = eArgTypeVarName; 434405fe67fSCaroline Tice var_name_arg.arg_repetition = eArgRepeatStar; 435405fe67fSCaroline Tice 436b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 437b9c1b51eSKate Stone // argument entry. 438405fe67fSCaroline Tice arg.push_back(var_name_arg); 439405fe67fSCaroline Tice 440405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 441405fe67fSCaroline Tice m_arguments.push_back(arg); 4422837b766SJim Ingham 443715c2365SGreg Clayton m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 444b9c1b51eSKate Stone m_option_group.Append(&m_option_format, 445b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_FORMAT | 446b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_GDB_FMT, 447b9c1b51eSKate Stone LLDB_OPT_SET_1); 4482837b766SJim Ingham m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 4492837b766SJim Ingham m_option_group.Finalize(); 4506d56d2ceSJim Ingham } 4516d56d2ceSJim Ingham 452c8ecc2a9SEugene Zelenko ~CommandObjectFrameVariable() override = default; 4536d56d2ceSJim Ingham 454b9c1b51eSKate Stone Options *GetOptions() override { return &m_option_group; } 455f21feadcSGreg Clayton 456ae34ed2cSRaphael Isemann void 457ae34ed2cSRaphael Isemann HandleArgumentCompletion(CompletionRequest &request, 4582443bbd4SRaphael Isemann OptionElementVector &opt_element_vector) override { 459f21feadcSGreg Clayton // Arguments are the standard source file completer. 460b9c1b51eSKate Stone CommandCompletions::InvokeCommonCompletionCallbacks( 461b9c1b51eSKate Stone GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, 462a2e76c0bSRaphael Isemann request, nullptr); 463f21feadcSGreg Clayton } 4646d56d2ceSJim Ingham 4655a988416SJim Ingham protected: 46673418dfeSEnrico Granata llvm::StringRef GetScopeString(VariableSP var_sp) { 46773418dfeSEnrico Granata if (!var_sp) 46873418dfeSEnrico Granata return llvm::StringRef::withNullAsEmpty(nullptr); 46973418dfeSEnrico Granata 47073418dfeSEnrico Granata switch (var_sp->GetScope()) { 47173418dfeSEnrico Granata case eValueTypeVariableGlobal: 47273418dfeSEnrico Granata return "GLOBAL: "; 47373418dfeSEnrico Granata case eValueTypeVariableStatic: 47473418dfeSEnrico Granata return "STATIC: "; 47573418dfeSEnrico Granata case eValueTypeVariableArgument: 47673418dfeSEnrico Granata return "ARG: "; 47773418dfeSEnrico Granata case eValueTypeVariableLocal: 47873418dfeSEnrico Granata return "LOCAL: "; 47973418dfeSEnrico Granata case eValueTypeVariableThreadLocal: 48073418dfeSEnrico Granata return "THREAD: "; 48173418dfeSEnrico Granata default: 48273418dfeSEnrico Granata break; 48373418dfeSEnrico Granata } 48473418dfeSEnrico Granata 48573418dfeSEnrico Granata return llvm::StringRef::withNullAsEmpty(nullptr); 48673418dfeSEnrico Granata } 48773418dfeSEnrico Granata 488b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 48905097246SAdrian Prantl // No need to check "frame" for validity as eCommandRequiresFrame ensures 49005097246SAdrian Prantl // it is valid 491b57e4a1bSJason Molenda StackFrame *frame = m_exe_ctx.GetFramePtr(); 4921e49e5e7SJohnny Chen 493a134cc1bSGreg Clayton Stream &s = result.GetOutputStream(); 4946d56d2ceSJim Ingham 495b9c1b51eSKate Stone // Be careful about the stack frame, if any summary formatter runs code, it 49605097246SAdrian Prantl // might clear the StackFrameList for the thread. So hold onto a shared 49705097246SAdrian Prantl // pointer to the frame so it stays alive. 498650543f9SJim Ingham 499b9c1b51eSKate Stone VariableList *variable_list = 500b9c1b51eSKate Stone frame->GetVariableList(m_option_variable.show_globals); 501a134cc1bSGreg Clayton 5026d56d2ceSJim Ingham VariableSP var_sp; 5036d56d2ceSJim Ingham ValueObjectSP valobj_sp; 50478a685aaSJim Ingham 505061858ceSEnrico Granata TypeSummaryImplSP summary_format_sp; 50617b11749SEnrico Granata if (!m_option_variable.summary.IsCurrentValueEmpty()) 507b9c1b51eSKate Stone DataVisualization::NamedSummaryFormats::GetSummaryFormat( 508b9c1b51eSKate Stone ConstString(m_option_variable.summary.GetCurrentValue()), 509b9c1b51eSKate Stone summary_format_sp); 51017b11749SEnrico Granata else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 511796ac80bSJonas Devlieghere summary_format_sp = std::make_shared<StringSummaryFormat>( 512b9c1b51eSKate Stone TypeSummaryImpl::Flags(), 513796ac80bSJonas Devlieghere m_option_variable.summary_string.GetCurrentValue()); 514f9fa6ee5SEnrico Granata 515b9c1b51eSKate Stone DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( 516b9c1b51eSKate Stone eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault, 517b9c1b51eSKate Stone summary_format_sp)); 518379447a7SEnrico Granata 519b9c1b51eSKate Stone const SymbolContext &sym_ctx = 520b9c1b51eSKate Stone frame->GetSymbolContext(eSymbolContextFunction); 5216754e04fSEnrico Granata if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 5226754e04fSEnrico Granata m_option_variable.show_globals = true; 5236754e04fSEnrico Granata 524b9c1b51eSKate Stone if (variable_list) { 5251deb7962SGreg Clayton const Format format = m_option_format.GetFormat(); 5260c489f58SEnrico Granata options.SetFormat(format); 5271deb7962SGreg Clayton 52811eb9c64SZachary Turner if (!command.empty()) { 52946747022SGreg Clayton VariableList regex_var_list; 53046747022SGreg Clayton 53105097246SAdrian Prantl // If we have any args to the variable command, we will make variable 53205097246SAdrian Prantl // objects from them... 533f965cc86SZachary Turner for (auto &entry : command) { 534b9c1b51eSKate Stone if (m_option_variable.use_regex) { 535c7bece56SGreg Clayton const size_t regex_start_index = regex_var_list.GetSize(); 5360d9a201eSRaphael Isemann llvm::StringRef name_str = entry.ref(); 53795eae423SZachary Turner RegularExpression regex(name_str); 538f9d90bc5SJan Kratochvil if (regex.IsValid()) { 53946747022SGreg Clayton size_t num_matches = 0; 540b9c1b51eSKate Stone const size_t num_new_regex_vars = 541b9c1b51eSKate Stone variable_list->AppendVariablesIfUnique(regex, regex_var_list, 54278a685aaSJim Ingham num_matches); 543b9c1b51eSKate Stone if (num_new_regex_vars > 0) { 544b9c1b51eSKate Stone for (size_t regex_idx = regex_start_index, 545b9c1b51eSKate Stone end_index = regex_var_list.GetSize(); 546b9c1b51eSKate Stone regex_idx < end_index; ++regex_idx) { 54746747022SGreg Clayton var_sp = regex_var_list.GetVariableAtIndex(regex_idx); 548b9c1b51eSKate Stone if (var_sp) { 549b9c1b51eSKate Stone valobj_sp = frame->GetValueObjectForFrameVariable( 550b9c1b51eSKate Stone var_sp, m_varobj_options.use_dynamic); 551b9c1b51eSKate Stone if (valobj_sp) { 55273418dfeSEnrico Granata std::string scope_string; 55373418dfeSEnrico Granata if (m_option_variable.show_scope) 55473418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 55573418dfeSEnrico Granata 55673418dfeSEnrico Granata if (!scope_string.empty()) 557771ef6d4SMalcolm Parsons s.PutCString(scope_string); 55873418dfeSEnrico Granata 559b9c1b51eSKate Stone if (m_option_variable.show_decl && 560b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 56145ba8543SGreg Clayton bool show_fullpaths = false; 56245ba8543SGreg Clayton bool show_module = true; 563b9c1b51eSKate Stone if (var_sp->DumpDeclaration(&s, show_fullpaths, 564b9c1b51eSKate Stone show_module)) 56546747022SGreg Clayton s.PutCString(": "); 56646747022SGreg Clayton } 5674d93b8cdSEnrico Granata valobj_sp->Dump(result.GetOutputStream(), options); 56846747022SGreg Clayton } 56946747022SGreg Clayton } 57046747022SGreg Clayton } 571b9c1b51eSKate Stone } else if (num_matches == 0) { 572b9c1b51eSKate Stone result.GetErrorStream().Printf("error: no variables matched " 573b9c1b51eSKate Stone "the regular expression '%s'.\n", 574f965cc86SZachary Turner entry.c_str()); 57546747022SGreg Clayton } 576b9c1b51eSKate Stone } else { 5773af3f1e8SJonas Devlieghere if (llvm::Error err = regex.GetError()) 5783af3f1e8SJonas Devlieghere result.GetErrorStream().Printf( 5793af3f1e8SJonas Devlieghere "error: %s\n", llvm::toString(std::move(err)).c_str()); 58046747022SGreg Clayton else 581b9c1b51eSKate Stone result.GetErrorStream().Printf( 582b9c1b51eSKate Stone "error: unknown regex error when compiling '%s'\n", 583f965cc86SZachary Turner entry.c_str()); 58446747022SGreg Clayton } 585b9c1b51eSKate Stone } else // No regex, either exact variable names or variable 586b9c1b51eSKate Stone // expressions. 58746747022SGreg Clayton { 58897206d57SZachary Turner Status error; 589b9c1b51eSKate Stone uint32_t expr_path_options = 590b9c1b51eSKate Stone StackFrame::eExpressionPathOptionCheckPtrVsMember | 59146252398SEnrico Granata StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 59246252398SEnrico Granata StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 5932837b766SJim Ingham lldb::VariableSP var_sp; 594b9c1b51eSKate Stone valobj_sp = frame->GetValueForVariableExpressionPath( 5950d9a201eSRaphael Isemann entry.ref(), m_varobj_options.use_dynamic, expr_path_options, 596b9c1b51eSKate Stone var_sp, error); 597b9c1b51eSKate Stone if (valobj_sp) { 59873418dfeSEnrico Granata std::string scope_string; 59973418dfeSEnrico Granata if (m_option_variable.show_scope) 60073418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 60173418dfeSEnrico Granata 60273418dfeSEnrico Granata if (!scope_string.empty()) 603771ef6d4SMalcolm Parsons s.PutCString(scope_string); 604b9c1b51eSKate Stone if (m_option_variable.show_decl && var_sp && 605b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 606a134cc1bSGreg Clayton var_sp->GetDeclaration().DumpStopContext(&s, false); 607a134cc1bSGreg Clayton s.PutCString(": "); 608a134cc1bSGreg Clayton } 6090c489f58SEnrico Granata 6100c489f58SEnrico Granata options.SetFormat(format); 611b9c1b51eSKate Stone options.SetVariableFormatDisplayLanguage( 612b9c1b51eSKate Stone valobj_sp->GetPreferredDisplayLanguage()); 613887062aeSJohnny Chen 614887062aeSJohnny Chen Stream &output_stream = result.GetOutputStream(); 615f965cc86SZachary Turner options.SetRootValueObjectName( 616f965cc86SZachary Turner valobj_sp->GetParent() ? entry.c_str() : nullptr); 6174d93b8cdSEnrico Granata valobj_sp->Dump(output_stream, options); 618b9c1b51eSKate Stone } else { 619c8ecc2a9SEugene Zelenko const char *error_cstr = error.AsCString(nullptr); 62054979cddSGreg Clayton if (error_cstr) 62154979cddSGreg Clayton result.GetErrorStream().Printf("error: %s\n", error_cstr); 62254979cddSGreg Clayton else 623b9c1b51eSKate Stone result.GetErrorStream().Printf("error: unable to find any " 624b9c1b51eSKate Stone "variable expression path that " 625b9c1b51eSKate Stone "matches '%s'.\n", 626f965cc86SZachary Turner entry.c_str()); 6276d56d2ceSJim Ingham } 6286d56d2ceSJim Ingham } 6296d56d2ceSJim Ingham } 630b9c1b51eSKate Stone } else // No command arg specified. Use variable_list, instead. 6316d56d2ceSJim Ingham { 632c7bece56SGreg Clayton const size_t num_variables = variable_list->GetSize(); 633b9c1b51eSKate Stone if (num_variables > 0) { 634b9c1b51eSKate Stone for (size_t i = 0; i < num_variables; i++) { 6351a65ae11SGreg Clayton var_sp = variable_list->GetVariableAtIndex(i); 636f955efc0SSylvestre Ledru switch (var_sp->GetScope()) { 637eb236735SJim Ingham case eValueTypeVariableGlobal: 638eb236735SJim Ingham if (!m_option_variable.show_globals) 639eb236735SJim Ingham continue; 640eb236735SJim Ingham break; 641eb236735SJim Ingham case eValueTypeVariableStatic: 642eb236735SJim Ingham if (!m_option_variable.show_globals) 643eb236735SJim Ingham continue; 644eb236735SJim Ingham break; 645eb236735SJim Ingham case eValueTypeVariableArgument: 646eb236735SJim Ingham if (!m_option_variable.show_args) 647eb236735SJim Ingham continue; 648eb236735SJim Ingham break; 649eb236735SJim Ingham case eValueTypeVariableLocal: 650eb236735SJim Ingham if (!m_option_variable.show_locals) 651eb236735SJim Ingham continue; 652eb236735SJim Ingham break; 653eb236735SJim Ingham default: 654eb236735SJim Ingham continue; 655eb236735SJim Ingham break; 656eb236735SJim Ingham } 657560558ebSEnrico Granata std::string scope_string; 658eb236735SJim Ingham if (m_option_variable.show_scope) 65973418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 6606d56d2ceSJim Ingham 66105097246SAdrian Prantl // Use the variable object code to make sure we are using the same 66205097246SAdrian Prantl // APIs as the public API will be using... 663b9c1b51eSKate Stone valobj_sp = frame->GetValueObjectForFrameVariable( 664b9c1b51eSKate Stone var_sp, m_varobj_options.use_dynamic); 665b9c1b51eSKate Stone if (valobj_sp) { 66605097246SAdrian Prantl // When dumping all variables, don't print any variables that are 66705097246SAdrian Prantl // not in scope to avoid extra unneeded output 668b9c1b51eSKate Stone if (valobj_sp->IsInScope()) { 669b9c1b51eSKate Stone if (!valobj_sp->GetTargetSP() 670b9c1b51eSKate Stone ->GetDisplayRuntimeSupportValues() && 671c8ecc2a9SEugene Zelenko valobj_sp->IsRuntimeSupportValue()) 672560558ebSEnrico Granata continue; 673560558ebSEnrico Granata 674560558ebSEnrico Granata if (!scope_string.empty()) 675771ef6d4SMalcolm Parsons s.PutCString(scope_string); 676560558ebSEnrico Granata 677b9c1b51eSKate Stone if (m_option_variable.show_decl && 678b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 679a134cc1bSGreg Clayton var_sp->GetDeclaration().DumpStopContext(&s, false); 680a134cc1bSGreg Clayton s.PutCString(": "); 681a134cc1bSGreg Clayton } 6820c489f58SEnrico Granata 6830c489f58SEnrico Granata options.SetFormat(format); 684b9c1b51eSKate Stone options.SetVariableFormatDisplayLanguage( 685b9c1b51eSKate Stone valobj_sp->GetPreferredDisplayLanguage()); 686f965cc86SZachary Turner options.SetRootValueObjectName( 687f965cc86SZachary Turner var_sp ? var_sp->GetName().AsCString() : nullptr); 6884d93b8cdSEnrico Granata valobj_sp->Dump(result.GetOutputStream(), options); 689a134cc1bSGreg Clayton } 690a134cc1bSGreg Clayton } 6916d56d2ceSJim Ingham } 6926d56d2ceSJim Ingham } 6936d56d2ceSJim Ingham } 6946d56d2ceSJim Ingham result.SetStatus(eReturnStatusSuccessFinishResult); 6956d56d2ceSJim Ingham } 69661a80ba6SEnrico Granata 69741ae8e74SKuba Mracek if (m_option_variable.show_recognized_args) { 69841ae8e74SKuba Mracek auto recognized_frame = frame->GetRecognizedFrame(); 69941ae8e74SKuba Mracek if (recognized_frame) { 70041ae8e74SKuba Mracek ValueObjectListSP recognized_arg_list = 70141ae8e74SKuba Mracek recognized_frame->GetRecognizedArguments(); 70241ae8e74SKuba Mracek if (recognized_arg_list) { 70341ae8e74SKuba Mracek for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { 70441ae8e74SKuba Mracek options.SetFormat(m_option_format.GetFormat()); 70541ae8e74SKuba Mracek options.SetVariableFormatDisplayLanguage( 70641ae8e74SKuba Mracek rec_value_sp->GetPreferredDisplayLanguage()); 70741ae8e74SKuba Mracek options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); 70841ae8e74SKuba Mracek rec_value_sp->Dump(result.GetOutputStream(), options); 70941ae8e74SKuba Mracek } 71041ae8e74SKuba Mracek } 71141ae8e74SKuba Mracek } 71241ae8e74SKuba Mracek } 71341ae8e74SKuba Mracek 714b9c1b51eSKate Stone if (m_interpreter.TruncationWarningNecessary()) { 71561a80ba6SEnrico Granata result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 71661a80ba6SEnrico Granata m_cmd_name.c_str()); 71761a80ba6SEnrico Granata m_interpreter.TruncationWarningGiven(); 71861a80ba6SEnrico Granata } 71961a80ba6SEnrico Granata 72024fff242SDavide Italiano // Increment statistics. 72124fff242SDavide Italiano bool res = result.Succeeded(); 722cb2380c9SRaphael Isemann Target &target = GetSelectedOrDummyTarget(); 72324fff242SDavide Italiano if (res) 724cb2380c9SRaphael Isemann target.IncrementStats(StatisticKind::FrameVarSuccess); 72524fff242SDavide Italiano else 726cb2380c9SRaphael Isemann target.IncrementStats(StatisticKind::FrameVarFailure); 72724fff242SDavide Italiano return res; 7286d56d2ceSJim Ingham } 7296d56d2ceSJim Ingham 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': 761db31e2e1SMed Ismail Bennani m_symbols.push_back(std::string(option_arg)); 76241ae8e74SKuba Mracek break; 76341ae8e74SKuba Mracek case 'x': 76441ae8e74SKuba Mracek m_regex = true; 76541ae8e74SKuba Mracek break; 76641ae8e74SKuba Mracek default: 76736162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 76841ae8e74SKuba Mracek } 76941ae8e74SKuba Mracek 77041ae8e74SKuba Mracek return error; 77141ae8e74SKuba Mracek } 77241ae8e74SKuba Mracek 77341ae8e74SKuba Mracek void OptionParsingStarting(ExecutionContext *execution_context) override { 77441ae8e74SKuba Mracek m_module = ""; 775db31e2e1SMed Ismail Bennani m_symbols.clear(); 77641ae8e74SKuba Mracek m_class_name = ""; 77741ae8e74SKuba Mracek m_regex = false; 77841ae8e74SKuba Mracek } 77941ae8e74SKuba Mracek 78041ae8e74SKuba Mracek llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 78141ae8e74SKuba Mracek return llvm::makeArrayRef(g_frame_recognizer_add_options); 78241ae8e74SKuba Mracek } 78341ae8e74SKuba Mracek 78441ae8e74SKuba Mracek // Instance variables to hold the values for command options. 78541ae8e74SKuba Mracek std::string m_class_name; 78641ae8e74SKuba Mracek std::string m_module; 787db31e2e1SMed Ismail Bennani std::vector<std::string> m_symbols; 78841ae8e74SKuba Mracek bool m_regex; 78941ae8e74SKuba Mracek }; 79041ae8e74SKuba Mracek 79141ae8e74SKuba Mracek CommandOptions m_options; 79241ae8e74SKuba Mracek 79341ae8e74SKuba Mracek Options *GetOptions() override { return &m_options; } 79441ae8e74SKuba Mracek 79541ae8e74SKuba Mracek protected: 79641ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override; 79741ae8e74SKuba Mracek 79841ae8e74SKuba Mracek public: 79941ae8e74SKuba Mracek CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 80041ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer add", 80141ae8e74SKuba Mracek "Add a new frame recognizer.", nullptr), 80241ae8e74SKuba Mracek m_options() { 80341ae8e74SKuba Mracek SetHelpLong(R"( 80441ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on 80541ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source 80641ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments 80741ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments. 80841ae8e74SKuba Mracek 80941ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class 81041ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a 81141ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type 81241ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize. 81341ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that 81441ae8e74SKuba Mracek represent the recognized arguments. 81541ae8e74SKuba Mracek 81641ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc 81741ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows: 81841ae8e74SKuba Mracek 81941ae8e74SKuba Mracek class LibcFdRecognizer(object): 82041ae8e74SKuba Mracek def get_recognized_arguments(self, frame): 82141ae8e74SKuba Mracek if frame.name in ["read", "write", "close"]: 82241ae8e74SKuba Mracek fd = frame.EvaluateExpression("$arg1").unsigned 82341ae8e74SKuba Mracek value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) 82441ae8e74SKuba Mracek return [value] 82541ae8e74SKuba Mracek return [] 82641ae8e74SKuba Mracek 82741ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script 82841ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'. 82941ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is 83041ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 83141ae8e74SKuba Mracek in other modules: 83241ae8e74SKuba Mracek 83341ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py 83441ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 83541ae8e74SKuba Mracek 83641ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we 83741ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable': 83841ae8e74SKuba Mracek 83941ae8e74SKuba Mracek (lldb) b read 84041ae8e74SKuba Mracek (lldb) r 84141ae8e74SKuba Mracek Process 1234 stopped 84241ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 84341ae8e74SKuba Mracek frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 84441ae8e74SKuba Mracek (lldb) frame variable 84541ae8e74SKuba Mracek (int) fd = 3 84641ae8e74SKuba Mracek 84741ae8e74SKuba Mracek )"); 84841ae8e74SKuba Mracek } 84941ae8e74SKuba Mracek ~CommandObjectFrameRecognizerAdd() override = default; 85041ae8e74SKuba Mracek }; 85141ae8e74SKuba Mracek 85241ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 85341ae8e74SKuba Mracek CommandReturnObject &result) { 8544e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON 85541ae8e74SKuba Mracek if (m_options.m_class_name.empty()) { 85641ae8e74SKuba Mracek result.AppendErrorWithFormat( 85741ae8e74SKuba Mracek "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 85841ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 85941ae8e74SKuba Mracek return false; 86041ae8e74SKuba Mracek } 86141ae8e74SKuba Mracek 86241ae8e74SKuba Mracek if (m_options.m_module.empty()) { 86341ae8e74SKuba Mracek result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 86441ae8e74SKuba Mracek m_cmd_name.c_str()); 86541ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 86641ae8e74SKuba Mracek return false; 86741ae8e74SKuba Mracek } 86841ae8e74SKuba Mracek 869db31e2e1SMed Ismail Bennani if (m_options.m_symbols.empty()) { 870db31e2e1SMed Ismail Bennani result.AppendErrorWithFormat( 871db31e2e1SMed Ismail Bennani "%s needs at least one symbol name (-n argument).\n", 872db31e2e1SMed Ismail Bennani m_cmd_name.c_str()); 873db31e2e1SMed Ismail Bennani result.SetStatus(eReturnStatusFailed); 874db31e2e1SMed Ismail Bennani return false; 875db31e2e1SMed Ismail Bennani } 876db31e2e1SMed Ismail Bennani 877db31e2e1SMed Ismail Bennani if (m_options.m_regex && m_options.m_symbols.size() > 1) { 878db31e2e1SMed Ismail Bennani result.AppendErrorWithFormat( 879db31e2e1SMed Ismail Bennani "%s needs only one symbol regular expression (-n argument).\n", 88041ae8e74SKuba Mracek m_cmd_name.c_str()); 88141ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 88241ae8e74SKuba Mracek return false; 88341ae8e74SKuba Mracek } 88441ae8e74SKuba Mracek 8852b29b432SJonas Devlieghere ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 88641ae8e74SKuba Mracek 88741ae8e74SKuba Mracek if (interpreter && 88841ae8e74SKuba Mracek !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 889a925974bSAdrian Prantl result.AppendWarning("The provided class does not exist - please define it " 89041ae8e74SKuba Mracek "before attempting to use this frame recognizer"); 89141ae8e74SKuba Mracek } 89241ae8e74SKuba Mracek 89341ae8e74SKuba Mracek StackFrameRecognizerSP recognizer_sp = 89441ae8e74SKuba Mracek StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 89541ae8e74SKuba Mracek interpreter, m_options.m_class_name.c_str())); 89641ae8e74SKuba Mracek if (m_options.m_regex) { 89741ae8e74SKuba Mracek auto module = 89841ae8e74SKuba Mracek RegularExpressionSP(new RegularExpression(m_options.m_module)); 89941ae8e74SKuba Mracek auto func = 900db31e2e1SMed Ismail Bennani RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); 9011b7c9eaeSRaphael Isemann GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 9021b7c9eaeSRaphael Isemann recognizer_sp, module, func); 90341ae8e74SKuba Mracek } else { 90441ae8e74SKuba Mracek auto module = ConstString(m_options.m_module); 905db31e2e1SMed Ismail Bennani std::vector<ConstString> symbols(m_options.m_symbols.begin(), 906db31e2e1SMed Ismail Bennani m_options.m_symbols.end()); 9071b7c9eaeSRaphael Isemann GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( 9081b7c9eaeSRaphael Isemann recognizer_sp, module, symbols); 90941ae8e74SKuba Mracek } 910f80d2655SKuba Mracek #endif 91141ae8e74SKuba Mracek 91241ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishNoResult); 91341ae8e74SKuba Mracek return result.Succeeded(); 91441ae8e74SKuba Mracek } 91541ae8e74SKuba Mracek 91641ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 91741ae8e74SKuba Mracek public: 91841ae8e74SKuba Mracek CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 91941ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer clear", 92041ae8e74SKuba Mracek "Delete all frame recognizers.", nullptr) {} 92141ae8e74SKuba Mracek 92241ae8e74SKuba Mracek ~CommandObjectFrameRecognizerClear() override = default; 92341ae8e74SKuba Mracek 92441ae8e74SKuba Mracek protected: 92541ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 9261b7c9eaeSRaphael Isemann GetSelectedOrDummyTarget() 9271b7c9eaeSRaphael Isemann .GetFrameRecognizerManager() 9281b7c9eaeSRaphael Isemann .RemoveAllRecognizers(); 92941ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 93041ae8e74SKuba Mracek return result.Succeeded(); 93141ae8e74SKuba Mracek } 93241ae8e74SKuba Mracek }; 93341ae8e74SKuba Mracek 93441ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 93541ae8e74SKuba Mracek public: 93641ae8e74SKuba Mracek CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 93741ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer delete", 93841ae8e74SKuba Mracek "Delete an existing frame recognizer.", nullptr) {} 93941ae8e74SKuba Mracek 94041ae8e74SKuba Mracek ~CommandObjectFrameRecognizerDelete() override = default; 94141ae8e74SKuba Mracek 942c37d25f0SGongyu Deng void 943c37d25f0SGongyu Deng HandleArgumentCompletion(CompletionRequest &request, 944c37d25f0SGongyu Deng OptionElementVector &opt_element_vector) override { 945c37d25f0SGongyu Deng if (request.GetCursorIndex() != 0) 946c37d25f0SGongyu Deng return; 947c37d25f0SGongyu Deng 9481b7c9eaeSRaphael Isemann GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 949c37d25f0SGongyu Deng [&request](uint32_t rid, std::string rname, std::string module, 950c37d25f0SGongyu Deng llvm::ArrayRef<lldb_private::ConstString> symbols, 951c37d25f0SGongyu Deng bool regexp) { 952c37d25f0SGongyu Deng StreamString strm; 953c37d25f0SGongyu Deng if (rname.empty()) 954c37d25f0SGongyu Deng rname = "(internal)"; 955c37d25f0SGongyu Deng 956c37d25f0SGongyu Deng strm << rname; 957c37d25f0SGongyu Deng if (!module.empty()) 958c37d25f0SGongyu Deng strm << ", module " << module; 959c37d25f0SGongyu Deng if (!symbols.empty()) 960c37d25f0SGongyu Deng for (auto &symbol : symbols) 961c37d25f0SGongyu Deng strm << ", symbol " << symbol; 962c37d25f0SGongyu Deng if (regexp) 963c37d25f0SGongyu Deng strm << " (regexp)"; 964c37d25f0SGongyu Deng 965c37d25f0SGongyu Deng request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString()); 966c37d25f0SGongyu Deng }); 967c37d25f0SGongyu Deng } 968c37d25f0SGongyu Deng 96941ae8e74SKuba Mracek protected: 97041ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 97141ae8e74SKuba Mracek if (command.GetArgumentCount() == 0) { 97241ae8e74SKuba Mracek if (!m_interpreter.Confirm( 97341ae8e74SKuba Mracek "About to delete all frame recognizers, do you want to do that?", 97441ae8e74SKuba Mracek true)) { 97541ae8e74SKuba Mracek result.AppendMessage("Operation cancelled..."); 97641ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 97741ae8e74SKuba Mracek return false; 97841ae8e74SKuba Mracek } 97941ae8e74SKuba Mracek 9801b7c9eaeSRaphael Isemann GetSelectedOrDummyTarget() 9811b7c9eaeSRaphael Isemann .GetFrameRecognizerManager() 9821b7c9eaeSRaphael Isemann .RemoveAllRecognizers(); 98341ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 98441ae8e74SKuba Mracek return result.Succeeded(); 98541ae8e74SKuba Mracek } 98641ae8e74SKuba Mracek 98741ae8e74SKuba Mracek if (command.GetArgumentCount() != 1) { 98841ae8e74SKuba Mracek result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 98941ae8e74SKuba Mracek m_cmd_name.c_str()); 99041ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 99141ae8e74SKuba Mracek return false; 99241ae8e74SKuba Mracek } 99341ae8e74SKuba Mracek 9949010cef2SRaphael Isemann uint32_t recognizer_id; 9959010cef2SRaphael Isemann if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) { 9969010cef2SRaphael Isemann result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 9979010cef2SRaphael Isemann command.GetArgumentAtIndex(0)); 9989010cef2SRaphael Isemann result.SetStatus(eReturnStatusFailed); 9999010cef2SRaphael Isemann return false; 10009010cef2SRaphael Isemann } 100141ae8e74SKuba Mracek 1002*5477fbc2SRaphael Isemann if (!GetSelectedOrDummyTarget() 10031b7c9eaeSRaphael Isemann .GetFrameRecognizerManager() 1004*5477fbc2SRaphael Isemann .RemoveRecognizerWithID(recognizer_id)) { 1005*5477fbc2SRaphael Isemann result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", 1006*5477fbc2SRaphael Isemann command.GetArgumentAtIndex(0)); 1007*5477fbc2SRaphael Isemann result.SetStatus(eReturnStatusFailed); 1008*5477fbc2SRaphael Isemann return false; 1009*5477fbc2SRaphael Isemann } 101041ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 101141ae8e74SKuba Mracek return result.Succeeded(); 101241ae8e74SKuba Mracek } 101341ae8e74SKuba Mracek }; 101441ae8e74SKuba Mracek 101541ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed { 101641ae8e74SKuba Mracek public: 101741ae8e74SKuba Mracek CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 101841ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer list", 101941ae8e74SKuba Mracek "Show a list of active frame recognizers.", 102041ae8e74SKuba Mracek nullptr) {} 102141ae8e74SKuba Mracek 102241ae8e74SKuba Mracek ~CommandObjectFrameRecognizerList() override = default; 102341ae8e74SKuba Mracek 102441ae8e74SKuba Mracek protected: 102541ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 102641ae8e74SKuba Mracek bool any_printed = false; 10271b7c9eaeSRaphael Isemann GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( 1028db31e2e1SMed Ismail Bennani [&result, &any_printed]( 1029db31e2e1SMed Ismail Bennani uint32_t recognizer_id, std::string name, std::string module, 1030db31e2e1SMed Ismail Bennani llvm::ArrayRef<ConstString> symbols, bool regexp) { 1031cb0c4ee3SMed Ismail Bennani Stream &stream = result.GetOutputStream(); 1032cb0c4ee3SMed Ismail Bennani 1033cb0c4ee3SMed Ismail Bennani if (name.empty()) 1034a925974bSAdrian Prantl name = "(internal)"; 1035cb0c4ee3SMed Ismail Bennani 1036cb0c4ee3SMed Ismail Bennani stream << std::to_string(recognizer_id) << ": " << name; 1037cb0c4ee3SMed Ismail Bennani if (!module.empty()) 1038cb0c4ee3SMed Ismail Bennani stream << ", module " << module; 1039db31e2e1SMed Ismail Bennani if (!symbols.empty()) 1040db31e2e1SMed Ismail Bennani for (auto &symbol : symbols) 1041db31e2e1SMed Ismail Bennani stream << ", symbol " << symbol; 1042cb0c4ee3SMed Ismail Bennani if (regexp) 1043cb0c4ee3SMed Ismail Bennani stream << " (regexp)"; 1044cb0c4ee3SMed Ismail Bennani 1045cb0c4ee3SMed Ismail Bennani stream.EOL(); 1046cb0c4ee3SMed Ismail Bennani stream.Flush(); 1047cb0c4ee3SMed Ismail Bennani 104841ae8e74SKuba Mracek any_printed = true; 104941ae8e74SKuba Mracek }); 105041ae8e74SKuba Mracek 105141ae8e74SKuba Mracek if (any_printed) 105241ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 105341ae8e74SKuba Mracek else { 105441ae8e74SKuba Mracek result.GetOutputStream().PutCString("no matching results found.\n"); 105541ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishNoResult); 105641ae8e74SKuba Mracek } 105741ae8e74SKuba Mracek return result.Succeeded(); 105841ae8e74SKuba Mracek } 105941ae8e74SKuba Mracek }; 106041ae8e74SKuba Mracek 106141ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 106241ae8e74SKuba Mracek public: 106341ae8e74SKuba Mracek CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 106441ae8e74SKuba Mracek : CommandObjectParsed( 106541ae8e74SKuba Mracek interpreter, "frame recognizer info", 106641ae8e74SKuba Mracek "Show which frame recognizer is applied a stack frame (if any).", 106741ae8e74SKuba Mracek nullptr) { 106841ae8e74SKuba Mracek CommandArgumentEntry arg; 106941ae8e74SKuba Mracek CommandArgumentData index_arg; 107041ae8e74SKuba Mracek 107141ae8e74SKuba Mracek // Define the first (and only) variant of this arg. 107241ae8e74SKuba Mracek index_arg.arg_type = eArgTypeFrameIndex; 107341ae8e74SKuba Mracek index_arg.arg_repetition = eArgRepeatPlain; 107441ae8e74SKuba Mracek 107541ae8e74SKuba Mracek // There is only one variant this argument could be; put it into the 107641ae8e74SKuba Mracek // argument entry. 107741ae8e74SKuba Mracek arg.push_back(index_arg); 107841ae8e74SKuba Mracek 107941ae8e74SKuba Mracek // Push the data for the first argument into the m_arguments vector. 108041ae8e74SKuba Mracek m_arguments.push_back(arg); 108141ae8e74SKuba Mracek } 108241ae8e74SKuba Mracek 108341ae8e74SKuba Mracek ~CommandObjectFrameRecognizerInfo() override = default; 108441ae8e74SKuba Mracek 108541ae8e74SKuba Mracek protected: 108641ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 10879010cef2SRaphael Isemann const char *frame_index_str = command.GetArgumentAtIndex(0); 10889010cef2SRaphael Isemann uint32_t frame_index; 10899010cef2SRaphael Isemann if (!llvm::to_integer(frame_index_str, frame_index)) { 10909010cef2SRaphael Isemann result.AppendErrorWithFormat("'%s' is not a valid frame index.", 10919010cef2SRaphael Isemann frame_index_str); 10929010cef2SRaphael Isemann result.SetStatus(eReturnStatusFailed); 10939010cef2SRaphael Isemann return false; 10949010cef2SRaphael Isemann } 10959010cef2SRaphael Isemann 109641ae8e74SKuba Mracek Process *process = m_exe_ctx.GetProcessPtr(); 109741ae8e74SKuba Mracek if (process == nullptr) { 109841ae8e74SKuba Mracek result.AppendError("no process"); 109941ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 110041ae8e74SKuba Mracek return false; 110141ae8e74SKuba Mracek } 110241ae8e74SKuba Mracek Thread *thread = m_exe_ctx.GetThreadPtr(); 110341ae8e74SKuba Mracek if (thread == nullptr) { 110441ae8e74SKuba Mracek result.AppendError("no thread"); 110541ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 110641ae8e74SKuba Mracek return false; 110741ae8e74SKuba Mracek } 110841ae8e74SKuba Mracek if (command.GetArgumentCount() != 1) { 110941ae8e74SKuba Mracek result.AppendErrorWithFormat( 111041ae8e74SKuba Mracek "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 111141ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 111241ae8e74SKuba Mracek return false; 111341ae8e74SKuba Mracek } 111441ae8e74SKuba Mracek 111541ae8e74SKuba Mracek StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 111641ae8e74SKuba Mracek if (!frame_sp) { 111741ae8e74SKuba Mracek result.AppendErrorWithFormat("no frame with index %u", frame_index); 111841ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 111941ae8e74SKuba Mracek return false; 112041ae8e74SKuba Mracek } 112141ae8e74SKuba Mracek 11221b7c9eaeSRaphael Isemann auto recognizer = GetSelectedOrDummyTarget() 11231b7c9eaeSRaphael Isemann .GetFrameRecognizerManager() 11241b7c9eaeSRaphael Isemann .GetRecognizerForFrame(frame_sp); 112541ae8e74SKuba Mracek 112641ae8e74SKuba Mracek Stream &output_stream = result.GetOutputStream(); 112741ae8e74SKuba Mracek output_stream.Printf("frame %d ", frame_index); 112841ae8e74SKuba Mracek if (recognizer) { 112941ae8e74SKuba Mracek output_stream << "is recognized by "; 113041ae8e74SKuba Mracek output_stream << recognizer->GetName(); 113141ae8e74SKuba Mracek } else { 113241ae8e74SKuba Mracek output_stream << "not recognized by any recognizer"; 113341ae8e74SKuba Mracek } 113441ae8e74SKuba Mracek output_stream.EOL(); 113541ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 113641ae8e74SKuba Mracek return result.Succeeded(); 113741ae8e74SKuba Mracek } 113841ae8e74SKuba Mracek }; 113941ae8e74SKuba Mracek 114041ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword { 114141ae8e74SKuba Mracek public: 114241ae8e74SKuba Mracek CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 114341ae8e74SKuba Mracek : CommandObjectMultiword( 114441ae8e74SKuba Mracek interpreter, "frame recognizer", 114541ae8e74SKuba Mracek "Commands for editing and viewing frame recognizers.", 114641ae8e74SKuba Mracek "frame recognizer [<sub-command-options>] ") { 1147a925974bSAdrian Prantl LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd( 1148a925974bSAdrian Prantl interpreter))); 114941ae8e74SKuba Mracek LoadSubCommand( 115041ae8e74SKuba Mracek "clear", 115141ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 115241ae8e74SKuba Mracek LoadSubCommand( 115341ae8e74SKuba Mracek "delete", 115441ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 1155a925974bSAdrian Prantl LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList( 1156a925974bSAdrian Prantl interpreter))); 1157a925974bSAdrian Prantl LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo( 1158a925974bSAdrian Prantl interpreter))); 115941ae8e74SKuba Mracek } 116041ae8e74SKuba Mracek 116141ae8e74SKuba Mracek ~CommandObjectFrameRecognizer() override = default; 116241ae8e74SKuba Mracek }; 116341ae8e74SKuba Mracek 116430fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame 116530fdc8d8SChris Lattner 116630fdc8d8SChris Lattner // CommandObjectMultiwordFrame 116730fdc8d8SChris Lattner 1168b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1169b9c1b51eSKate Stone CommandInterpreter &interpreter) 1170a925974bSAdrian Prantl : CommandObjectMultiword(interpreter, "frame", 1171a925974bSAdrian Prantl "Commands for selecting and " 1172b9c1b51eSKate Stone "examing the current " 1173b9c1b51eSKate Stone "thread's stack frames.", 1174b9c1b51eSKate Stone "frame <subcommand> [<subcommand-options>]") { 1175b9c1b51eSKate Stone LoadSubCommand("diagnose", 1176b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1177b9c1b51eSKate Stone LoadSubCommand("info", 1178b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1179b9c1b51eSKate Stone LoadSubCommand("select", 1180b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1181b9c1b51eSKate Stone LoadSubCommand("variable", 1182b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 11834e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON 1184a925974bSAdrian Prantl LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer( 1185a925974bSAdrian Prantl interpreter))); 118641ae8e74SKuba Mracek #endif 118730fdc8d8SChris Lattner } 118830fdc8d8SChris Lattner 1189c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1190