130fdc8d8SChris Lattner //===-- CommandObjectFrame.cpp ----------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner // C Includes
1130fdc8d8SChris Lattner // C++ Includes
12de6bd243SJohnny Chen #include <string>
13c8ecc2a9SEugene Zelenko 
1430fdc8d8SChris Lattner // Other libraries and framework includes
1530fdc8d8SChris Lattner // Project includes
16c8ecc2a9SEugene Zelenko #include "CommandObjectFrame.h"
1730fdc8d8SChris Lattner #include "lldb/Core/Debugger.h"
186d56d2ceSJim Ingham #include "lldb/Core/Module.h"
196d56d2ceSJim Ingham #include "lldb/Core/StreamFile.h"
206d56d2ceSJim Ingham #include "lldb/Core/Value.h"
216d56d2ceSJim Ingham #include "lldb/Core/ValueObject.h"
226d56d2ceSJim Ingham #include "lldb/Core/ValueObjectVariable.h"
235548cb50SEnrico Granata #include "lldb/DataFormatters/DataVisualization.h"
244d93b8cdSEnrico Granata #include "lldb/DataFormatters/ValueObjectPrinter.h"
257fb56d0aSGreg Clayton #include "lldb/Host/Host.h"
263eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h"
2741ae8e74SKuba Mracek #include "lldb/Host/StringConvert.h"
2830fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h"
2930fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h"
301deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h"
312837b766SJim Ingham #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
32715c2365SGreg Clayton #include "lldb/Interpreter/OptionGroupVariable.h"
33b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h"
346d56d2ceSJim Ingham #include "lldb/Symbol/ClangASTContext.h"
35b9c1b51eSKate Stone #include "lldb/Symbol/CompilerType.h"
366754e04fSEnrico Granata #include "lldb/Symbol/Function.h"
376d56d2ceSJim Ingham #include "lldb/Symbol/ObjectFile.h"
386d56d2ceSJim Ingham #include "lldb/Symbol/SymbolContext.h"
396d56d2ceSJim Ingham #include "lldb/Symbol/Type.h"
406d56d2ceSJim Ingham #include "lldb/Symbol/Variable.h"
416d56d2ceSJim Ingham #include "lldb/Symbol/VariableList.h"
4230fdc8d8SChris Lattner #include "lldb/Target/Process.h"
43b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h"
4441ae8e74SKuba Mracek #include "lldb/Target/StackFrameRecognizer.h"
454740a734SSean Callanan #include "lldb/Target/StopInfo.h"
466d56d2ceSJim Ingham #include "lldb/Target/Target.h"
47b9c1b51eSKate Stone #include "lldb/Target/Thread.h"
48145d95c9SPavel Labath #include "lldb/Utility/Args.h"
494740a734SSean Callanan #include "lldb/Utility/LLDBAssert.h"
50bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
5138d0632eSPavel Labath #include "lldb/Utility/Timer.h"
5230fdc8d8SChris Lattner 
5330fdc8d8SChris Lattner using namespace lldb;
5430fdc8d8SChris Lattner using namespace lldb_private;
5530fdc8d8SChris Lattner 
564740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose
574740a734SSean Callanan 
584740a734SSean Callanan //-------------------------------------------------------------------------
594740a734SSean Callanan // CommandObjectFrameInfo
604740a734SSean Callanan //-------------------------------------------------------------------------
614740a734SSean Callanan 
624740a734SSean Callanan //-------------------------------------------------------------------------
634740a734SSean Callanan // CommandObjectFrameDiagnose
644740a734SSean Callanan //-------------------------------------------------------------------------
654740a734SSean Callanan 
668fe53c49STatyana Krasnukha static constexpr OptionDefinition g_frame_diag_options[] = {
671f0f5b5bSZachary Turner     // clang-format off
688fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "register", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeRegisterName,    "A register to diagnose." },
698fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "address",  'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddress,         "An address to diagnose." },
708fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "offset",   'o', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset,          "An optional offset.  Requires --register." }
711f0f5b5bSZachary Turner     // clang-format on
721f0f5b5bSZachary Turner };
731f0f5b5bSZachary Turner 
74b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed {
754740a734SSean Callanan public:
76b9c1b51eSKate Stone   class CommandOptions : public Options {
774740a734SSean Callanan   public:
78b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
794740a734SSean Callanan 
804740a734SSean Callanan     ~CommandOptions() override = default;
814740a734SSean Callanan 
8297206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
83b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
8497206d57SZachary Turner       Status error;
854740a734SSean Callanan       const int short_option = m_getopt_table[option_idx].val;
86b9c1b51eSKate Stone       switch (short_option) {
874740a734SSean Callanan       case 'r':
884740a734SSean Callanan         reg = ConstString(option_arg);
894740a734SSean Callanan         break;
904740a734SSean Callanan 
91b9c1b51eSKate Stone       case 'a': {
92fe11483bSZachary Turner         address.emplace();
93fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *address)) {
944740a734SSean Callanan           address.reset();
95b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid address argument '%s'",
96fe11483bSZachary Turner                                          option_arg.str().c_str());
974740a734SSean Callanan         }
98b9c1b51eSKate Stone       } break;
994740a734SSean Callanan 
100b9c1b51eSKate Stone       case 'o': {
101fe11483bSZachary Turner         offset.emplace();
102fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *offset)) {
1034740a734SSean Callanan           offset.reset();
104b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid offset argument '%s'",
105fe11483bSZachary Turner                                          option_arg.str().c_str());
1064740a734SSean Callanan         }
107b9c1b51eSKate Stone       } break;
1084740a734SSean Callanan 
1094740a734SSean Callanan       default:
110b9c1b51eSKate Stone         error.SetErrorStringWithFormat("invalid short option character '%c'",
111b9c1b51eSKate Stone                                        short_option);
1124740a734SSean Callanan         break;
1134740a734SSean Callanan       }
1144740a734SSean Callanan 
1154740a734SSean Callanan       return error;
1164740a734SSean Callanan     }
1174740a734SSean Callanan 
118b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
1194740a734SSean Callanan       address.reset();
1204740a734SSean Callanan       reg.reset();
1214740a734SSean Callanan       offset.reset();
1224740a734SSean Callanan     }
1234740a734SSean Callanan 
1241f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
12570602439SZachary Turner       return llvm::makeArrayRef(g_frame_diag_options);
1261f0f5b5bSZachary Turner     }
1274740a734SSean Callanan 
1284740a734SSean Callanan     // Options.
1294740a734SSean Callanan     llvm::Optional<lldb::addr_t> address;
1304740a734SSean Callanan     llvm::Optional<ConstString> reg;
1314740a734SSean Callanan     llvm::Optional<int64_t> offset;
1324740a734SSean Callanan   };
1334740a734SSean Callanan 
1344740a734SSean Callanan   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
1354740a734SSean Callanan       : CommandObjectParsed(interpreter, "frame diagnose",
136b9c1b51eSKate Stone                             "Try to determine what path path the current stop "
137b9c1b51eSKate Stone                             "location used to get to a register or address",
138b9c1b51eSKate Stone                             nullptr,
139b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
140b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched |
1414740a734SSean Callanan                                 eCommandProcessMustBePaused),
142b9c1b51eSKate Stone         m_options() {
1434740a734SSean Callanan     CommandArgumentEntry arg;
1444740a734SSean Callanan     CommandArgumentData index_arg;
1454740a734SSean Callanan 
1464740a734SSean Callanan     // Define the first (and only) variant of this arg.
1474740a734SSean Callanan     index_arg.arg_type = eArgTypeFrameIndex;
1484740a734SSean Callanan     index_arg.arg_repetition = eArgRepeatOptional;
1494740a734SSean Callanan 
150b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
151b9c1b51eSKate Stone     // argument entry.
1524740a734SSean Callanan     arg.push_back(index_arg);
1534740a734SSean Callanan 
1544740a734SSean Callanan     // Push the data for the first argument into the m_arguments vector.
1554740a734SSean Callanan     m_arguments.push_back(arg);
1564740a734SSean Callanan   }
1574740a734SSean Callanan 
1584740a734SSean Callanan   ~CommandObjectFrameDiagnose() override = default;
1594740a734SSean Callanan 
160b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
1614740a734SSean Callanan 
1624740a734SSean Callanan protected:
163b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1644740a734SSean Callanan     Thread *thread = m_exe_ctx.GetThreadPtr();
1654740a734SSean Callanan     StackFrameSP frame_sp = thread->GetSelectedFrame();
1664740a734SSean Callanan 
1674740a734SSean Callanan     ValueObjectSP valobj_sp;
1684740a734SSean Callanan 
169b9c1b51eSKate Stone     if (m_options.address.hasValue()) {
170b9c1b51eSKate Stone       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
171b9c1b51eSKate Stone         result.AppendError(
172b9c1b51eSKate Stone             "`frame diagnose --address` is incompatible with other arguments.");
1734740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1744740a734SSean Callanan         return false;
1754740a734SSean Callanan       }
1764740a734SSean Callanan       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
177b9c1b51eSKate Stone     } else if (m_options.reg.hasValue()) {
178b9c1b51eSKate Stone       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
179b9c1b51eSKate Stone           m_options.reg.getValue(), m_options.offset.getValueOr(0));
180b9c1b51eSKate Stone     } else {
1814740a734SSean Callanan       StopInfoSP stop_info_sp = thread->GetStopInfo();
182b9c1b51eSKate Stone       if (!stop_info_sp) {
1834740a734SSean Callanan         result.AppendError("No arguments provided, and no stop info.");
1844740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1854740a734SSean Callanan         return false;
1864740a734SSean Callanan       }
1874740a734SSean Callanan 
1884740a734SSean Callanan       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
1894740a734SSean Callanan     }
1904740a734SSean Callanan 
191b9c1b51eSKate Stone     if (!valobj_sp) {
1924740a734SSean Callanan       result.AppendError("No diagnosis available.");
1934740a734SSean Callanan       result.SetStatus(eReturnStatusFailed);
1944740a734SSean Callanan       return false;
1954740a734SSean Callanan     }
1964740a734SSean Callanan 
1974740a734SSean Callanan 
1983bc714b2SZachary Turner     DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp](
1993bc714b2SZachary Turner         ConstString type, ConstString var, const DumpValueObjectOptions &opts,
2003bc714b2SZachary Turner         Stream &stream) -> bool {
201b9c1b51eSKate Stone       const ValueObject::GetExpressionPathFormat format = ValueObject::
202b9c1b51eSKate Stone           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
2035d1f711aSPavel Labath       const bool qualify_cxx_base_classes = false;
2044740a734SSean Callanan       valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
2054740a734SSean Callanan       stream.PutCString(" =");
2064740a734SSean Callanan       return true;
2074740a734SSean Callanan     };
2084740a734SSean Callanan 
2094740a734SSean Callanan     DumpValueObjectOptions options;
2104740a734SSean Callanan     options.SetDeclPrintingHelper(helper);
211b9c1b51eSKate Stone     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
212b9c1b51eSKate Stone                                options);
2134740a734SSean Callanan     printer.PrintValueObject();
2144740a734SSean Callanan 
2154740a734SSean Callanan     return true;
2164740a734SSean Callanan   }
2174740a734SSean Callanan 
2184740a734SSean Callanan protected:
2194740a734SSean Callanan   CommandOptions m_options;
2204740a734SSean Callanan };
2214740a734SSean Callanan 
22230fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo
22330fdc8d8SChris Lattner 
22430fdc8d8SChris Lattner //-------------------------------------------------------------------------
22530fdc8d8SChris Lattner // CommandObjectFrameInfo
22630fdc8d8SChris Lattner //-------------------------------------------------------------------------
22730fdc8d8SChris Lattner 
228b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed {
22930fdc8d8SChris Lattner public:
2307428a18cSKate Stone   CommandObjectFrameInfo(CommandInterpreter &interpreter)
231b9c1b51eSKate Stone       : CommandObjectParsed(
232b9c1b51eSKate Stone             interpreter, "frame info", "List information about the current "
233b9c1b51eSKate Stone                                        "stack frame in the current thread.",
234b9c1b51eSKate Stone             "frame info",
235b9c1b51eSKate Stone             eCommandRequiresFrame | eCommandTryTargetAPILock |
236b9c1b51eSKate Stone                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
23730fdc8d8SChris Lattner 
238c8ecc2a9SEugene Zelenko   ~CommandObjectFrameInfo() override = default;
23930fdc8d8SChris Lattner 
2405a988416SJim Ingham protected:
241b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
242f9fc609fSGreg Clayton     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
24330fdc8d8SChris Lattner     result.SetStatus(eReturnStatusSuccessFinishResult);
24430fdc8d8SChris Lattner     return result.Succeeded();
24530fdc8d8SChris Lattner   }
24630fdc8d8SChris Lattner };
24730fdc8d8SChris Lattner 
24830fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect
24930fdc8d8SChris Lattner 
25030fdc8d8SChris Lattner //-------------------------------------------------------------------------
25130fdc8d8SChris Lattner // CommandObjectFrameSelect
25230fdc8d8SChris Lattner //-------------------------------------------------------------------------
25330fdc8d8SChris Lattner 
2541f0f5b5bSZachary Turner static OptionDefinition g_frame_select_options[] = {
2551f0f5b5bSZachary Turner     // clang-format off
2568fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset, "A relative frame index offset from the current frame index." },
2571f0f5b5bSZachary Turner     // clang-format on
2581f0f5b5bSZachary Turner };
2591f0f5b5bSZachary Turner 
260b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed {
26130fdc8d8SChris Lattner public:
262b9c1b51eSKate Stone   class CommandOptions : public Options {
263864174e1SGreg Clayton   public:
264b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
265864174e1SGreg Clayton 
266c8ecc2a9SEugene Zelenko     ~CommandOptions() override = default;
267864174e1SGreg Clayton 
26897206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
269b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
27097206d57SZachary Turner       Status error;
2713bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
272b9c1b51eSKate Stone       switch (short_option) {
273864174e1SGreg Clayton       case 'r':
274fe11483bSZachary Turner         if (option_arg.getAsInteger(0, relative_frame_offset)) {
275fe11483bSZachary Turner           relative_frame_offset = INT32_MIN;
276b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
277fe11483bSZachary Turner                                          option_arg.str().c_str());
278fe11483bSZachary Turner         }
279864174e1SGreg Clayton         break;
280864174e1SGreg Clayton 
281864174e1SGreg Clayton       default:
282b9c1b51eSKate Stone         error.SetErrorStringWithFormat("invalid short option character '%c'",
283b9c1b51eSKate Stone                                        short_option);
284864174e1SGreg Clayton         break;
285864174e1SGreg Clayton       }
286864174e1SGreg Clayton 
287864174e1SGreg Clayton       return error;
288864174e1SGreg Clayton     }
289864174e1SGreg Clayton 
290b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
291864174e1SGreg Clayton       relative_frame_offset = INT32_MIN;
292864174e1SGreg Clayton     }
293864174e1SGreg Clayton 
2941f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
29570602439SZachary Turner       return llvm::makeArrayRef(g_frame_select_options);
2961f0f5b5bSZachary Turner     }
297864174e1SGreg Clayton 
298864174e1SGreg Clayton     int32_t relative_frame_offset;
299864174e1SGreg Clayton   };
300864174e1SGreg Clayton 
3017428a18cSKate Stone   CommandObjectFrameSelect(CommandInterpreter &interpreter)
3027428a18cSKate Stone       : CommandObjectParsed(
303b9c1b51eSKate Stone             interpreter, "frame select", "Select the current stack frame by "
304b9c1b51eSKate Stone                                          "index from within the current thread "
305b9c1b51eSKate Stone                                          "(see 'thread backtrace'.)",
306b9c1b51eSKate Stone             nullptr,
307b9c1b51eSKate Stone             eCommandRequiresThread | eCommandTryTargetAPILock |
308b9c1b51eSKate Stone                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
309b9c1b51eSKate Stone         m_options() {
310405fe67fSCaroline Tice     CommandArgumentEntry arg;
311405fe67fSCaroline Tice     CommandArgumentData index_arg;
312405fe67fSCaroline Tice 
313405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
314405fe67fSCaroline Tice     index_arg.arg_type = eArgTypeFrameIndex;
315864174e1SGreg Clayton     index_arg.arg_repetition = eArgRepeatOptional;
316405fe67fSCaroline Tice 
317b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
318b9c1b51eSKate Stone     // argument entry.
319405fe67fSCaroline Tice     arg.push_back(index_arg);
320405fe67fSCaroline Tice 
321405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
322405fe67fSCaroline Tice     m_arguments.push_back(arg);
32330fdc8d8SChris Lattner   }
32430fdc8d8SChris Lattner 
325c8ecc2a9SEugene Zelenko   ~CommandObjectFrameSelect() override = default;
32630fdc8d8SChris Lattner 
327b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
328864174e1SGreg Clayton 
3295a988416SJim Ingham protected:
330b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
331b9c1b51eSKate Stone     // No need to check "thread" for validity as eCommandRequiresThread ensures
332b9c1b51eSKate Stone     // it is valid
333f9fc609fSGreg Clayton     Thread *thread = m_exe_ctx.GetThreadPtr();
334f9fc609fSGreg Clayton 
335864174e1SGreg Clayton     uint32_t frame_idx = UINT32_MAX;
336b9c1b51eSKate Stone     if (m_options.relative_frame_offset != INT32_MIN) {
337864174e1SGreg Clayton       // The one and only argument is a signed relative frame index
338c14ee32dSGreg Clayton       frame_idx = thread->GetSelectedFrameIndex();
339864174e1SGreg Clayton       if (frame_idx == UINT32_MAX)
340864174e1SGreg Clayton         frame_idx = 0;
341864174e1SGreg Clayton 
342b9c1b51eSKate Stone       if (m_options.relative_frame_offset < 0) {
3433985c8c6SSaleem Abdulrasool         if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset)
344864174e1SGreg Clayton           frame_idx += m_options.relative_frame_offset;
345b9c1b51eSKate Stone         else {
346b9c1b51eSKate Stone           if (frame_idx == 0) {
34705097246SAdrian Prantl             // If you are already at the bottom of the stack, then just warn
34805097246SAdrian Prantl             // and don't reset the frame.
3497428a18cSKate Stone             result.AppendError("Already at the bottom of the stack.");
350213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
351213b4546SJim Ingham             return false;
352b9c1b51eSKate Stone           } else
353864174e1SGreg Clayton             frame_idx = 0;
354864174e1SGreg Clayton         }
355b9c1b51eSKate Stone       } else if (m_options.relative_frame_offset > 0) {
356b9c1b51eSKate Stone         // I don't want "up 20" where "20" takes you past the top of the stack
357b9c1b51eSKate Stone         // to produce
358b9c1b51eSKate Stone         // an error, but rather to just go to the top.  So I have to count the
359b9c1b51eSKate Stone         // stack here...
360b0c72a5fSJim Ingham         const uint32_t num_frames = thread->GetStackFrameCount();
361b9c1b51eSKate Stone         if (static_cast<int32_t>(num_frames - frame_idx) >
362b9c1b51eSKate Stone             m_options.relative_frame_offset)
363864174e1SGreg Clayton           frame_idx += m_options.relative_frame_offset;
364b9c1b51eSKate Stone         else {
365b9c1b51eSKate Stone           if (frame_idx == num_frames - 1) {
366b9c1b51eSKate Stone             // If we are already at the top of the stack, just warn and don't
367b9c1b51eSKate Stone             // reset the frame.
3687428a18cSKate Stone             result.AppendError("Already at the top of the stack.");
369213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
370213b4546SJim Ingham             return false;
371b9c1b51eSKate Stone           } else
372864174e1SGreg Clayton             frame_idx = num_frames - 1;
373864174e1SGreg Clayton         }
374864174e1SGreg Clayton       }
375b9c1b51eSKate Stone     } else {
376f965cc86SZachary Turner       if (command.GetArgumentCount() > 1) {
377f965cc86SZachary Turner         result.AppendErrorWithFormat(
378f965cc86SZachary Turner             "too many arguments; expected frame-index, saw '%s'.\n",
379867e7d17SZachary Turner             command[0].c_str());
380f965cc86SZachary Turner         m_options.GenerateOptionUsage(
381f965cc86SZachary Turner             result.GetErrorStream(), this,
382f965cc86SZachary Turner             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
383f965cc86SZachary Turner         return false;
384f965cc86SZachary Turner       }
385f965cc86SZachary Turner 
386b9c1b51eSKate Stone       if (command.GetArgumentCount() == 1) {
387f965cc86SZachary Turner         if (command[0].ref.getAsInteger(0, frame_idx)) {
388b9c1b51eSKate Stone           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
389f965cc86SZachary Turner                                        command[0].c_str());
390afbb0af8SJim Ingham           result.SetStatus(eReturnStatusFailed);
391afbb0af8SJim Ingham           return false;
392afbb0af8SJim Ingham         }
393b9c1b51eSKate Stone       } else if (command.GetArgumentCount() == 0) {
39482d4a2b9SJason Molenda         frame_idx = thread->GetSelectedFrameIndex();
395b9c1b51eSKate Stone         if (frame_idx == UINT32_MAX) {
39682d4a2b9SJason Molenda           frame_idx = 0;
39782d4a2b9SJason Molenda         }
398864174e1SGreg Clayton       }
399864174e1SGreg Clayton     }
40030fdc8d8SChris Lattner 
401b9c1b51eSKate Stone     bool success = thread->SetSelectedFrameByIndexNoisily(
402b9c1b51eSKate Stone         frame_idx, result.GetOutputStream());
403b9c1b51eSKate Stone     if (success) {
404f9fc609fSGreg Clayton       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
40530fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
406b9c1b51eSKate Stone     } else {
407b9c1b51eSKate Stone       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
408b9c1b51eSKate Stone                                    frame_idx);
40930fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
41093208b86SJim Ingham     }
41193208b86SJim Ingham 
41293208b86SJim Ingham     return result.Succeeded();
41330fdc8d8SChris Lattner   }
414864174e1SGreg Clayton 
415c8ecc2a9SEugene Zelenko protected:
416864174e1SGreg Clayton   CommandOptions m_options;
417864174e1SGreg Clayton };
418864174e1SGreg Clayton 
4196d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable
4206d56d2ceSJim Ingham //----------------------------------------------------------------------
4216d56d2ceSJim Ingham // List images with associated information
4226d56d2ceSJim Ingham //----------------------------------------------------------------------
423b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed {
4246d56d2ceSJim Ingham public:
4257428a18cSKate Stone   CommandObjectFrameVariable(CommandInterpreter &interpreter)
4267428a18cSKate Stone       : CommandObjectParsed(
427b9c1b51eSKate Stone             interpreter, "frame variable",
428b9c1b51eSKate Stone             "Show variables for the current stack frame. Defaults to all "
4297428a18cSKate Stone             "arguments and local variables in scope. Names of argument, "
4307428a18cSKate Stone             "local, file static and file global variables can be specified. "
431ed8a705cSGreg Clayton             "Children of aggregate variables can be specified such as "
432285ae0c0SJim Ingham             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
433285ae0c0SJim Ingham             "not invoke operator overloads if they exist, but directly access "
434285ae0c0SJim Ingham             "the specified element.  If you want to trigger operator overloads "
435285ae0c0SJim Ingham             "use the expression command to print the variable instead."
436285ae0c0SJim Ingham             "\nIt is worth noting that except for overloaded "
437285ae0c0SJim Ingham             "operators, when printing local variables 'expr local_var' and "
438285ae0c0SJim Ingham             "'frame var local_var' produce the same "
439285ae0c0SJim Ingham             "results.  However, 'frame variable' is more efficient, since it "
440285ae0c0SJim Ingham             "uses debug information and memory reads directly, rather than "
441285ae0c0SJim Ingham             "parsing and evaluating an expression, which may even involve "
442285ae0c0SJim Ingham             "JITing and running code in the target program.",
443b9c1b51eSKate Stone             nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock |
444b9c1b51eSKate Stone                          eCommandProcessMustBeLaunched |
4457428a18cSKate Stone                          eCommandProcessMustBePaused | eCommandRequiresProcess),
446e1cfbc79STodd Fiala         m_option_group(),
447b9c1b51eSKate Stone         m_option_variable(
448b9c1b51eSKate Stone             true), // Include the frame specific options by passing "true"
4491deb7962SGreg Clayton         m_option_format(eFormatDefault),
450b9c1b51eSKate Stone         m_varobj_options() {
451405fe67fSCaroline Tice     CommandArgumentEntry arg;
452405fe67fSCaroline Tice     CommandArgumentData var_name_arg;
453405fe67fSCaroline Tice 
454405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
455405fe67fSCaroline Tice     var_name_arg.arg_type = eArgTypeVarName;
456405fe67fSCaroline Tice     var_name_arg.arg_repetition = eArgRepeatStar;
457405fe67fSCaroline Tice 
458b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
459b9c1b51eSKate Stone     // argument entry.
460405fe67fSCaroline Tice     arg.push_back(var_name_arg);
461405fe67fSCaroline Tice 
462405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
463405fe67fSCaroline Tice     m_arguments.push_back(arg);
4642837b766SJim Ingham 
465715c2365SGreg Clayton     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
466b9c1b51eSKate Stone     m_option_group.Append(&m_option_format,
467b9c1b51eSKate Stone                           OptionGroupFormat::OPTION_GROUP_FORMAT |
468b9c1b51eSKate Stone                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
469b9c1b51eSKate Stone                           LLDB_OPT_SET_1);
4702837b766SJim Ingham     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
4712837b766SJim Ingham     m_option_group.Finalize();
4726d56d2ceSJim Ingham   }
4736d56d2ceSJim Ingham 
474c8ecc2a9SEugene Zelenko   ~CommandObjectFrameVariable() override = default;
4756d56d2ceSJim Ingham 
476b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
477f21feadcSGreg Clayton 
4782443bbd4SRaphael Isemann   int HandleArgumentCompletion(
4792443bbd4SRaphael Isemann       CompletionRequest &request,
4802443bbd4SRaphael Isemann       OptionElementVector &opt_element_vector) override {
481f21feadcSGreg Clayton     // Arguments are the standard source file completer.
482b9c1b51eSKate Stone     CommandCompletions::InvokeCommonCompletionCallbacks(
483b9c1b51eSKate Stone         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
484a2e76c0bSRaphael Isemann         request, nullptr);
4851a6d7ab5SRaphael Isemann     return request.GetNumberOfMatches();
486f21feadcSGreg Clayton   }
4876d56d2ceSJim Ingham 
4885a988416SJim Ingham protected:
48973418dfeSEnrico Granata   llvm::StringRef GetScopeString(VariableSP var_sp) {
49073418dfeSEnrico Granata     if (!var_sp)
49173418dfeSEnrico Granata       return llvm::StringRef::withNullAsEmpty(nullptr);
49273418dfeSEnrico Granata 
49373418dfeSEnrico Granata     switch (var_sp->GetScope()) {
49473418dfeSEnrico Granata     case eValueTypeVariableGlobal:
49573418dfeSEnrico Granata       return "GLOBAL: ";
49673418dfeSEnrico Granata     case eValueTypeVariableStatic:
49773418dfeSEnrico Granata       return "STATIC: ";
49873418dfeSEnrico Granata     case eValueTypeVariableArgument:
49973418dfeSEnrico Granata       return "ARG: ";
50073418dfeSEnrico Granata     case eValueTypeVariableLocal:
50173418dfeSEnrico Granata       return "LOCAL: ";
50273418dfeSEnrico Granata     case eValueTypeVariableThreadLocal:
50373418dfeSEnrico Granata       return "THREAD: ";
50473418dfeSEnrico Granata     default:
50573418dfeSEnrico Granata       break;
50673418dfeSEnrico Granata     }
50773418dfeSEnrico Granata 
50873418dfeSEnrico Granata     return llvm::StringRef::withNullAsEmpty(nullptr);
50973418dfeSEnrico Granata   }
51073418dfeSEnrico Granata 
511b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
51205097246SAdrian Prantl     // No need to check "frame" for validity as eCommandRequiresFrame ensures
51305097246SAdrian Prantl     // it is valid
514b57e4a1bSJason Molenda     StackFrame *frame = m_exe_ctx.GetFramePtr();
5151e49e5e7SJohnny Chen 
516a134cc1bSGreg Clayton     Stream &s = result.GetOutputStream();
5176d56d2ceSJim Ingham 
518b9c1b51eSKate Stone     // Be careful about the stack frame, if any summary formatter runs code, it
51905097246SAdrian Prantl     // might clear the StackFrameList for the thread.  So hold onto a shared
52005097246SAdrian Prantl     // pointer to the frame so it stays alive.
521650543f9SJim Ingham 
522b9c1b51eSKate Stone     VariableList *variable_list =
523b9c1b51eSKate Stone         frame->GetVariableList(m_option_variable.show_globals);
524a134cc1bSGreg Clayton 
5256d56d2ceSJim Ingham     VariableSP var_sp;
5266d56d2ceSJim Ingham     ValueObjectSP valobj_sp;
52778a685aaSJim Ingham 
528061858ceSEnrico Granata     TypeSummaryImplSP summary_format_sp;
52917b11749SEnrico Granata     if (!m_option_variable.summary.IsCurrentValueEmpty())
530b9c1b51eSKate Stone       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
531b9c1b51eSKate Stone           ConstString(m_option_variable.summary.GetCurrentValue()),
532b9c1b51eSKate Stone           summary_format_sp);
53317b11749SEnrico Granata     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
534b9c1b51eSKate Stone       summary_format_sp.reset(new StringSummaryFormat(
535b9c1b51eSKate Stone           TypeSummaryImpl::Flags(),
536b9c1b51eSKate Stone           m_option_variable.summary_string.GetCurrentValue()));
537f9fa6ee5SEnrico Granata 
538b9c1b51eSKate Stone     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
539b9c1b51eSKate Stone         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
540b9c1b51eSKate Stone         summary_format_sp));
541379447a7SEnrico Granata 
542b9c1b51eSKate Stone     const SymbolContext &sym_ctx =
543b9c1b51eSKate Stone         frame->GetSymbolContext(eSymbolContextFunction);
5446754e04fSEnrico Granata     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
5456754e04fSEnrico Granata       m_option_variable.show_globals = true;
5466754e04fSEnrico Granata 
547b9c1b51eSKate Stone     if (variable_list) {
5481deb7962SGreg Clayton       const Format format = m_option_format.GetFormat();
5490c489f58SEnrico Granata       options.SetFormat(format);
5501deb7962SGreg Clayton 
55111eb9c64SZachary Turner       if (!command.empty()) {
55246747022SGreg Clayton         VariableList regex_var_list;
55346747022SGreg Clayton 
55405097246SAdrian Prantl         // If we have any args to the variable command, we will make variable
55505097246SAdrian Prantl         // objects from them...
556f965cc86SZachary Turner         for (auto &entry : command) {
557b9c1b51eSKate Stone           if (m_option_variable.use_regex) {
558c7bece56SGreg Clayton             const size_t regex_start_index = regex_var_list.GetSize();
559f965cc86SZachary Turner             llvm::StringRef name_str = entry.ref;
56095eae423SZachary Turner             RegularExpression regex(name_str);
56195eae423SZachary Turner             if (regex.Compile(name_str)) {
56246747022SGreg Clayton               size_t num_matches = 0;
563b9c1b51eSKate Stone               const size_t num_new_regex_vars =
564b9c1b51eSKate Stone                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
56578a685aaSJim Ingham                                                          num_matches);
566b9c1b51eSKate Stone               if (num_new_regex_vars > 0) {
567b9c1b51eSKate Stone                 for (size_t regex_idx = regex_start_index,
568b9c1b51eSKate Stone                             end_index = regex_var_list.GetSize();
569b9c1b51eSKate Stone                      regex_idx < end_index; ++regex_idx) {
57046747022SGreg Clayton                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
571b9c1b51eSKate Stone                   if (var_sp) {
572b9c1b51eSKate Stone                     valobj_sp = frame->GetValueObjectForFrameVariable(
573b9c1b51eSKate Stone                         var_sp, m_varobj_options.use_dynamic);
574b9c1b51eSKate Stone                     if (valobj_sp) {
57573418dfeSEnrico Granata                       std::string scope_string;
57673418dfeSEnrico Granata                       if (m_option_variable.show_scope)
57773418dfeSEnrico Granata                         scope_string = GetScopeString(var_sp).str();
57873418dfeSEnrico Granata 
57973418dfeSEnrico Granata                       if (!scope_string.empty())
580771ef6d4SMalcolm Parsons                         s.PutCString(scope_string);
58173418dfeSEnrico Granata 
582b9c1b51eSKate Stone                       if (m_option_variable.show_decl &&
583b9c1b51eSKate Stone                           var_sp->GetDeclaration().GetFile()) {
58445ba8543SGreg Clayton                         bool show_fullpaths = false;
58545ba8543SGreg Clayton                         bool show_module = true;
586b9c1b51eSKate Stone                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
587b9c1b51eSKate Stone                                                     show_module))
58846747022SGreg Clayton                           s.PutCString(": ");
58946747022SGreg Clayton                       }
5904d93b8cdSEnrico Granata                       valobj_sp->Dump(result.GetOutputStream(), options);
59146747022SGreg Clayton                     }
59246747022SGreg Clayton                   }
59346747022SGreg Clayton                 }
594b9c1b51eSKate Stone               } else if (num_matches == 0) {
595b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: no variables matched "
596b9c1b51eSKate Stone                                                "the regular expression '%s'.\n",
597f965cc86SZachary Turner                                                entry.c_str());
59846747022SGreg Clayton               }
599b9c1b51eSKate Stone             } else {
60046747022SGreg Clayton               char regex_error[1024];
60146747022SGreg Clayton               if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
60246747022SGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", regex_error);
60346747022SGreg Clayton               else
604b9c1b51eSKate Stone                 result.GetErrorStream().Printf(
605b9c1b51eSKate Stone                     "error: unknown regex error when compiling '%s'\n",
606f965cc86SZachary Turner                     entry.c_str());
60746747022SGreg Clayton             }
608b9c1b51eSKate Stone           } else // No regex, either exact variable names or variable
609b9c1b51eSKate Stone                  // expressions.
61046747022SGreg Clayton           {
61197206d57SZachary Turner             Status error;
612b9c1b51eSKate Stone             uint32_t expr_path_options =
613b9c1b51eSKate Stone                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
61446252398SEnrico Granata                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
61546252398SEnrico Granata                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
6162837b766SJim Ingham             lldb::VariableSP var_sp;
617b9c1b51eSKate Stone             valobj_sp = frame->GetValueForVariableExpressionPath(
618f965cc86SZachary Turner                 entry.ref, m_varobj_options.use_dynamic, expr_path_options,
619b9c1b51eSKate Stone                 var_sp, error);
620b9c1b51eSKate Stone             if (valobj_sp) {
62173418dfeSEnrico Granata               std::string scope_string;
62273418dfeSEnrico Granata               if (m_option_variable.show_scope)
62373418dfeSEnrico Granata                 scope_string = GetScopeString(var_sp).str();
62473418dfeSEnrico Granata 
62573418dfeSEnrico Granata               if (!scope_string.empty())
626771ef6d4SMalcolm Parsons                 s.PutCString(scope_string);
627b9c1b51eSKate Stone               if (m_option_variable.show_decl && var_sp &&
628b9c1b51eSKate Stone                   var_sp->GetDeclaration().GetFile()) {
629a134cc1bSGreg Clayton                 var_sp->GetDeclaration().DumpStopContext(&s, false);
630a134cc1bSGreg Clayton                 s.PutCString(": ");
631a134cc1bSGreg Clayton               }
6320c489f58SEnrico Granata 
6330c489f58SEnrico Granata               options.SetFormat(format);
634b9c1b51eSKate Stone               options.SetVariableFormatDisplayLanguage(
635b9c1b51eSKate Stone                   valobj_sp->GetPreferredDisplayLanguage());
636887062aeSJohnny Chen 
637887062aeSJohnny Chen               Stream &output_stream = result.GetOutputStream();
638f965cc86SZachary Turner               options.SetRootValueObjectName(
639f965cc86SZachary Turner                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
6404d93b8cdSEnrico Granata               valobj_sp->Dump(output_stream, options);
641b9c1b51eSKate Stone             } else {
642c8ecc2a9SEugene Zelenko               const char *error_cstr = error.AsCString(nullptr);
64354979cddSGreg Clayton               if (error_cstr)
64454979cddSGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
64554979cddSGreg Clayton               else
646b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: unable to find any "
647b9c1b51eSKate Stone                                                "variable expression path that "
648b9c1b51eSKate Stone                                                "matches '%s'.\n",
649f965cc86SZachary Turner                                                entry.c_str());
6506d56d2ceSJim Ingham             }
6516d56d2ceSJim Ingham           }
6526d56d2ceSJim Ingham         }
653b9c1b51eSKate Stone       } else // No command arg specified.  Use variable_list, instead.
6546d56d2ceSJim Ingham       {
655c7bece56SGreg Clayton         const size_t num_variables = variable_list->GetSize();
656b9c1b51eSKate Stone         if (num_variables > 0) {
657b9c1b51eSKate Stone           for (size_t i = 0; i < num_variables; i++) {
6581a65ae11SGreg Clayton             var_sp = variable_list->GetVariableAtIndex(i);
659f955efc0SSylvestre Ledru             switch (var_sp->GetScope()) {
660eb236735SJim Ingham             case eValueTypeVariableGlobal:
661eb236735SJim Ingham               if (!m_option_variable.show_globals)
662eb236735SJim Ingham                 continue;
663eb236735SJim Ingham               break;
664eb236735SJim Ingham             case eValueTypeVariableStatic:
665eb236735SJim Ingham               if (!m_option_variable.show_globals)
666eb236735SJim Ingham                 continue;
667eb236735SJim Ingham               break;
668eb236735SJim Ingham             case eValueTypeVariableArgument:
669eb236735SJim Ingham               if (!m_option_variable.show_args)
670eb236735SJim Ingham                 continue;
671eb236735SJim Ingham               break;
672eb236735SJim Ingham             case eValueTypeVariableLocal:
673eb236735SJim Ingham               if (!m_option_variable.show_locals)
674eb236735SJim Ingham                 continue;
675eb236735SJim Ingham               break;
676eb236735SJim Ingham             default:
677eb236735SJim Ingham               continue;
678eb236735SJim Ingham               break;
679eb236735SJim Ingham             }
680560558ebSEnrico Granata             std::string scope_string;
681eb236735SJim Ingham             if (m_option_variable.show_scope)
68273418dfeSEnrico Granata               scope_string = GetScopeString(var_sp).str();
6836d56d2ceSJim Ingham 
68405097246SAdrian Prantl             // Use the variable object code to make sure we are using the same
68505097246SAdrian Prantl             // APIs as the public API will be using...
686b9c1b51eSKate Stone             valobj_sp = frame->GetValueObjectForFrameVariable(
687b9c1b51eSKate Stone                 var_sp, m_varobj_options.use_dynamic);
688b9c1b51eSKate Stone             if (valobj_sp) {
68905097246SAdrian Prantl               // When dumping all variables, don't print any variables that are
69005097246SAdrian Prantl               // not in scope to avoid extra unneeded output
691b9c1b51eSKate Stone               if (valobj_sp->IsInScope()) {
692b9c1b51eSKate Stone                 if (!valobj_sp->GetTargetSP()
693b9c1b51eSKate Stone                          ->GetDisplayRuntimeSupportValues() &&
694c8ecc2a9SEugene Zelenko                     valobj_sp->IsRuntimeSupportValue())
695560558ebSEnrico Granata                   continue;
696560558ebSEnrico Granata 
697560558ebSEnrico Granata                 if (!scope_string.empty())
698771ef6d4SMalcolm Parsons                   s.PutCString(scope_string);
699560558ebSEnrico Granata 
700b9c1b51eSKate Stone                 if (m_option_variable.show_decl &&
701b9c1b51eSKate Stone                     var_sp->GetDeclaration().GetFile()) {
702a134cc1bSGreg Clayton                   var_sp->GetDeclaration().DumpStopContext(&s, false);
703a134cc1bSGreg Clayton                   s.PutCString(": ");
704a134cc1bSGreg Clayton                 }
7050c489f58SEnrico Granata 
7060c489f58SEnrico Granata                 options.SetFormat(format);
707b9c1b51eSKate Stone                 options.SetVariableFormatDisplayLanguage(
708b9c1b51eSKate Stone                     valobj_sp->GetPreferredDisplayLanguage());
709f965cc86SZachary Turner                 options.SetRootValueObjectName(
710f965cc86SZachary Turner                     var_sp ? var_sp->GetName().AsCString() : nullptr);
7114d93b8cdSEnrico Granata                 valobj_sp->Dump(result.GetOutputStream(), options);
712a134cc1bSGreg Clayton               }
713a134cc1bSGreg Clayton             }
7146d56d2ceSJim Ingham           }
7156d56d2ceSJim Ingham         }
7166d56d2ceSJim Ingham       }
7176d56d2ceSJim Ingham       result.SetStatus(eReturnStatusSuccessFinishResult);
7186d56d2ceSJim Ingham     }
71961a80ba6SEnrico Granata 
72041ae8e74SKuba Mracek     if (m_option_variable.show_recognized_args) {
72141ae8e74SKuba Mracek       auto recognized_frame = frame->GetRecognizedFrame();
72241ae8e74SKuba Mracek       if (recognized_frame) {
72341ae8e74SKuba Mracek         ValueObjectListSP recognized_arg_list =
72441ae8e74SKuba Mracek             recognized_frame->GetRecognizedArguments();
72541ae8e74SKuba Mracek         if (recognized_arg_list) {
72641ae8e74SKuba Mracek           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
72741ae8e74SKuba Mracek             options.SetFormat(m_option_format.GetFormat());
72841ae8e74SKuba Mracek             options.SetVariableFormatDisplayLanguage(
72941ae8e74SKuba Mracek                 rec_value_sp->GetPreferredDisplayLanguage());
73041ae8e74SKuba Mracek             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
73141ae8e74SKuba Mracek             rec_value_sp->Dump(result.GetOutputStream(), options);
73241ae8e74SKuba Mracek           }
73341ae8e74SKuba Mracek         }
73441ae8e74SKuba Mracek       }
73541ae8e74SKuba Mracek     }
73641ae8e74SKuba Mracek 
737b9c1b51eSKate Stone     if (m_interpreter.TruncationWarningNecessary()) {
73861a80ba6SEnrico Granata       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
73961a80ba6SEnrico Granata                                       m_cmd_name.c_str());
74061a80ba6SEnrico Granata       m_interpreter.TruncationWarningGiven();
74161a80ba6SEnrico Granata     }
74261a80ba6SEnrico Granata 
74324fff242SDavide Italiano     // Increment statistics.
74424fff242SDavide Italiano     bool res = result.Succeeded();
7450df817aaSDavide Italiano     Target *target = GetSelectedOrDummyTarget();
74624fff242SDavide Italiano     if (res)
74724fff242SDavide Italiano       target->IncrementStats(StatisticKind::FrameVarSuccess);
74824fff242SDavide Italiano     else
74924fff242SDavide Italiano       target->IncrementStats(StatisticKind::FrameVarFailure);
75024fff242SDavide Italiano     return res;
7516d56d2ceSJim Ingham   }
7526d56d2ceSJim Ingham 
753c8ecc2a9SEugene Zelenko protected:
7542837b766SJim Ingham   OptionGroupOptions m_option_group;
755715c2365SGreg Clayton   OptionGroupVariable m_option_variable;
7561deb7962SGreg Clayton   OptionGroupFormat m_option_format;
7572837b766SJim Ingham   OptionGroupValueObjectDisplay m_varobj_options;
7586d56d2ceSJim Ingham };
7596d56d2ceSJim Ingham 
76041ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer
76141ae8e74SKuba Mracek 
76241ae8e74SKuba Mracek static OptionDefinition g_frame_recognizer_add_options[] = {
76341ae8e74SKuba Mracek     // clang-format off
76441ae8e74SKuba Mracek   { LLDB_OPT_SET_ALL, false, "shlib",         's', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eModuleCompletion, eArgTypeShlibName,   "Name of the module or shared library that this recognizer applies to." },
76541ae8e74SKuba Mracek   { LLDB_OPT_SET_ALL, false, "function",      'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeName,        "Name of the function that this recognizer applies to." },
76641ae8e74SKuba Mracek   { LLDB_OPT_SET_2,   false, "python-class",  'l', OptionParser::eRequiredArgument, nullptr, {}, 0,                                     eArgTypePythonClass, "Give the name of a Python class to use for this frame recognizer." },
76741ae8e74SKuba Mracek   { LLDB_OPT_SET_ALL, false, "regex",         'x', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,        "Function name and module name are actually regular expressions." }
76841ae8e74SKuba Mracek     // clang-format on
76941ae8e74SKuba Mracek };
77041ae8e74SKuba Mracek 
77141ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
77241ae8e74SKuba Mracek private:
77341ae8e74SKuba Mracek   class CommandOptions : public Options {
77441ae8e74SKuba Mracek   public:
77541ae8e74SKuba Mracek     CommandOptions() : Options() {}
77641ae8e74SKuba Mracek     ~CommandOptions() override = default;
77741ae8e74SKuba Mracek 
77841ae8e74SKuba Mracek     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
77941ae8e74SKuba Mracek                           ExecutionContext *execution_context) override {
78041ae8e74SKuba Mracek       Status error;
78141ae8e74SKuba Mracek       const int short_option = m_getopt_table[option_idx].val;
78241ae8e74SKuba Mracek 
78341ae8e74SKuba Mracek       switch (short_option) {
78441ae8e74SKuba Mracek       case 'l':
78541ae8e74SKuba Mracek         m_class_name = std::string(option_arg);
78641ae8e74SKuba Mracek         break;
78741ae8e74SKuba Mracek       case 's':
78841ae8e74SKuba Mracek         m_module = std::string(option_arg);
78941ae8e74SKuba Mracek         break;
79041ae8e74SKuba Mracek       case 'n':
79141ae8e74SKuba Mracek         m_function = std::string(option_arg);
79241ae8e74SKuba Mracek         break;
79341ae8e74SKuba Mracek       case 'x':
79441ae8e74SKuba Mracek         m_regex = true;
79541ae8e74SKuba Mracek         break;
79641ae8e74SKuba Mracek       default:
79741ae8e74SKuba Mracek         error.SetErrorStringWithFormat("unrecognized option '%c'",
79841ae8e74SKuba Mracek                                        short_option);
79941ae8e74SKuba Mracek         break;
80041ae8e74SKuba Mracek       }
80141ae8e74SKuba Mracek 
80241ae8e74SKuba Mracek       return error;
80341ae8e74SKuba Mracek     }
80441ae8e74SKuba Mracek 
80541ae8e74SKuba Mracek     void OptionParsingStarting(ExecutionContext *execution_context) override {
80641ae8e74SKuba Mracek       m_module = "";
80741ae8e74SKuba Mracek       m_function = "";
80841ae8e74SKuba Mracek       m_class_name = "";
80941ae8e74SKuba Mracek       m_regex = false;
81041ae8e74SKuba Mracek     }
81141ae8e74SKuba Mracek 
81241ae8e74SKuba Mracek     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
81341ae8e74SKuba Mracek       return llvm::makeArrayRef(g_frame_recognizer_add_options);
81441ae8e74SKuba Mracek     }
81541ae8e74SKuba Mracek 
81641ae8e74SKuba Mracek     // Instance variables to hold the values for command options.
81741ae8e74SKuba Mracek     std::string m_class_name;
81841ae8e74SKuba Mracek     std::string m_module;
81941ae8e74SKuba Mracek     std::string m_function;
82041ae8e74SKuba Mracek     bool m_regex;
82141ae8e74SKuba Mracek   };
82241ae8e74SKuba Mracek 
82341ae8e74SKuba Mracek   CommandOptions m_options;
82441ae8e74SKuba Mracek 
82541ae8e74SKuba Mracek   Options *GetOptions() override { return &m_options; }
82641ae8e74SKuba Mracek 
82741ae8e74SKuba Mracek protected:
82841ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override;
82941ae8e74SKuba Mracek 
83041ae8e74SKuba Mracek public:
83141ae8e74SKuba Mracek   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
83241ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer add",
83341ae8e74SKuba Mracek                             "Add a new frame recognizer.", nullptr),
83441ae8e74SKuba Mracek         m_options() {
83541ae8e74SKuba Mracek     SetHelpLong(R"(
83641ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on
83741ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source
83841ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments
83941ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments.
84041ae8e74SKuba Mracek 
84141ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class
84241ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a
84341ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type
84441ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize.
84541ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that
84641ae8e74SKuba Mracek represent the recognized arguments.
84741ae8e74SKuba Mracek 
84841ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc
84941ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows:
85041ae8e74SKuba Mracek 
85141ae8e74SKuba Mracek   class LibcFdRecognizer(object):
85241ae8e74SKuba Mracek     def get_recognized_arguments(self, frame):
85341ae8e74SKuba Mracek       if frame.name in ["read", "write", "close"]:
85441ae8e74SKuba Mracek         fd = frame.EvaluateExpression("$arg1").unsigned
85541ae8e74SKuba Mracek         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
85641ae8e74SKuba Mracek         return [value]
85741ae8e74SKuba Mracek       return []
85841ae8e74SKuba Mracek 
85941ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script
86041ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'.
86141ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is
86241ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
86341ae8e74SKuba Mracek in other modules:
86441ae8e74SKuba Mracek 
86541ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py
86641ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
86741ae8e74SKuba Mracek 
86841ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we
86941ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable':
87041ae8e74SKuba Mracek 
87141ae8e74SKuba Mracek (lldb) b read
87241ae8e74SKuba Mracek (lldb) r
87341ae8e74SKuba Mracek Process 1234 stopped
87441ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
87541ae8e74SKuba Mracek     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
87641ae8e74SKuba Mracek (lldb) frame variable
87741ae8e74SKuba Mracek (int) fd = 3
87841ae8e74SKuba Mracek 
87941ae8e74SKuba Mracek     )");
88041ae8e74SKuba Mracek   }
88141ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerAdd() override = default;
88241ae8e74SKuba Mracek };
88341ae8e74SKuba Mracek 
88441ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
88541ae8e74SKuba Mracek                                                 CommandReturnObject &result) {
886*f80d2655SKuba Mracek #ifndef LLDB_DISABLE_PYTHON
88741ae8e74SKuba Mracek   if (m_options.m_class_name.empty()) {
88841ae8e74SKuba Mracek     result.AppendErrorWithFormat(
88941ae8e74SKuba Mracek         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
89041ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
89141ae8e74SKuba Mracek     return false;
89241ae8e74SKuba Mracek   }
89341ae8e74SKuba Mracek 
89441ae8e74SKuba Mracek   if (m_options.m_module.empty()) {
89541ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
89641ae8e74SKuba Mracek                                  m_cmd_name.c_str());
89741ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
89841ae8e74SKuba Mracek     return false;
89941ae8e74SKuba Mracek   }
90041ae8e74SKuba Mracek 
90141ae8e74SKuba Mracek   if (m_options.m_function.empty()) {
90241ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a function name (-n argument).\n",
90341ae8e74SKuba Mracek                                  m_cmd_name.c_str());
90441ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
90541ae8e74SKuba Mracek     return false;
90641ae8e74SKuba Mracek   }
90741ae8e74SKuba Mracek 
90841ae8e74SKuba Mracek   ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
90941ae8e74SKuba Mracek 
91041ae8e74SKuba Mracek   if (interpreter &&
91141ae8e74SKuba Mracek       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
91241ae8e74SKuba Mracek     result.AppendWarning(
91341ae8e74SKuba Mracek         "The provided class does not exist - please define it "
91441ae8e74SKuba Mracek         "before attempting to use this frame recognizer");
91541ae8e74SKuba Mracek   }
91641ae8e74SKuba Mracek 
91741ae8e74SKuba Mracek   StackFrameRecognizerSP recognizer_sp =
91841ae8e74SKuba Mracek       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
91941ae8e74SKuba Mracek           interpreter, m_options.m_class_name.c_str()));
92041ae8e74SKuba Mracek   if (m_options.m_regex) {
92141ae8e74SKuba Mracek     auto module =
92241ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_module));
92341ae8e74SKuba Mracek     auto func =
92441ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_function));
92541ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
92641ae8e74SKuba Mracek   } else {
92741ae8e74SKuba Mracek     auto module = ConstString(m_options.m_module);
92841ae8e74SKuba Mracek     auto func = ConstString(m_options.m_function);
92941ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
93041ae8e74SKuba Mracek   }
931*f80d2655SKuba Mracek #endif
93241ae8e74SKuba Mracek 
93341ae8e74SKuba Mracek   result.SetStatus(eReturnStatusSuccessFinishNoResult);
93441ae8e74SKuba Mracek   return result.Succeeded();
93541ae8e74SKuba Mracek }
93641ae8e74SKuba Mracek 
93741ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
93841ae8e74SKuba Mracek public:
93941ae8e74SKuba Mracek   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
94041ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer clear",
94141ae8e74SKuba Mracek                            "Delete all frame recognizers.", nullptr) {}
94241ae8e74SKuba Mracek 
94341ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerClear() override = default;
94441ae8e74SKuba Mracek 
94541ae8e74SKuba Mracek protected:
94641ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
94741ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveAllRecognizers();
94841ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
94941ae8e74SKuba Mracek     return result.Succeeded();
95041ae8e74SKuba Mracek   }
95141ae8e74SKuba Mracek };
95241ae8e74SKuba Mracek 
95341ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
95441ae8e74SKuba Mracek  public:
95541ae8e74SKuba Mracek   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
95641ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer delete",
95741ae8e74SKuba Mracek                             "Delete an existing frame recognizer.", nullptr) {}
95841ae8e74SKuba Mracek 
95941ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerDelete() override = default;
96041ae8e74SKuba Mracek 
96141ae8e74SKuba Mracek  protected:
96241ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
96341ae8e74SKuba Mracek     if (command.GetArgumentCount() == 0) {
96441ae8e74SKuba Mracek       if (!m_interpreter.Confirm(
96541ae8e74SKuba Mracek               "About to delete all frame recognizers, do you want to do that?",
96641ae8e74SKuba Mracek               true)) {
96741ae8e74SKuba Mracek         result.AppendMessage("Operation cancelled...");
96841ae8e74SKuba Mracek         result.SetStatus(eReturnStatusFailed);
96941ae8e74SKuba Mracek         return false;
97041ae8e74SKuba Mracek       }
97141ae8e74SKuba Mracek 
97241ae8e74SKuba Mracek       StackFrameRecognizerManager::RemoveAllRecognizers();
97341ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
97441ae8e74SKuba Mracek       return result.Succeeded();
97541ae8e74SKuba Mracek     }
97641ae8e74SKuba Mracek 
97741ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
97841ae8e74SKuba Mracek       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
97941ae8e74SKuba Mracek                                    m_cmd_name.c_str());
98041ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
98141ae8e74SKuba Mracek       return false;
98241ae8e74SKuba Mracek     }
98341ae8e74SKuba Mracek 
98441ae8e74SKuba Mracek     uint32_t recognizer_id =
98541ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
98641ae8e74SKuba Mracek 
98741ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
98841ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
98941ae8e74SKuba Mracek     return result.Succeeded();
99041ae8e74SKuba Mracek   }
99141ae8e74SKuba Mracek };
99241ae8e74SKuba Mracek 
99341ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed {
99441ae8e74SKuba Mracek  public:
99541ae8e74SKuba Mracek   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
99641ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer list",
99741ae8e74SKuba Mracek                             "Show a list of active frame recognizers.",
99841ae8e74SKuba Mracek                             nullptr) {}
99941ae8e74SKuba Mracek 
100041ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerList() override = default;
100141ae8e74SKuba Mracek 
100241ae8e74SKuba Mracek  protected:
100341ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
100441ae8e74SKuba Mracek     bool any_printed = false;
100541ae8e74SKuba Mracek     StackFrameRecognizerManager::ForEach(
100641ae8e74SKuba Mracek         [&result, &any_printed](uint32_t recognizer_id, std::string name,
100741ae8e74SKuba Mracek                                 std::string function, std::string symbol,
100841ae8e74SKuba Mracek                                 bool regexp) {
100941ae8e74SKuba Mracek           if (name == "") name = "(internal)";
101041ae8e74SKuba Mracek           result.GetOutputStream().Printf(
101141ae8e74SKuba Mracek               "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(),
101241ae8e74SKuba Mracek               function.c_str(), symbol.c_str(), regexp ? " (regexp)" : "");
101341ae8e74SKuba Mracek           any_printed = true;
101441ae8e74SKuba Mracek         });
101541ae8e74SKuba Mracek 
101641ae8e74SKuba Mracek     if (any_printed)
101741ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
101841ae8e74SKuba Mracek     else {
101941ae8e74SKuba Mracek       result.GetOutputStream().PutCString("no matching results found.\n");
102041ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishNoResult);
102141ae8e74SKuba Mracek     }
102241ae8e74SKuba Mracek     return result.Succeeded();
102341ae8e74SKuba Mracek   }
102441ae8e74SKuba Mracek };
102541ae8e74SKuba Mracek 
102641ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
102741ae8e74SKuba Mracek  public:
102841ae8e74SKuba Mracek   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
102941ae8e74SKuba Mracek       : CommandObjectParsed(
103041ae8e74SKuba Mracek             interpreter, "frame recognizer info",
103141ae8e74SKuba Mracek             "Show which frame recognizer is applied a stack frame (if any).",
103241ae8e74SKuba Mracek             nullptr) {
103341ae8e74SKuba Mracek     CommandArgumentEntry arg;
103441ae8e74SKuba Mracek     CommandArgumentData index_arg;
103541ae8e74SKuba Mracek 
103641ae8e74SKuba Mracek     // Define the first (and only) variant of this arg.
103741ae8e74SKuba Mracek     index_arg.arg_type = eArgTypeFrameIndex;
103841ae8e74SKuba Mracek     index_arg.arg_repetition = eArgRepeatPlain;
103941ae8e74SKuba Mracek 
104041ae8e74SKuba Mracek     // There is only one variant this argument could be; put it into the
104141ae8e74SKuba Mracek     // argument entry.
104241ae8e74SKuba Mracek     arg.push_back(index_arg);
104341ae8e74SKuba Mracek 
104441ae8e74SKuba Mracek     // Push the data for the first argument into the m_arguments vector.
104541ae8e74SKuba Mracek     m_arguments.push_back(arg);
104641ae8e74SKuba Mracek   }
104741ae8e74SKuba Mracek 
104841ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerInfo() override = default;
104941ae8e74SKuba Mracek 
105041ae8e74SKuba Mracek  protected:
105141ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
105241ae8e74SKuba Mracek     Process *process = m_exe_ctx.GetProcessPtr();
105341ae8e74SKuba Mracek     if (process == nullptr) {
105441ae8e74SKuba Mracek       result.AppendError("no process");
105541ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
105641ae8e74SKuba Mracek       return false;
105741ae8e74SKuba Mracek     }
105841ae8e74SKuba Mracek     Thread *thread = m_exe_ctx.GetThreadPtr();
105941ae8e74SKuba Mracek     if (thread == nullptr) {
106041ae8e74SKuba Mracek       result.AppendError("no thread");
106141ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
106241ae8e74SKuba Mracek       return false;
106341ae8e74SKuba Mracek     }
106441ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
106541ae8e74SKuba Mracek       result.AppendErrorWithFormat(
106641ae8e74SKuba Mracek           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
106741ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
106841ae8e74SKuba Mracek       return false;
106941ae8e74SKuba Mracek     }
107041ae8e74SKuba Mracek 
107141ae8e74SKuba Mracek     uint32_t frame_index =
107241ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
107341ae8e74SKuba Mracek     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
107441ae8e74SKuba Mracek     if (!frame_sp) {
107541ae8e74SKuba Mracek       result.AppendErrorWithFormat("no frame with index %u", frame_index);
107641ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
107741ae8e74SKuba Mracek       return false;
107841ae8e74SKuba Mracek     }
107941ae8e74SKuba Mracek 
108041ae8e74SKuba Mracek     auto recognizer =
108141ae8e74SKuba Mracek         StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
108241ae8e74SKuba Mracek 
108341ae8e74SKuba Mracek     Stream &output_stream = result.GetOutputStream();
108441ae8e74SKuba Mracek     output_stream.Printf("frame %d ", frame_index);
108541ae8e74SKuba Mracek     if (recognizer) {
108641ae8e74SKuba Mracek       output_stream << "is recognized by ";
108741ae8e74SKuba Mracek       output_stream << recognizer->GetName();
108841ae8e74SKuba Mracek     } else {
108941ae8e74SKuba Mracek       output_stream << "not recognized by any recognizer";
109041ae8e74SKuba Mracek     }
109141ae8e74SKuba Mracek     output_stream.EOL();
109241ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
109341ae8e74SKuba Mracek     return result.Succeeded();
109441ae8e74SKuba Mracek   }
109541ae8e74SKuba Mracek };
109641ae8e74SKuba Mracek 
109741ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword {
109841ae8e74SKuba Mracek  public:
109941ae8e74SKuba Mracek   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
110041ae8e74SKuba Mracek       : CommandObjectMultiword(
110141ae8e74SKuba Mracek             interpreter, "frame recognizer",
110241ae8e74SKuba Mracek             "Commands for editing and viewing frame recognizers.",
110341ae8e74SKuba Mracek             "frame recognizer [<sub-command-options>] ") {
110441ae8e74SKuba Mracek     LoadSubCommand(
110541ae8e74SKuba Mracek         "add",
110641ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter)));
110741ae8e74SKuba Mracek     LoadSubCommand(
110841ae8e74SKuba Mracek         "clear",
110941ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
111041ae8e74SKuba Mracek     LoadSubCommand(
111141ae8e74SKuba Mracek         "delete",
111241ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
111341ae8e74SKuba Mracek     LoadSubCommand(
111441ae8e74SKuba Mracek         "list",
111541ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter)));
111641ae8e74SKuba Mracek     LoadSubCommand(
111741ae8e74SKuba Mracek         "info",
111841ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerInfo(interpreter)));
111941ae8e74SKuba Mracek   }
112041ae8e74SKuba Mracek 
112141ae8e74SKuba Mracek   ~CommandObjectFrameRecognizer() override = default;
112241ae8e74SKuba Mracek };
112341ae8e74SKuba Mracek 
112430fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
112530fdc8d8SChris Lattner 
112630fdc8d8SChris Lattner //-------------------------------------------------------------------------
112730fdc8d8SChris Lattner // CommandObjectMultiwordFrame
112830fdc8d8SChris Lattner //-------------------------------------------------------------------------
112930fdc8d8SChris Lattner 
1130b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1131b9c1b51eSKate Stone     CommandInterpreter &interpreter)
1132b9c1b51eSKate Stone     : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and "
1133b9c1b51eSKate Stone                                                    "examing the current "
1134b9c1b51eSKate Stone                                                    "thread's stack frames.",
1135b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
1136b9c1b51eSKate Stone   LoadSubCommand("diagnose",
1137b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1138b9c1b51eSKate Stone   LoadSubCommand("info",
1139b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1140b9c1b51eSKate Stone   LoadSubCommand("select",
1141b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1142b9c1b51eSKate Stone   LoadSubCommand("variable",
1143b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
114441ae8e74SKuba Mracek #ifndef LLDB_DISABLE_PYTHON
114541ae8e74SKuba Mracek   LoadSubCommand(
114641ae8e74SKuba Mracek       "recognizer",
114741ae8e74SKuba Mracek       CommandObjectSP(new CommandObjectFrameRecognizer(interpreter)));
114841ae8e74SKuba Mracek #endif
114930fdc8d8SChris Lattner }
115030fdc8d8SChris Lattner 
1151c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1152