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" 1541ae8e74SKuba Mracek #include "lldb/Host/StringConvert.h" 1630fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h" 1730fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h" 181deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h" 192837b766SJim Ingham #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" 20715c2365SGreg Clayton #include "lldb/Interpreter/OptionGroupVariable.h" 21b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h" 226754e04fSEnrico Granata #include "lldb/Symbol/Function.h" 236d56d2ceSJim Ingham #include "lldb/Symbol/SymbolContext.h" 246d56d2ceSJim Ingham #include "lldb/Symbol/Variable.h" 256d56d2ceSJim Ingham #include "lldb/Symbol/VariableList.h" 26b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h" 2741ae8e74SKuba Mracek #include "lldb/Target/StackFrameRecognizer.h" 284740a734SSean Callanan #include "lldb/Target/StopInfo.h" 296d56d2ceSJim Ingham #include "lldb/Target/Target.h" 30b9c1b51eSKate Stone #include "lldb/Target/Thread.h" 31145d95c9SPavel Labath #include "lldb/Utility/Args.h" 3230fdc8d8SChris Lattner 33796ac80bSJonas Devlieghere #include <memory> 34796ac80bSJonas Devlieghere #include <string> 35796ac80bSJonas Devlieghere 3630fdc8d8SChris Lattner using namespace lldb; 3730fdc8d8SChris Lattner using namespace lldb_private; 3830fdc8d8SChris Lattner 394740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose 404740a734SSean Callanan 414740a734SSean Callanan // CommandObjectFrameInfo 424740a734SSean Callanan 434740a734SSean Callanan // CommandObjectFrameDiagnose 444740a734SSean Callanan 45ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_diag 46ec67e734SRaphael Isemann #include "CommandOptions.inc" 471f0f5b5bSZachary Turner 48b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed { 494740a734SSean Callanan public: 50b9c1b51eSKate Stone class CommandOptions : public Options { 514740a734SSean Callanan public: 52b9c1b51eSKate Stone CommandOptions() : Options() { OptionParsingStarting(nullptr); } 534740a734SSean Callanan 544740a734SSean Callanan ~CommandOptions() override = default; 554740a734SSean Callanan 5697206d57SZachary Turner Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 57b9c1b51eSKate Stone ExecutionContext *execution_context) override { 5897206d57SZachary Turner Status error; 594740a734SSean Callanan const int short_option = m_getopt_table[option_idx].val; 60b9c1b51eSKate Stone switch (short_option) { 614740a734SSean Callanan case 'r': 624740a734SSean Callanan reg = ConstString(option_arg); 634740a734SSean Callanan break; 644740a734SSean Callanan 65b9c1b51eSKate Stone case 'a': { 66fe11483bSZachary Turner address.emplace(); 67fe11483bSZachary Turner if (option_arg.getAsInteger(0, *address)) { 684740a734SSean Callanan address.reset(); 69b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid address argument '%s'", 70fe11483bSZachary Turner option_arg.str().c_str()); 714740a734SSean Callanan } 72b9c1b51eSKate Stone } break; 734740a734SSean Callanan 74b9c1b51eSKate Stone case 'o': { 75fe11483bSZachary Turner offset.emplace(); 76fe11483bSZachary Turner if (option_arg.getAsInteger(0, *offset)) { 774740a734SSean Callanan offset.reset(); 78b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid offset argument '%s'", 79fe11483bSZachary Turner option_arg.str().c_str()); 804740a734SSean Callanan } 81b9c1b51eSKate Stone } break; 824740a734SSean Callanan 834740a734SSean Callanan default: 8436162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 854740a734SSean Callanan } 864740a734SSean Callanan 874740a734SSean Callanan return error; 884740a734SSean Callanan } 894740a734SSean Callanan 90b9c1b51eSKate Stone void OptionParsingStarting(ExecutionContext *execution_context) override { 914740a734SSean Callanan address.reset(); 924740a734SSean Callanan reg.reset(); 934740a734SSean Callanan offset.reset(); 944740a734SSean Callanan } 954740a734SSean Callanan 961f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 9770602439SZachary Turner return llvm::makeArrayRef(g_frame_diag_options); 981f0f5b5bSZachary Turner } 994740a734SSean Callanan 1004740a734SSean Callanan // Options. 1014740a734SSean Callanan llvm::Optional<lldb::addr_t> address; 1024740a734SSean Callanan llvm::Optional<ConstString> reg; 1034740a734SSean Callanan llvm::Optional<int64_t> offset; 1044740a734SSean Callanan }; 1054740a734SSean Callanan 1064740a734SSean Callanan CommandObjectFrameDiagnose(CommandInterpreter &interpreter) 1074740a734SSean Callanan : CommandObjectParsed(interpreter, "frame diagnose", 108b9c1b51eSKate Stone "Try to determine what path path the current stop " 109b9c1b51eSKate Stone "location used to get to a register or address", 110b9c1b51eSKate Stone nullptr, 111b9c1b51eSKate Stone eCommandRequiresThread | eCommandTryTargetAPILock | 112b9c1b51eSKate Stone eCommandProcessMustBeLaunched | 1134740a734SSean Callanan eCommandProcessMustBePaused), 114b9c1b51eSKate Stone m_options() { 1154740a734SSean Callanan CommandArgumentEntry arg; 1164740a734SSean Callanan CommandArgumentData index_arg; 1174740a734SSean Callanan 1184740a734SSean Callanan // Define the first (and only) variant of this arg. 1194740a734SSean Callanan index_arg.arg_type = eArgTypeFrameIndex; 1204740a734SSean Callanan index_arg.arg_repetition = eArgRepeatOptional; 1214740a734SSean Callanan 122b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 123b9c1b51eSKate Stone // argument entry. 1244740a734SSean Callanan arg.push_back(index_arg); 1254740a734SSean Callanan 1264740a734SSean Callanan // Push the data for the first argument into the m_arguments vector. 1274740a734SSean Callanan m_arguments.push_back(arg); 1284740a734SSean Callanan } 1294740a734SSean Callanan 1304740a734SSean Callanan ~CommandObjectFrameDiagnose() override = default; 1314740a734SSean Callanan 132b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 1334740a734SSean Callanan 1344740a734SSean Callanan protected: 135b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 1364740a734SSean Callanan Thread *thread = m_exe_ctx.GetThreadPtr(); 1374740a734SSean Callanan StackFrameSP frame_sp = thread->GetSelectedFrame(); 1384740a734SSean Callanan 1394740a734SSean Callanan ValueObjectSP valobj_sp; 1404740a734SSean Callanan 141b9c1b51eSKate Stone if (m_options.address.hasValue()) { 142b9c1b51eSKate Stone if (m_options.reg.hasValue() || m_options.offset.hasValue()) { 143b9c1b51eSKate Stone result.AppendError( 144b9c1b51eSKate Stone "`frame diagnose --address` is incompatible with other arguments."); 1454740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1464740a734SSean Callanan return false; 1474740a734SSean Callanan } 1484740a734SSean Callanan valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue()); 149b9c1b51eSKate Stone } else if (m_options.reg.hasValue()) { 150b9c1b51eSKate Stone valobj_sp = frame_sp->GuessValueForRegisterAndOffset( 151b9c1b51eSKate Stone m_options.reg.getValue(), m_options.offset.getValueOr(0)); 152b9c1b51eSKate Stone } else { 1534740a734SSean Callanan StopInfoSP stop_info_sp = thread->GetStopInfo(); 154b9c1b51eSKate Stone if (!stop_info_sp) { 1554740a734SSean Callanan result.AppendError("No arguments provided, and no stop info."); 1564740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1574740a734SSean Callanan return false; 1584740a734SSean Callanan } 1594740a734SSean Callanan 1604740a734SSean Callanan valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp); 1614740a734SSean Callanan } 1624740a734SSean Callanan 163b9c1b51eSKate Stone if (!valobj_sp) { 1644740a734SSean Callanan result.AppendError("No diagnosis available."); 1654740a734SSean Callanan result.SetStatus(eReturnStatusFailed); 1664740a734SSean Callanan return false; 1674740a734SSean Callanan } 1684740a734SSean Callanan 169a925974bSAdrian Prantl DumpValueObjectOptions::DeclPrintingHelper helper = 170a925974bSAdrian Prantl [&valobj_sp](ConstString type, ConstString var, 171a925974bSAdrian Prantl const DumpValueObjectOptions &opts, 1723bc714b2SZachary Turner Stream &stream) -> bool { 173b9c1b51eSKate Stone const ValueObject::GetExpressionPathFormat format = ValueObject:: 174b9c1b51eSKate Stone GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers; 175*3014efe0SAlex Langford valobj_sp->GetExpressionPath(stream, format); 1764740a734SSean Callanan stream.PutCString(" ="); 1774740a734SSean Callanan return true; 1784740a734SSean Callanan }; 1794740a734SSean Callanan 1804740a734SSean Callanan DumpValueObjectOptions options; 1814740a734SSean Callanan options.SetDeclPrintingHelper(helper); 182b9c1b51eSKate Stone ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), 183b9c1b51eSKate Stone options); 1844740a734SSean Callanan printer.PrintValueObject(); 1854740a734SSean Callanan 1864740a734SSean Callanan return true; 1874740a734SSean Callanan } 1884740a734SSean Callanan 1894740a734SSean Callanan protected: 1904740a734SSean Callanan CommandOptions m_options; 1914740a734SSean Callanan }; 1924740a734SSean Callanan 19330fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo 19430fdc8d8SChris Lattner 19530fdc8d8SChris Lattner // CommandObjectFrameInfo 19630fdc8d8SChris Lattner 197b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed { 19830fdc8d8SChris Lattner public: 1997428a18cSKate Stone CommandObjectFrameInfo(CommandInterpreter &interpreter) 200a925974bSAdrian Prantl : CommandObjectParsed(interpreter, "frame info", 201a925974bSAdrian Prantl "List information about the current " 202b9c1b51eSKate Stone "stack frame in the current thread.", 203b9c1b51eSKate Stone "frame info", 204b9c1b51eSKate Stone eCommandRequiresFrame | eCommandTryTargetAPILock | 205a925974bSAdrian Prantl eCommandProcessMustBeLaunched | 206a925974bSAdrian Prantl eCommandProcessMustBePaused) {} 20730fdc8d8SChris Lattner 208c8ecc2a9SEugene Zelenko ~CommandObjectFrameInfo() override = default; 20930fdc8d8SChris Lattner 2105a988416SJim Ingham protected: 211b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 212f9fc609fSGreg Clayton m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream()); 21330fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 21430fdc8d8SChris Lattner return result.Succeeded(); 21530fdc8d8SChris Lattner } 21630fdc8d8SChris Lattner }; 21730fdc8d8SChris Lattner 21830fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect 21930fdc8d8SChris Lattner 22030fdc8d8SChris Lattner // CommandObjectFrameSelect 22130fdc8d8SChris Lattner 222ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_select 223ec67e734SRaphael Isemann #include "CommandOptions.inc" 2241f0f5b5bSZachary Turner 225b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed { 22630fdc8d8SChris Lattner public: 227b9c1b51eSKate Stone class CommandOptions : public Options { 228864174e1SGreg Clayton public: 229b9c1b51eSKate Stone CommandOptions() : Options() { OptionParsingStarting(nullptr); } 230864174e1SGreg Clayton 231c8ecc2a9SEugene Zelenko ~CommandOptions() override = default; 232864174e1SGreg Clayton 23397206d57SZachary Turner Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 234b9c1b51eSKate Stone ExecutionContext *execution_context) override { 23597206d57SZachary Turner Status error; 2363bcdfc0eSGreg Clayton const int short_option = m_getopt_table[option_idx].val; 237b9c1b51eSKate Stone switch (short_option) { 238dab6f074SRaphael Isemann case 'r': { 239dab6f074SRaphael Isemann int32_t offset = 0; 240dab6f074SRaphael Isemann if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) { 241b9c1b51eSKate Stone error.SetErrorStringWithFormat("invalid frame offset argument '%s'", 242fe11483bSZachary Turner option_arg.str().c_str()); 243dab6f074SRaphael Isemann } else 244dab6f074SRaphael Isemann relative_frame_offset = offset; 2455a039d55SRaphael Isemann break; 246dab6f074SRaphael Isemann } 247864174e1SGreg Clayton 248864174e1SGreg Clayton default: 24936162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 250864174e1SGreg Clayton } 251864174e1SGreg Clayton 252864174e1SGreg Clayton return error; 253864174e1SGreg Clayton } 254864174e1SGreg Clayton 2555a039d55SRaphael Isemann void OptionParsingStarting(ExecutionContext *execution_context) override { 256dab6f074SRaphael Isemann relative_frame_offset.reset(); 2575a039d55SRaphael Isemann } 258864174e1SGreg Clayton 2591f0f5b5bSZachary Turner llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 26070602439SZachary Turner return llvm::makeArrayRef(g_frame_select_options); 2611f0f5b5bSZachary Turner } 262864174e1SGreg Clayton 263dab6f074SRaphael Isemann llvm::Optional<int32_t> relative_frame_offset; 264864174e1SGreg Clayton }; 265864174e1SGreg Clayton 2667428a18cSKate Stone CommandObjectFrameSelect(CommandInterpreter &interpreter) 267a925974bSAdrian Prantl : CommandObjectParsed(interpreter, "frame select", 268a925974bSAdrian Prantl "Select the current stack frame by " 269b9c1b51eSKate Stone "index from within the current thread " 270b9c1b51eSKate Stone "(see 'thread backtrace'.)", 271b9c1b51eSKate Stone nullptr, 272b9c1b51eSKate Stone eCommandRequiresThread | eCommandTryTargetAPILock | 273a925974bSAdrian Prantl eCommandProcessMustBeLaunched | 274a925974bSAdrian Prantl eCommandProcessMustBePaused), 275b9c1b51eSKate Stone m_options() { 276405fe67fSCaroline Tice CommandArgumentEntry arg; 277405fe67fSCaroline Tice CommandArgumentData index_arg; 278405fe67fSCaroline Tice 279405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 280405fe67fSCaroline Tice index_arg.arg_type = eArgTypeFrameIndex; 281864174e1SGreg Clayton index_arg.arg_repetition = eArgRepeatOptional; 282405fe67fSCaroline Tice 283b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 284b9c1b51eSKate Stone // argument entry. 285405fe67fSCaroline Tice arg.push_back(index_arg); 286405fe67fSCaroline Tice 287405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 288405fe67fSCaroline Tice m_arguments.push_back(arg); 28930fdc8d8SChris Lattner } 29030fdc8d8SChris Lattner 291c8ecc2a9SEugene Zelenko ~CommandObjectFrameSelect() override = default; 29230fdc8d8SChris Lattner 293b9c1b51eSKate Stone Options *GetOptions() override { return &m_options; } 294864174e1SGreg Clayton 2955a988416SJim Ingham protected: 296b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 297b9c1b51eSKate Stone // No need to check "thread" for validity as eCommandRequiresThread ensures 298b9c1b51eSKate Stone // it is valid 299f9fc609fSGreg Clayton Thread *thread = m_exe_ctx.GetThreadPtr(); 300f9fc609fSGreg Clayton 301864174e1SGreg Clayton uint32_t frame_idx = UINT32_MAX; 302dab6f074SRaphael Isemann if (m_options.relative_frame_offset.hasValue()) { 303864174e1SGreg Clayton // The one and only argument is a signed relative frame index 304c14ee32dSGreg Clayton frame_idx = thread->GetSelectedFrameIndex(); 305864174e1SGreg Clayton if (frame_idx == UINT32_MAX) 306864174e1SGreg Clayton frame_idx = 0; 307864174e1SGreg Clayton 308dab6f074SRaphael Isemann if (*m_options.relative_frame_offset < 0) { 309dab6f074SRaphael Isemann if (static_cast<int32_t>(frame_idx) >= 310dab6f074SRaphael Isemann -*m_options.relative_frame_offset) 311dab6f074SRaphael Isemann frame_idx += *m_options.relative_frame_offset; 312b9c1b51eSKate Stone else { 313b9c1b51eSKate Stone if (frame_idx == 0) { 31405097246SAdrian Prantl // If you are already at the bottom of the stack, then just warn 31505097246SAdrian Prantl // and don't reset the frame. 3167428a18cSKate Stone result.AppendError("Already at the bottom of the stack."); 317213b4546SJim Ingham result.SetStatus(eReturnStatusFailed); 318213b4546SJim Ingham return false; 319b9c1b51eSKate Stone } else 320864174e1SGreg Clayton frame_idx = 0; 321864174e1SGreg Clayton } 322dab6f074SRaphael Isemann } else if (*m_options.relative_frame_offset > 0) { 323b9c1b51eSKate Stone // I don't want "up 20" where "20" takes you past the top of the stack 324b9c1b51eSKate Stone // to produce 325b9c1b51eSKate Stone // an error, but rather to just go to the top. So I have to count the 326b9c1b51eSKate Stone // stack here... 327b0c72a5fSJim Ingham const uint32_t num_frames = thread->GetStackFrameCount(); 328b9c1b51eSKate Stone if (static_cast<int32_t>(num_frames - frame_idx) > 329dab6f074SRaphael Isemann *m_options.relative_frame_offset) 330dab6f074SRaphael Isemann frame_idx += *m_options.relative_frame_offset; 331b9c1b51eSKate Stone else { 332b9c1b51eSKate Stone if (frame_idx == num_frames - 1) { 333b9c1b51eSKate Stone // If we are already at the top of the stack, just warn and don't 334b9c1b51eSKate Stone // reset the frame. 3357428a18cSKate Stone result.AppendError("Already at the top of the stack."); 336213b4546SJim Ingham result.SetStatus(eReturnStatusFailed); 337213b4546SJim Ingham return false; 338b9c1b51eSKate Stone } else 339864174e1SGreg Clayton frame_idx = num_frames - 1; 340864174e1SGreg Clayton } 341864174e1SGreg Clayton } 342b9c1b51eSKate Stone } else { 343f965cc86SZachary Turner if (command.GetArgumentCount() > 1) { 344f965cc86SZachary Turner result.AppendErrorWithFormat( 345f965cc86SZachary Turner "too many arguments; expected frame-index, saw '%s'.\n", 346867e7d17SZachary Turner command[0].c_str()); 347f965cc86SZachary Turner m_options.GenerateOptionUsage( 348f965cc86SZachary Turner result.GetErrorStream(), this, 349f965cc86SZachary Turner GetCommandInterpreter().GetDebugger().GetTerminalWidth()); 350f965cc86SZachary Turner return false; 351f965cc86SZachary Turner } 352f965cc86SZachary Turner 353b9c1b51eSKate Stone if (command.GetArgumentCount() == 1) { 3540d9a201eSRaphael Isemann if (command[0].ref().getAsInteger(0, frame_idx)) { 355b9c1b51eSKate Stone result.AppendErrorWithFormat("invalid frame index argument '%s'.", 356f965cc86SZachary Turner command[0].c_str()); 357afbb0af8SJim Ingham result.SetStatus(eReturnStatusFailed); 358afbb0af8SJim Ingham return false; 359afbb0af8SJim Ingham } 360b9c1b51eSKate Stone } else if (command.GetArgumentCount() == 0) { 36182d4a2b9SJason Molenda frame_idx = thread->GetSelectedFrameIndex(); 362b9c1b51eSKate Stone if (frame_idx == UINT32_MAX) { 36382d4a2b9SJason Molenda frame_idx = 0; 36482d4a2b9SJason Molenda } 365864174e1SGreg Clayton } 366864174e1SGreg Clayton } 36730fdc8d8SChris Lattner 368b9c1b51eSKate Stone bool success = thread->SetSelectedFrameByIndexNoisily( 369b9c1b51eSKate Stone frame_idx, result.GetOutputStream()); 370b9c1b51eSKate Stone if (success) { 371f9fc609fSGreg Clayton m_exe_ctx.SetFrameSP(thread->GetSelectedFrame()); 37230fdc8d8SChris Lattner result.SetStatus(eReturnStatusSuccessFinishResult); 373b9c1b51eSKate Stone } else { 374b9c1b51eSKate Stone result.AppendErrorWithFormat("Frame index (%u) out of range.\n", 375b9c1b51eSKate Stone frame_idx); 37630fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 37793208b86SJim Ingham } 37893208b86SJim Ingham 37993208b86SJim Ingham return result.Succeeded(); 38030fdc8d8SChris Lattner } 381864174e1SGreg Clayton 382c8ecc2a9SEugene Zelenko protected: 383864174e1SGreg Clayton CommandOptions m_options; 384864174e1SGreg Clayton }; 385864174e1SGreg Clayton 3866d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable 3876d56d2ceSJim Ingham // List images with associated information 388b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed { 3896d56d2ceSJim Ingham public: 3907428a18cSKate Stone CommandObjectFrameVariable(CommandInterpreter &interpreter) 3917428a18cSKate Stone : CommandObjectParsed( 392b9c1b51eSKate Stone interpreter, "frame variable", 393b9c1b51eSKate Stone "Show variables for the current stack frame. Defaults to all " 3947428a18cSKate Stone "arguments and local variables in scope. Names of argument, " 3957428a18cSKate Stone "local, file static and file global variables can be specified. " 396ed8a705cSGreg Clayton "Children of aggregate variables can be specified such as " 397285ae0c0SJim Ingham "'var->child.x'. The -> and [] operators in 'frame variable' do " 398285ae0c0SJim Ingham "not invoke operator overloads if they exist, but directly access " 399285ae0c0SJim Ingham "the specified element. If you want to trigger operator overloads " 400285ae0c0SJim Ingham "use the expression command to print the variable instead." 401285ae0c0SJim Ingham "\nIt is worth noting that except for overloaded " 402285ae0c0SJim Ingham "operators, when printing local variables 'expr local_var' and " 403285ae0c0SJim Ingham "'frame var local_var' produce the same " 404285ae0c0SJim Ingham "results. However, 'frame variable' is more efficient, since it " 405285ae0c0SJim Ingham "uses debug information and memory reads directly, rather than " 406285ae0c0SJim Ingham "parsing and evaluating an expression, which may even involve " 407285ae0c0SJim Ingham "JITing and running code in the target program.", 408a925974bSAdrian Prantl nullptr, 409a925974bSAdrian Prantl eCommandRequiresFrame | eCommandTryTargetAPILock | 410a925974bSAdrian Prantl eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | 411a925974bSAdrian Prantl eCommandRequiresProcess), 412e1cfbc79STodd Fiala m_option_group(), 413b9c1b51eSKate Stone m_option_variable( 414b9c1b51eSKate Stone true), // Include the frame specific options by passing "true" 415a925974bSAdrian Prantl m_option_format(eFormatDefault), m_varobj_options() { 416405fe67fSCaroline Tice CommandArgumentEntry arg; 417405fe67fSCaroline Tice CommandArgumentData var_name_arg; 418405fe67fSCaroline Tice 419405fe67fSCaroline Tice // Define the first (and only) variant of this arg. 420405fe67fSCaroline Tice var_name_arg.arg_type = eArgTypeVarName; 421405fe67fSCaroline Tice var_name_arg.arg_repetition = eArgRepeatStar; 422405fe67fSCaroline Tice 423b9c1b51eSKate Stone // There is only one variant this argument could be; put it into the 424b9c1b51eSKate Stone // argument entry. 425405fe67fSCaroline Tice arg.push_back(var_name_arg); 426405fe67fSCaroline Tice 427405fe67fSCaroline Tice // Push the data for the first argument into the m_arguments vector. 428405fe67fSCaroline Tice m_arguments.push_back(arg); 4292837b766SJim Ingham 430715c2365SGreg Clayton m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 431b9c1b51eSKate Stone m_option_group.Append(&m_option_format, 432b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_FORMAT | 433b9c1b51eSKate Stone OptionGroupFormat::OPTION_GROUP_GDB_FMT, 434b9c1b51eSKate Stone LLDB_OPT_SET_1); 4352837b766SJim Ingham m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); 4362837b766SJim Ingham m_option_group.Finalize(); 4376d56d2ceSJim Ingham } 4386d56d2ceSJim Ingham 439c8ecc2a9SEugene Zelenko ~CommandObjectFrameVariable() override = default; 4406d56d2ceSJim Ingham 441b9c1b51eSKate Stone Options *GetOptions() override { return &m_option_group; } 442f21feadcSGreg Clayton 443ae34ed2cSRaphael Isemann void 444ae34ed2cSRaphael Isemann HandleArgumentCompletion(CompletionRequest &request, 4452443bbd4SRaphael Isemann OptionElementVector &opt_element_vector) override { 446f21feadcSGreg Clayton // Arguments are the standard source file completer. 447b9c1b51eSKate Stone CommandCompletions::InvokeCommonCompletionCallbacks( 448b9c1b51eSKate Stone GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, 449a2e76c0bSRaphael Isemann request, nullptr); 450f21feadcSGreg Clayton } 4516d56d2ceSJim Ingham 4525a988416SJim Ingham protected: 45373418dfeSEnrico Granata llvm::StringRef GetScopeString(VariableSP var_sp) { 45473418dfeSEnrico Granata if (!var_sp) 45573418dfeSEnrico Granata return llvm::StringRef::withNullAsEmpty(nullptr); 45673418dfeSEnrico Granata 45773418dfeSEnrico Granata switch (var_sp->GetScope()) { 45873418dfeSEnrico Granata case eValueTypeVariableGlobal: 45973418dfeSEnrico Granata return "GLOBAL: "; 46073418dfeSEnrico Granata case eValueTypeVariableStatic: 46173418dfeSEnrico Granata return "STATIC: "; 46273418dfeSEnrico Granata case eValueTypeVariableArgument: 46373418dfeSEnrico Granata return "ARG: "; 46473418dfeSEnrico Granata case eValueTypeVariableLocal: 46573418dfeSEnrico Granata return "LOCAL: "; 46673418dfeSEnrico Granata case eValueTypeVariableThreadLocal: 46773418dfeSEnrico Granata return "THREAD: "; 46873418dfeSEnrico Granata default: 46973418dfeSEnrico Granata break; 47073418dfeSEnrico Granata } 47173418dfeSEnrico Granata 47273418dfeSEnrico Granata return llvm::StringRef::withNullAsEmpty(nullptr); 47373418dfeSEnrico Granata } 47473418dfeSEnrico Granata 475b9c1b51eSKate Stone bool DoExecute(Args &command, CommandReturnObject &result) override { 47605097246SAdrian Prantl // No need to check "frame" for validity as eCommandRequiresFrame ensures 47705097246SAdrian Prantl // it is valid 478b57e4a1bSJason Molenda StackFrame *frame = m_exe_ctx.GetFramePtr(); 4791e49e5e7SJohnny Chen 480a134cc1bSGreg Clayton Stream &s = result.GetOutputStream(); 4816d56d2ceSJim Ingham 482b9c1b51eSKate Stone // Be careful about the stack frame, if any summary formatter runs code, it 48305097246SAdrian Prantl // might clear the StackFrameList for the thread. So hold onto a shared 48405097246SAdrian Prantl // pointer to the frame so it stays alive. 485650543f9SJim Ingham 486b9c1b51eSKate Stone VariableList *variable_list = 487b9c1b51eSKate Stone frame->GetVariableList(m_option_variable.show_globals); 488a134cc1bSGreg Clayton 4896d56d2ceSJim Ingham VariableSP var_sp; 4906d56d2ceSJim Ingham ValueObjectSP valobj_sp; 49178a685aaSJim Ingham 492061858ceSEnrico Granata TypeSummaryImplSP summary_format_sp; 49317b11749SEnrico Granata if (!m_option_variable.summary.IsCurrentValueEmpty()) 494b9c1b51eSKate Stone DataVisualization::NamedSummaryFormats::GetSummaryFormat( 495b9c1b51eSKate Stone ConstString(m_option_variable.summary.GetCurrentValue()), 496b9c1b51eSKate Stone summary_format_sp); 49717b11749SEnrico Granata else if (!m_option_variable.summary_string.IsCurrentValueEmpty()) 498796ac80bSJonas Devlieghere summary_format_sp = std::make_shared<StringSummaryFormat>( 499b9c1b51eSKate Stone TypeSummaryImpl::Flags(), 500796ac80bSJonas Devlieghere m_option_variable.summary_string.GetCurrentValue()); 501f9fa6ee5SEnrico Granata 502b9c1b51eSKate Stone DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( 503b9c1b51eSKate Stone eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault, 504b9c1b51eSKate Stone summary_format_sp)); 505379447a7SEnrico Granata 506b9c1b51eSKate Stone const SymbolContext &sym_ctx = 507b9c1b51eSKate Stone frame->GetSymbolContext(eSymbolContextFunction); 5086754e04fSEnrico Granata if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction()) 5096754e04fSEnrico Granata m_option_variable.show_globals = true; 5106754e04fSEnrico Granata 511b9c1b51eSKate Stone if (variable_list) { 5121deb7962SGreg Clayton const Format format = m_option_format.GetFormat(); 5130c489f58SEnrico Granata options.SetFormat(format); 5141deb7962SGreg Clayton 51511eb9c64SZachary Turner if (!command.empty()) { 51646747022SGreg Clayton VariableList regex_var_list; 51746747022SGreg Clayton 51805097246SAdrian Prantl // If we have any args to the variable command, we will make variable 51905097246SAdrian Prantl // objects from them... 520f965cc86SZachary Turner for (auto &entry : command) { 521b9c1b51eSKate Stone if (m_option_variable.use_regex) { 522c7bece56SGreg Clayton const size_t regex_start_index = regex_var_list.GetSize(); 5230d9a201eSRaphael Isemann llvm::StringRef name_str = entry.ref(); 52495eae423SZachary Turner RegularExpression regex(name_str); 525f9d90bc5SJan Kratochvil if (regex.IsValid()) { 52646747022SGreg Clayton size_t num_matches = 0; 527b9c1b51eSKate Stone const size_t num_new_regex_vars = 528b9c1b51eSKate Stone variable_list->AppendVariablesIfUnique(regex, regex_var_list, 52978a685aaSJim Ingham num_matches); 530b9c1b51eSKate Stone if (num_new_regex_vars > 0) { 531b9c1b51eSKate Stone for (size_t regex_idx = regex_start_index, 532b9c1b51eSKate Stone end_index = regex_var_list.GetSize(); 533b9c1b51eSKate Stone regex_idx < end_index; ++regex_idx) { 53446747022SGreg Clayton var_sp = regex_var_list.GetVariableAtIndex(regex_idx); 535b9c1b51eSKate Stone if (var_sp) { 536b9c1b51eSKate Stone valobj_sp = frame->GetValueObjectForFrameVariable( 537b9c1b51eSKate Stone var_sp, m_varobj_options.use_dynamic); 538b9c1b51eSKate Stone if (valobj_sp) { 53973418dfeSEnrico Granata std::string scope_string; 54073418dfeSEnrico Granata if (m_option_variable.show_scope) 54173418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 54273418dfeSEnrico Granata 54373418dfeSEnrico Granata if (!scope_string.empty()) 544771ef6d4SMalcolm Parsons s.PutCString(scope_string); 54573418dfeSEnrico Granata 546b9c1b51eSKate Stone if (m_option_variable.show_decl && 547b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 54845ba8543SGreg Clayton bool show_fullpaths = false; 54945ba8543SGreg Clayton bool show_module = true; 550b9c1b51eSKate Stone if (var_sp->DumpDeclaration(&s, show_fullpaths, 551b9c1b51eSKate Stone show_module)) 55246747022SGreg Clayton s.PutCString(": "); 55346747022SGreg Clayton } 5544d93b8cdSEnrico Granata valobj_sp->Dump(result.GetOutputStream(), options); 55546747022SGreg Clayton } 55646747022SGreg Clayton } 55746747022SGreg Clayton } 558b9c1b51eSKate Stone } else if (num_matches == 0) { 559b9c1b51eSKate Stone result.GetErrorStream().Printf("error: no variables matched " 560b9c1b51eSKate Stone "the regular expression '%s'.\n", 561f965cc86SZachary Turner entry.c_str()); 56246747022SGreg Clayton } 563b9c1b51eSKate Stone } else { 5643af3f1e8SJonas Devlieghere if (llvm::Error err = regex.GetError()) 5653af3f1e8SJonas Devlieghere result.GetErrorStream().Printf( 5663af3f1e8SJonas Devlieghere "error: %s\n", llvm::toString(std::move(err)).c_str()); 56746747022SGreg Clayton else 568b9c1b51eSKate Stone result.GetErrorStream().Printf( 569b9c1b51eSKate Stone "error: unknown regex error when compiling '%s'\n", 570f965cc86SZachary Turner entry.c_str()); 57146747022SGreg Clayton } 572b9c1b51eSKate Stone } else // No regex, either exact variable names or variable 573b9c1b51eSKate Stone // expressions. 57446747022SGreg Clayton { 57597206d57SZachary Turner Status error; 576b9c1b51eSKate Stone uint32_t expr_path_options = 577b9c1b51eSKate Stone StackFrame::eExpressionPathOptionCheckPtrVsMember | 57846252398SEnrico Granata StackFrame::eExpressionPathOptionsAllowDirectIVarAccess | 57946252398SEnrico Granata StackFrame::eExpressionPathOptionsInspectAnonymousUnions; 5802837b766SJim Ingham lldb::VariableSP var_sp; 581b9c1b51eSKate Stone valobj_sp = frame->GetValueForVariableExpressionPath( 5820d9a201eSRaphael Isemann entry.ref(), m_varobj_options.use_dynamic, expr_path_options, 583b9c1b51eSKate Stone var_sp, error); 584b9c1b51eSKate Stone if (valobj_sp) { 58573418dfeSEnrico Granata std::string scope_string; 58673418dfeSEnrico Granata if (m_option_variable.show_scope) 58773418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 58873418dfeSEnrico Granata 58973418dfeSEnrico Granata if (!scope_string.empty()) 590771ef6d4SMalcolm Parsons s.PutCString(scope_string); 591b9c1b51eSKate Stone if (m_option_variable.show_decl && var_sp && 592b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 593a134cc1bSGreg Clayton var_sp->GetDeclaration().DumpStopContext(&s, false); 594a134cc1bSGreg Clayton s.PutCString(": "); 595a134cc1bSGreg Clayton } 5960c489f58SEnrico Granata 5970c489f58SEnrico Granata options.SetFormat(format); 598b9c1b51eSKate Stone options.SetVariableFormatDisplayLanguage( 599b9c1b51eSKate Stone valobj_sp->GetPreferredDisplayLanguage()); 600887062aeSJohnny Chen 601887062aeSJohnny Chen Stream &output_stream = result.GetOutputStream(); 602f965cc86SZachary Turner options.SetRootValueObjectName( 603f965cc86SZachary Turner valobj_sp->GetParent() ? entry.c_str() : nullptr); 6044d93b8cdSEnrico Granata valobj_sp->Dump(output_stream, options); 605b9c1b51eSKate Stone } else { 606c8ecc2a9SEugene Zelenko const char *error_cstr = error.AsCString(nullptr); 60754979cddSGreg Clayton if (error_cstr) 60854979cddSGreg Clayton result.GetErrorStream().Printf("error: %s\n", error_cstr); 60954979cddSGreg Clayton else 610b9c1b51eSKate Stone result.GetErrorStream().Printf("error: unable to find any " 611b9c1b51eSKate Stone "variable expression path that " 612b9c1b51eSKate Stone "matches '%s'.\n", 613f965cc86SZachary Turner entry.c_str()); 6146d56d2ceSJim Ingham } 6156d56d2ceSJim Ingham } 6166d56d2ceSJim Ingham } 617b9c1b51eSKate Stone } else // No command arg specified. Use variable_list, instead. 6186d56d2ceSJim Ingham { 619c7bece56SGreg Clayton const size_t num_variables = variable_list->GetSize(); 620b9c1b51eSKate Stone if (num_variables > 0) { 621b9c1b51eSKate Stone for (size_t i = 0; i < num_variables; i++) { 6221a65ae11SGreg Clayton var_sp = variable_list->GetVariableAtIndex(i); 623f955efc0SSylvestre Ledru switch (var_sp->GetScope()) { 624eb236735SJim Ingham case eValueTypeVariableGlobal: 625eb236735SJim Ingham if (!m_option_variable.show_globals) 626eb236735SJim Ingham continue; 627eb236735SJim Ingham break; 628eb236735SJim Ingham case eValueTypeVariableStatic: 629eb236735SJim Ingham if (!m_option_variable.show_globals) 630eb236735SJim Ingham continue; 631eb236735SJim Ingham break; 632eb236735SJim Ingham case eValueTypeVariableArgument: 633eb236735SJim Ingham if (!m_option_variable.show_args) 634eb236735SJim Ingham continue; 635eb236735SJim Ingham break; 636eb236735SJim Ingham case eValueTypeVariableLocal: 637eb236735SJim Ingham if (!m_option_variable.show_locals) 638eb236735SJim Ingham continue; 639eb236735SJim Ingham break; 640eb236735SJim Ingham default: 641eb236735SJim Ingham continue; 642eb236735SJim Ingham break; 643eb236735SJim Ingham } 644560558ebSEnrico Granata std::string scope_string; 645eb236735SJim Ingham if (m_option_variable.show_scope) 64673418dfeSEnrico Granata scope_string = GetScopeString(var_sp).str(); 6476d56d2ceSJim Ingham 64805097246SAdrian Prantl // Use the variable object code to make sure we are using the same 64905097246SAdrian Prantl // APIs as the public API will be using... 650b9c1b51eSKate Stone valobj_sp = frame->GetValueObjectForFrameVariable( 651b9c1b51eSKate Stone var_sp, m_varobj_options.use_dynamic); 652b9c1b51eSKate Stone if (valobj_sp) { 65305097246SAdrian Prantl // When dumping all variables, don't print any variables that are 65405097246SAdrian Prantl // not in scope to avoid extra unneeded output 655b9c1b51eSKate Stone if (valobj_sp->IsInScope()) { 656b9c1b51eSKate Stone if (!valobj_sp->GetTargetSP() 657b9c1b51eSKate Stone ->GetDisplayRuntimeSupportValues() && 658c8ecc2a9SEugene Zelenko valobj_sp->IsRuntimeSupportValue()) 659560558ebSEnrico Granata continue; 660560558ebSEnrico Granata 661560558ebSEnrico Granata if (!scope_string.empty()) 662771ef6d4SMalcolm Parsons s.PutCString(scope_string); 663560558ebSEnrico Granata 664b9c1b51eSKate Stone if (m_option_variable.show_decl && 665b9c1b51eSKate Stone var_sp->GetDeclaration().GetFile()) { 666a134cc1bSGreg Clayton var_sp->GetDeclaration().DumpStopContext(&s, false); 667a134cc1bSGreg Clayton s.PutCString(": "); 668a134cc1bSGreg Clayton } 6690c489f58SEnrico Granata 6700c489f58SEnrico Granata options.SetFormat(format); 671b9c1b51eSKate Stone options.SetVariableFormatDisplayLanguage( 672b9c1b51eSKate Stone valobj_sp->GetPreferredDisplayLanguage()); 673f965cc86SZachary Turner options.SetRootValueObjectName( 674f965cc86SZachary Turner var_sp ? var_sp->GetName().AsCString() : nullptr); 6754d93b8cdSEnrico Granata valobj_sp->Dump(result.GetOutputStream(), options); 676a134cc1bSGreg Clayton } 677a134cc1bSGreg Clayton } 6786d56d2ceSJim Ingham } 6796d56d2ceSJim Ingham } 6806d56d2ceSJim Ingham } 6816d56d2ceSJim Ingham result.SetStatus(eReturnStatusSuccessFinishResult); 6826d56d2ceSJim Ingham } 68361a80ba6SEnrico Granata 68441ae8e74SKuba Mracek if (m_option_variable.show_recognized_args) { 68541ae8e74SKuba Mracek auto recognized_frame = frame->GetRecognizedFrame(); 68641ae8e74SKuba Mracek if (recognized_frame) { 68741ae8e74SKuba Mracek ValueObjectListSP recognized_arg_list = 68841ae8e74SKuba Mracek recognized_frame->GetRecognizedArguments(); 68941ae8e74SKuba Mracek if (recognized_arg_list) { 69041ae8e74SKuba Mracek for (auto &rec_value_sp : recognized_arg_list->GetObjects()) { 69141ae8e74SKuba Mracek options.SetFormat(m_option_format.GetFormat()); 69241ae8e74SKuba Mracek options.SetVariableFormatDisplayLanguage( 69341ae8e74SKuba Mracek rec_value_sp->GetPreferredDisplayLanguage()); 69441ae8e74SKuba Mracek options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); 69541ae8e74SKuba Mracek rec_value_sp->Dump(result.GetOutputStream(), options); 69641ae8e74SKuba Mracek } 69741ae8e74SKuba Mracek } 69841ae8e74SKuba Mracek } 69941ae8e74SKuba Mracek } 70041ae8e74SKuba Mracek 701b9c1b51eSKate Stone if (m_interpreter.TruncationWarningNecessary()) { 70261a80ba6SEnrico Granata result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(), 70361a80ba6SEnrico Granata m_cmd_name.c_str()); 70461a80ba6SEnrico Granata m_interpreter.TruncationWarningGiven(); 70561a80ba6SEnrico Granata } 70661a80ba6SEnrico Granata 70724fff242SDavide Italiano // Increment statistics. 70824fff242SDavide Italiano bool res = result.Succeeded(); 709cb2380c9SRaphael Isemann Target &target = GetSelectedOrDummyTarget(); 71024fff242SDavide Italiano if (res) 711cb2380c9SRaphael Isemann target.IncrementStats(StatisticKind::FrameVarSuccess); 71224fff242SDavide Italiano else 713cb2380c9SRaphael Isemann target.IncrementStats(StatisticKind::FrameVarFailure); 71424fff242SDavide Italiano return res; 7156d56d2ceSJim Ingham } 7166d56d2ceSJim Ingham 717c8ecc2a9SEugene Zelenko protected: 7182837b766SJim Ingham OptionGroupOptions m_option_group; 719715c2365SGreg Clayton OptionGroupVariable m_option_variable; 7201deb7962SGreg Clayton OptionGroupFormat m_option_format; 7212837b766SJim Ingham OptionGroupValueObjectDisplay m_varobj_options; 7226d56d2ceSJim Ingham }; 7236d56d2ceSJim Ingham 72441ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer 72541ae8e74SKuba Mracek 726ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_recognizer_add 727ec67e734SRaphael Isemann #include "CommandOptions.inc" 72841ae8e74SKuba Mracek 72941ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { 73041ae8e74SKuba Mracek private: 73141ae8e74SKuba Mracek class CommandOptions : public Options { 73241ae8e74SKuba Mracek public: 73341ae8e74SKuba Mracek CommandOptions() : Options() {} 73441ae8e74SKuba Mracek ~CommandOptions() override = default; 73541ae8e74SKuba Mracek 73641ae8e74SKuba Mracek Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 73741ae8e74SKuba Mracek ExecutionContext *execution_context) override { 73841ae8e74SKuba Mracek Status error; 73941ae8e74SKuba Mracek const int short_option = m_getopt_table[option_idx].val; 74041ae8e74SKuba Mracek 74141ae8e74SKuba Mracek switch (short_option) { 74241ae8e74SKuba Mracek case 'l': 74341ae8e74SKuba Mracek m_class_name = std::string(option_arg); 74441ae8e74SKuba Mracek break; 74541ae8e74SKuba Mracek case 's': 74641ae8e74SKuba Mracek m_module = std::string(option_arg); 74741ae8e74SKuba Mracek break; 74841ae8e74SKuba Mracek case 'n': 74941ae8e74SKuba Mracek m_function = std::string(option_arg); 75041ae8e74SKuba Mracek break; 75141ae8e74SKuba Mracek case 'x': 75241ae8e74SKuba Mracek m_regex = true; 75341ae8e74SKuba Mracek break; 75441ae8e74SKuba Mracek default: 75536162014SRaphael Isemann llvm_unreachable("Unimplemented option"); 75641ae8e74SKuba Mracek } 75741ae8e74SKuba Mracek 75841ae8e74SKuba Mracek return error; 75941ae8e74SKuba Mracek } 76041ae8e74SKuba Mracek 76141ae8e74SKuba Mracek void OptionParsingStarting(ExecutionContext *execution_context) override { 76241ae8e74SKuba Mracek m_module = ""; 76341ae8e74SKuba Mracek m_function = ""; 76441ae8e74SKuba Mracek m_class_name = ""; 76541ae8e74SKuba Mracek m_regex = false; 76641ae8e74SKuba Mracek } 76741ae8e74SKuba Mracek 76841ae8e74SKuba Mracek llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 76941ae8e74SKuba Mracek return llvm::makeArrayRef(g_frame_recognizer_add_options); 77041ae8e74SKuba Mracek } 77141ae8e74SKuba Mracek 77241ae8e74SKuba Mracek // Instance variables to hold the values for command options. 77341ae8e74SKuba Mracek std::string m_class_name; 77441ae8e74SKuba Mracek std::string m_module; 77541ae8e74SKuba Mracek std::string m_function; 77641ae8e74SKuba Mracek bool m_regex; 77741ae8e74SKuba Mracek }; 77841ae8e74SKuba Mracek 77941ae8e74SKuba Mracek CommandOptions m_options; 78041ae8e74SKuba Mracek 78141ae8e74SKuba Mracek Options *GetOptions() override { return &m_options; } 78241ae8e74SKuba Mracek 78341ae8e74SKuba Mracek protected: 78441ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override; 78541ae8e74SKuba Mracek 78641ae8e74SKuba Mracek public: 78741ae8e74SKuba Mracek CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter) 78841ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer add", 78941ae8e74SKuba Mracek "Add a new frame recognizer.", nullptr), 79041ae8e74SKuba Mracek m_options() { 79141ae8e74SKuba Mracek SetHelpLong(R"( 79241ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on 79341ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source 79441ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments 79541ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments. 79641ae8e74SKuba Mracek 79741ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class 79841ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a 79941ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type 80041ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize. 80141ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that 80241ae8e74SKuba Mracek represent the recognized arguments. 80341ae8e74SKuba Mracek 80441ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc 80541ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows: 80641ae8e74SKuba Mracek 80741ae8e74SKuba Mracek class LibcFdRecognizer(object): 80841ae8e74SKuba Mracek def get_recognized_arguments(self, frame): 80941ae8e74SKuba Mracek if frame.name in ["read", "write", "close"]: 81041ae8e74SKuba Mracek fd = frame.EvaluateExpression("$arg1").unsigned 81141ae8e74SKuba Mracek value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd) 81241ae8e74SKuba Mracek return [value] 81341ae8e74SKuba Mracek return [] 81441ae8e74SKuba Mracek 81541ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script 81641ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'. 81741ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is 81841ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name 81941ae8e74SKuba Mracek in other modules: 82041ae8e74SKuba Mracek 82141ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py 82241ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib 82341ae8e74SKuba Mracek 82441ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we 82541ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable': 82641ae8e74SKuba Mracek 82741ae8e74SKuba Mracek (lldb) b read 82841ae8e74SKuba Mracek (lldb) r 82941ae8e74SKuba Mracek Process 1234 stopped 83041ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3 83141ae8e74SKuba Mracek frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read 83241ae8e74SKuba Mracek (lldb) frame variable 83341ae8e74SKuba Mracek (int) fd = 3 83441ae8e74SKuba Mracek 83541ae8e74SKuba Mracek )"); 83641ae8e74SKuba Mracek } 83741ae8e74SKuba Mracek ~CommandObjectFrameRecognizerAdd() override = default; 83841ae8e74SKuba Mracek }; 83941ae8e74SKuba Mracek 84041ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, 84141ae8e74SKuba Mracek CommandReturnObject &result) { 8424e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON 84341ae8e74SKuba Mracek if (m_options.m_class_name.empty()) { 84441ae8e74SKuba Mracek result.AppendErrorWithFormat( 84541ae8e74SKuba Mracek "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); 84641ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 84741ae8e74SKuba Mracek return false; 84841ae8e74SKuba Mracek } 84941ae8e74SKuba Mracek 85041ae8e74SKuba Mracek if (m_options.m_module.empty()) { 85141ae8e74SKuba Mracek result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", 85241ae8e74SKuba Mracek m_cmd_name.c_str()); 85341ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 85441ae8e74SKuba Mracek return false; 85541ae8e74SKuba Mracek } 85641ae8e74SKuba Mracek 85741ae8e74SKuba Mracek if (m_options.m_function.empty()) { 85841ae8e74SKuba Mracek result.AppendErrorWithFormat("%s needs a function name (-n argument).\n", 85941ae8e74SKuba Mracek m_cmd_name.c_str()); 86041ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 86141ae8e74SKuba Mracek return false; 86241ae8e74SKuba Mracek } 86341ae8e74SKuba Mracek 8642b29b432SJonas Devlieghere ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 86541ae8e74SKuba Mracek 86641ae8e74SKuba Mracek if (interpreter && 86741ae8e74SKuba Mracek !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) { 868a925974bSAdrian Prantl result.AppendWarning("The provided class does not exist - please define it " 86941ae8e74SKuba Mracek "before attempting to use this frame recognizer"); 87041ae8e74SKuba Mracek } 87141ae8e74SKuba Mracek 87241ae8e74SKuba Mracek StackFrameRecognizerSP recognizer_sp = 87341ae8e74SKuba Mracek StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( 87441ae8e74SKuba Mracek interpreter, m_options.m_class_name.c_str())); 87541ae8e74SKuba Mracek if (m_options.m_regex) { 87641ae8e74SKuba Mracek auto module = 87741ae8e74SKuba Mracek RegularExpressionSP(new RegularExpression(m_options.m_module)); 87841ae8e74SKuba Mracek auto func = 87941ae8e74SKuba Mracek RegularExpressionSP(new RegularExpression(m_options.m_function)); 88041ae8e74SKuba Mracek StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); 88141ae8e74SKuba Mracek } else { 88241ae8e74SKuba Mracek auto module = ConstString(m_options.m_module); 88341ae8e74SKuba Mracek auto func = ConstString(m_options.m_function); 88441ae8e74SKuba Mracek StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); 88541ae8e74SKuba Mracek } 886f80d2655SKuba Mracek #endif 88741ae8e74SKuba Mracek 88841ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishNoResult); 88941ae8e74SKuba Mracek return result.Succeeded(); 89041ae8e74SKuba Mracek } 89141ae8e74SKuba Mracek 89241ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed { 89341ae8e74SKuba Mracek public: 89441ae8e74SKuba Mracek CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter) 89541ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer clear", 89641ae8e74SKuba Mracek "Delete all frame recognizers.", nullptr) {} 89741ae8e74SKuba Mracek 89841ae8e74SKuba Mracek ~CommandObjectFrameRecognizerClear() override = default; 89941ae8e74SKuba Mracek 90041ae8e74SKuba Mracek protected: 90141ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 90241ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveAllRecognizers(); 90341ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 90441ae8e74SKuba Mracek return result.Succeeded(); 90541ae8e74SKuba Mracek } 90641ae8e74SKuba Mracek }; 90741ae8e74SKuba Mracek 90841ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed { 90941ae8e74SKuba Mracek public: 91041ae8e74SKuba Mracek CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter) 91141ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer delete", 91241ae8e74SKuba Mracek "Delete an existing frame recognizer.", nullptr) {} 91341ae8e74SKuba Mracek 91441ae8e74SKuba Mracek ~CommandObjectFrameRecognizerDelete() override = default; 91541ae8e74SKuba Mracek 91641ae8e74SKuba Mracek protected: 91741ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 91841ae8e74SKuba Mracek if (command.GetArgumentCount() == 0) { 91941ae8e74SKuba Mracek if (!m_interpreter.Confirm( 92041ae8e74SKuba Mracek "About to delete all frame recognizers, do you want to do that?", 92141ae8e74SKuba Mracek true)) { 92241ae8e74SKuba Mracek result.AppendMessage("Operation cancelled..."); 92341ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 92441ae8e74SKuba Mracek return false; 92541ae8e74SKuba Mracek } 92641ae8e74SKuba Mracek 92741ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveAllRecognizers(); 92841ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 92941ae8e74SKuba Mracek return result.Succeeded(); 93041ae8e74SKuba Mracek } 93141ae8e74SKuba Mracek 93241ae8e74SKuba Mracek if (command.GetArgumentCount() != 1) { 93341ae8e74SKuba Mracek result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", 93441ae8e74SKuba Mracek m_cmd_name.c_str()); 93541ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 93641ae8e74SKuba Mracek return false; 93741ae8e74SKuba Mracek } 93841ae8e74SKuba Mracek 93941ae8e74SKuba Mracek uint32_t recognizer_id = 94041ae8e74SKuba Mracek StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 94141ae8e74SKuba Mracek 94241ae8e74SKuba Mracek StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id); 94341ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 94441ae8e74SKuba Mracek return result.Succeeded(); 94541ae8e74SKuba Mracek } 94641ae8e74SKuba Mracek }; 94741ae8e74SKuba Mracek 94841ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed { 94941ae8e74SKuba Mracek public: 95041ae8e74SKuba Mracek CommandObjectFrameRecognizerList(CommandInterpreter &interpreter) 95141ae8e74SKuba Mracek : CommandObjectParsed(interpreter, "frame recognizer list", 95241ae8e74SKuba Mracek "Show a list of active frame recognizers.", 95341ae8e74SKuba Mracek nullptr) {} 95441ae8e74SKuba Mracek 95541ae8e74SKuba Mracek ~CommandObjectFrameRecognizerList() override = default; 95641ae8e74SKuba Mracek 95741ae8e74SKuba Mracek protected: 95841ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 95941ae8e74SKuba Mracek bool any_printed = false; 96041ae8e74SKuba Mracek StackFrameRecognizerManager::ForEach( 96141ae8e74SKuba Mracek [&result, &any_printed](uint32_t recognizer_id, std::string name, 96241ae8e74SKuba Mracek std::string function, std::string symbol, 96341ae8e74SKuba Mracek bool regexp) { 964a925974bSAdrian Prantl if (name == "") 965a925974bSAdrian Prantl name = "(internal)"; 96641ae8e74SKuba Mracek result.GetOutputStream().Printf( 96741ae8e74SKuba Mracek "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(), 96841ae8e74SKuba Mracek function.c_str(), symbol.c_str(), regexp ? " (regexp)" : ""); 96941ae8e74SKuba Mracek any_printed = true; 97041ae8e74SKuba Mracek }); 97141ae8e74SKuba Mracek 97241ae8e74SKuba Mracek if (any_printed) 97341ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 97441ae8e74SKuba Mracek else { 97541ae8e74SKuba Mracek result.GetOutputStream().PutCString("no matching results found.\n"); 97641ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishNoResult); 97741ae8e74SKuba Mracek } 97841ae8e74SKuba Mracek return result.Succeeded(); 97941ae8e74SKuba Mracek } 98041ae8e74SKuba Mracek }; 98141ae8e74SKuba Mracek 98241ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed { 98341ae8e74SKuba Mracek public: 98441ae8e74SKuba Mracek CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter) 98541ae8e74SKuba Mracek : CommandObjectParsed( 98641ae8e74SKuba Mracek interpreter, "frame recognizer info", 98741ae8e74SKuba Mracek "Show which frame recognizer is applied a stack frame (if any).", 98841ae8e74SKuba Mracek nullptr) { 98941ae8e74SKuba Mracek CommandArgumentEntry arg; 99041ae8e74SKuba Mracek CommandArgumentData index_arg; 99141ae8e74SKuba Mracek 99241ae8e74SKuba Mracek // Define the first (and only) variant of this arg. 99341ae8e74SKuba Mracek index_arg.arg_type = eArgTypeFrameIndex; 99441ae8e74SKuba Mracek index_arg.arg_repetition = eArgRepeatPlain; 99541ae8e74SKuba Mracek 99641ae8e74SKuba Mracek // There is only one variant this argument could be; put it into the 99741ae8e74SKuba Mracek // argument entry. 99841ae8e74SKuba Mracek arg.push_back(index_arg); 99941ae8e74SKuba Mracek 100041ae8e74SKuba Mracek // Push the data for the first argument into the m_arguments vector. 100141ae8e74SKuba Mracek m_arguments.push_back(arg); 100241ae8e74SKuba Mracek } 100341ae8e74SKuba Mracek 100441ae8e74SKuba Mracek ~CommandObjectFrameRecognizerInfo() override = default; 100541ae8e74SKuba Mracek 100641ae8e74SKuba Mracek protected: 100741ae8e74SKuba Mracek bool DoExecute(Args &command, CommandReturnObject &result) override { 100841ae8e74SKuba Mracek Process *process = m_exe_ctx.GetProcessPtr(); 100941ae8e74SKuba Mracek if (process == nullptr) { 101041ae8e74SKuba Mracek result.AppendError("no process"); 101141ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 101241ae8e74SKuba Mracek return false; 101341ae8e74SKuba Mracek } 101441ae8e74SKuba Mracek Thread *thread = m_exe_ctx.GetThreadPtr(); 101541ae8e74SKuba Mracek if (thread == nullptr) { 101641ae8e74SKuba Mracek result.AppendError("no thread"); 101741ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 101841ae8e74SKuba Mracek return false; 101941ae8e74SKuba Mracek } 102041ae8e74SKuba Mracek if (command.GetArgumentCount() != 1) { 102141ae8e74SKuba Mracek result.AppendErrorWithFormat( 102241ae8e74SKuba Mracek "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); 102341ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 102441ae8e74SKuba Mracek return false; 102541ae8e74SKuba Mracek } 102641ae8e74SKuba Mracek 102741ae8e74SKuba Mracek uint32_t frame_index = 102841ae8e74SKuba Mracek StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0); 102941ae8e74SKuba Mracek StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); 103041ae8e74SKuba Mracek if (!frame_sp) { 103141ae8e74SKuba Mracek result.AppendErrorWithFormat("no frame with index %u", frame_index); 103241ae8e74SKuba Mracek result.SetStatus(eReturnStatusFailed); 103341ae8e74SKuba Mracek return false; 103441ae8e74SKuba Mracek } 103541ae8e74SKuba Mracek 103641ae8e74SKuba Mracek auto recognizer = 103741ae8e74SKuba Mracek StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp); 103841ae8e74SKuba Mracek 103941ae8e74SKuba Mracek Stream &output_stream = result.GetOutputStream(); 104041ae8e74SKuba Mracek output_stream.Printf("frame %d ", frame_index); 104141ae8e74SKuba Mracek if (recognizer) { 104241ae8e74SKuba Mracek output_stream << "is recognized by "; 104341ae8e74SKuba Mracek output_stream << recognizer->GetName(); 104441ae8e74SKuba Mracek } else { 104541ae8e74SKuba Mracek output_stream << "not recognized by any recognizer"; 104641ae8e74SKuba Mracek } 104741ae8e74SKuba Mracek output_stream.EOL(); 104841ae8e74SKuba Mracek result.SetStatus(eReturnStatusSuccessFinishResult); 104941ae8e74SKuba Mracek return result.Succeeded(); 105041ae8e74SKuba Mracek } 105141ae8e74SKuba Mracek }; 105241ae8e74SKuba Mracek 105341ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword { 105441ae8e74SKuba Mracek public: 105541ae8e74SKuba Mracek CommandObjectFrameRecognizer(CommandInterpreter &interpreter) 105641ae8e74SKuba Mracek : CommandObjectMultiword( 105741ae8e74SKuba Mracek interpreter, "frame recognizer", 105841ae8e74SKuba Mracek "Commands for editing and viewing frame recognizers.", 105941ae8e74SKuba Mracek "frame recognizer [<sub-command-options>] ") { 1060a925974bSAdrian Prantl LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd( 1061a925974bSAdrian Prantl interpreter))); 106241ae8e74SKuba Mracek LoadSubCommand( 106341ae8e74SKuba Mracek "clear", 106441ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter))); 106541ae8e74SKuba Mracek LoadSubCommand( 106641ae8e74SKuba Mracek "delete", 106741ae8e74SKuba Mracek CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter))); 1068a925974bSAdrian Prantl LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList( 1069a925974bSAdrian Prantl interpreter))); 1070a925974bSAdrian Prantl LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo( 1071a925974bSAdrian Prantl interpreter))); 107241ae8e74SKuba Mracek } 107341ae8e74SKuba Mracek 107441ae8e74SKuba Mracek ~CommandObjectFrameRecognizer() override = default; 107541ae8e74SKuba Mracek }; 107641ae8e74SKuba Mracek 107730fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame 107830fdc8d8SChris Lattner 107930fdc8d8SChris Lattner // CommandObjectMultiwordFrame 108030fdc8d8SChris Lattner 1081b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame( 1082b9c1b51eSKate Stone CommandInterpreter &interpreter) 1083a925974bSAdrian Prantl : CommandObjectMultiword(interpreter, "frame", 1084a925974bSAdrian Prantl "Commands for selecting and " 1085b9c1b51eSKate Stone "examing the current " 1086b9c1b51eSKate Stone "thread's stack frames.", 1087b9c1b51eSKate Stone "frame <subcommand> [<subcommand-options>]") { 1088b9c1b51eSKate Stone LoadSubCommand("diagnose", 1089b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameDiagnose(interpreter))); 1090b9c1b51eSKate Stone LoadSubCommand("info", 1091b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameInfo(interpreter))); 1092b9c1b51eSKate Stone LoadSubCommand("select", 1093b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameSelect(interpreter))); 1094b9c1b51eSKate Stone LoadSubCommand("variable", 1095b9c1b51eSKate Stone CommandObjectSP(new CommandObjectFrameVariable(interpreter))); 10964e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON 1097a925974bSAdrian Prantl LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer( 1098a925974bSAdrian Prantl interpreter))); 109941ae8e74SKuba Mracek #endif 110030fdc8d8SChris Lattner } 110130fdc8d8SChris Lattner 1102c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default; 1103