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"
27*41ae8e74SKuba 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"
44*41ae8e74SKuba 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 
720*41ae8e74SKuba Mracek     if (m_option_variable.show_recognized_args) {
721*41ae8e74SKuba Mracek       auto recognized_frame = frame->GetRecognizedFrame();
722*41ae8e74SKuba Mracek       if (recognized_frame) {
723*41ae8e74SKuba Mracek         ValueObjectListSP recognized_arg_list =
724*41ae8e74SKuba Mracek             recognized_frame->GetRecognizedArguments();
725*41ae8e74SKuba Mracek         if (recognized_arg_list) {
726*41ae8e74SKuba Mracek           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
727*41ae8e74SKuba Mracek             options.SetFormat(m_option_format.GetFormat());
728*41ae8e74SKuba Mracek             options.SetVariableFormatDisplayLanguage(
729*41ae8e74SKuba Mracek                 rec_value_sp->GetPreferredDisplayLanguage());
730*41ae8e74SKuba Mracek             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
731*41ae8e74SKuba Mracek             rec_value_sp->Dump(result.GetOutputStream(), options);
732*41ae8e74SKuba Mracek           }
733*41ae8e74SKuba Mracek         }
734*41ae8e74SKuba Mracek       }
735*41ae8e74SKuba Mracek     }
736*41ae8e74SKuba 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 
760*41ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer
761*41ae8e74SKuba Mracek 
762*41ae8e74SKuba Mracek static OptionDefinition g_frame_recognizer_add_options[] = {
763*41ae8e74SKuba Mracek     // clang-format off
764*41ae8e74SKuba 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." },
765*41ae8e74SKuba Mracek   { LLDB_OPT_SET_ALL, false, "function",      'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeName,        "Name of the function that this recognizer applies to." },
766*41ae8e74SKuba 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." },
767*41ae8e74SKuba Mracek   { LLDB_OPT_SET_ALL, false, "regex",         'x', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,        "Function name and module name are actually regular expressions." }
768*41ae8e74SKuba Mracek     // clang-format on
769*41ae8e74SKuba Mracek };
770*41ae8e74SKuba Mracek 
771*41ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
772*41ae8e74SKuba Mracek private:
773*41ae8e74SKuba Mracek   class CommandOptions : public Options {
774*41ae8e74SKuba Mracek   public:
775*41ae8e74SKuba Mracek     CommandOptions() : Options() {}
776*41ae8e74SKuba Mracek     ~CommandOptions() override = default;
777*41ae8e74SKuba Mracek 
778*41ae8e74SKuba Mracek     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
779*41ae8e74SKuba Mracek                           ExecutionContext *execution_context) override {
780*41ae8e74SKuba Mracek       Status error;
781*41ae8e74SKuba Mracek       const int short_option = m_getopt_table[option_idx].val;
782*41ae8e74SKuba Mracek 
783*41ae8e74SKuba Mracek       switch (short_option) {
784*41ae8e74SKuba Mracek       case 'l':
785*41ae8e74SKuba Mracek         m_class_name = std::string(option_arg);
786*41ae8e74SKuba Mracek         break;
787*41ae8e74SKuba Mracek       case 's':
788*41ae8e74SKuba Mracek         m_module = std::string(option_arg);
789*41ae8e74SKuba Mracek         break;
790*41ae8e74SKuba Mracek       case 'n':
791*41ae8e74SKuba Mracek         m_function = std::string(option_arg);
792*41ae8e74SKuba Mracek         break;
793*41ae8e74SKuba Mracek       case 'x':
794*41ae8e74SKuba Mracek         m_regex = true;
795*41ae8e74SKuba Mracek         break;
796*41ae8e74SKuba Mracek       default:
797*41ae8e74SKuba Mracek         error.SetErrorStringWithFormat("unrecognized option '%c'",
798*41ae8e74SKuba Mracek                                        short_option);
799*41ae8e74SKuba Mracek         break;
800*41ae8e74SKuba Mracek       }
801*41ae8e74SKuba Mracek 
802*41ae8e74SKuba Mracek       return error;
803*41ae8e74SKuba Mracek     }
804*41ae8e74SKuba Mracek 
805*41ae8e74SKuba Mracek     void OptionParsingStarting(ExecutionContext *execution_context) override {
806*41ae8e74SKuba Mracek       m_module = "";
807*41ae8e74SKuba Mracek       m_function = "";
808*41ae8e74SKuba Mracek       m_class_name = "";
809*41ae8e74SKuba Mracek       m_regex = false;
810*41ae8e74SKuba Mracek     }
811*41ae8e74SKuba Mracek 
812*41ae8e74SKuba Mracek     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
813*41ae8e74SKuba Mracek       return llvm::makeArrayRef(g_frame_recognizer_add_options);
814*41ae8e74SKuba Mracek     }
815*41ae8e74SKuba Mracek 
816*41ae8e74SKuba Mracek     // Instance variables to hold the values for command options.
817*41ae8e74SKuba Mracek     std::string m_class_name;
818*41ae8e74SKuba Mracek     std::string m_module;
819*41ae8e74SKuba Mracek     std::string m_function;
820*41ae8e74SKuba Mracek     bool m_regex;
821*41ae8e74SKuba Mracek   };
822*41ae8e74SKuba Mracek 
823*41ae8e74SKuba Mracek   CommandOptions m_options;
824*41ae8e74SKuba Mracek 
825*41ae8e74SKuba Mracek   Options *GetOptions() override { return &m_options; }
826*41ae8e74SKuba Mracek 
827*41ae8e74SKuba Mracek protected:
828*41ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override;
829*41ae8e74SKuba Mracek 
830*41ae8e74SKuba Mracek public:
831*41ae8e74SKuba Mracek   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
832*41ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer add",
833*41ae8e74SKuba Mracek                             "Add a new frame recognizer.", nullptr),
834*41ae8e74SKuba Mracek         m_options() {
835*41ae8e74SKuba Mracek     SetHelpLong(R"(
836*41ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on
837*41ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source
838*41ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments
839*41ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments.
840*41ae8e74SKuba Mracek 
841*41ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class
842*41ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a
843*41ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type
844*41ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize.
845*41ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that
846*41ae8e74SKuba Mracek represent the recognized arguments.
847*41ae8e74SKuba Mracek 
848*41ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc
849*41ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows:
850*41ae8e74SKuba Mracek 
851*41ae8e74SKuba Mracek   class LibcFdRecognizer(object):
852*41ae8e74SKuba Mracek     def get_recognized_arguments(self, frame):
853*41ae8e74SKuba Mracek       if frame.name in ["read", "write", "close"]:
854*41ae8e74SKuba Mracek         fd = frame.EvaluateExpression("$arg1").unsigned
855*41ae8e74SKuba Mracek         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
856*41ae8e74SKuba Mracek         return [value]
857*41ae8e74SKuba Mracek       return []
858*41ae8e74SKuba Mracek 
859*41ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script
860*41ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'.
861*41ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is
862*41ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
863*41ae8e74SKuba Mracek in other modules:
864*41ae8e74SKuba Mracek 
865*41ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py
866*41ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
867*41ae8e74SKuba Mracek 
868*41ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we
869*41ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable':
870*41ae8e74SKuba Mracek 
871*41ae8e74SKuba Mracek (lldb) b read
872*41ae8e74SKuba Mracek (lldb) r
873*41ae8e74SKuba Mracek Process 1234 stopped
874*41ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
875*41ae8e74SKuba Mracek     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
876*41ae8e74SKuba Mracek (lldb) frame variable
877*41ae8e74SKuba Mracek (int) fd = 3
878*41ae8e74SKuba Mracek 
879*41ae8e74SKuba Mracek     )");
880*41ae8e74SKuba Mracek   }
881*41ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerAdd() override = default;
882*41ae8e74SKuba Mracek };
883*41ae8e74SKuba Mracek 
884*41ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
885*41ae8e74SKuba Mracek                                                 CommandReturnObject &result) {
886*41ae8e74SKuba Mracek   if (m_options.m_class_name.empty()) {
887*41ae8e74SKuba Mracek     result.AppendErrorWithFormat(
888*41ae8e74SKuba Mracek         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
889*41ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
890*41ae8e74SKuba Mracek     return false;
891*41ae8e74SKuba Mracek   }
892*41ae8e74SKuba Mracek 
893*41ae8e74SKuba Mracek   if (m_options.m_module.empty()) {
894*41ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
895*41ae8e74SKuba Mracek                                  m_cmd_name.c_str());
896*41ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
897*41ae8e74SKuba Mracek     return false;
898*41ae8e74SKuba Mracek   }
899*41ae8e74SKuba Mracek 
900*41ae8e74SKuba Mracek   if (m_options.m_function.empty()) {
901*41ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a function name (-n argument).\n",
902*41ae8e74SKuba Mracek                                  m_cmd_name.c_str());
903*41ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
904*41ae8e74SKuba Mracek     return false;
905*41ae8e74SKuba Mracek   }
906*41ae8e74SKuba Mracek 
907*41ae8e74SKuba Mracek   ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
908*41ae8e74SKuba Mracek 
909*41ae8e74SKuba Mracek   if (interpreter &&
910*41ae8e74SKuba Mracek       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
911*41ae8e74SKuba Mracek     result.AppendWarning(
912*41ae8e74SKuba Mracek         "The provided class does not exist - please define it "
913*41ae8e74SKuba Mracek         "before attempting to use this frame recognizer");
914*41ae8e74SKuba Mracek   }
915*41ae8e74SKuba Mracek 
916*41ae8e74SKuba Mracek   StackFrameRecognizerSP recognizer_sp =
917*41ae8e74SKuba Mracek       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
918*41ae8e74SKuba Mracek           interpreter, m_options.m_class_name.c_str()));
919*41ae8e74SKuba Mracek   if (m_options.m_regex) {
920*41ae8e74SKuba Mracek     auto module =
921*41ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_module));
922*41ae8e74SKuba Mracek     auto func =
923*41ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_function));
924*41ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
925*41ae8e74SKuba Mracek   } else {
926*41ae8e74SKuba Mracek     auto module = ConstString(m_options.m_module);
927*41ae8e74SKuba Mracek     auto func = ConstString(m_options.m_function);
928*41ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
929*41ae8e74SKuba Mracek   }
930*41ae8e74SKuba Mracek 
931*41ae8e74SKuba Mracek   result.SetStatus(eReturnStatusSuccessFinishNoResult);
932*41ae8e74SKuba Mracek   return result.Succeeded();
933*41ae8e74SKuba Mracek }
934*41ae8e74SKuba Mracek 
935*41ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
936*41ae8e74SKuba Mracek public:
937*41ae8e74SKuba Mracek   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
938*41ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer clear",
939*41ae8e74SKuba Mracek                            "Delete all frame recognizers.", nullptr) {}
940*41ae8e74SKuba Mracek 
941*41ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerClear() override = default;
942*41ae8e74SKuba Mracek 
943*41ae8e74SKuba Mracek protected:
944*41ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
945*41ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveAllRecognizers();
946*41ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
947*41ae8e74SKuba Mracek     return result.Succeeded();
948*41ae8e74SKuba Mracek   }
949*41ae8e74SKuba Mracek };
950*41ae8e74SKuba Mracek 
951*41ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
952*41ae8e74SKuba Mracek  public:
953*41ae8e74SKuba Mracek   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
954*41ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer delete",
955*41ae8e74SKuba Mracek                             "Delete an existing frame recognizer.", nullptr) {}
956*41ae8e74SKuba Mracek 
957*41ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerDelete() override = default;
958*41ae8e74SKuba Mracek 
959*41ae8e74SKuba Mracek  protected:
960*41ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
961*41ae8e74SKuba Mracek     if (command.GetArgumentCount() == 0) {
962*41ae8e74SKuba Mracek       if (!m_interpreter.Confirm(
963*41ae8e74SKuba Mracek               "About to delete all frame recognizers, do you want to do that?",
964*41ae8e74SKuba Mracek               true)) {
965*41ae8e74SKuba Mracek         result.AppendMessage("Operation cancelled...");
966*41ae8e74SKuba Mracek         result.SetStatus(eReturnStatusFailed);
967*41ae8e74SKuba Mracek         return false;
968*41ae8e74SKuba Mracek       }
969*41ae8e74SKuba Mracek 
970*41ae8e74SKuba Mracek       StackFrameRecognizerManager::RemoveAllRecognizers();
971*41ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
972*41ae8e74SKuba Mracek       return result.Succeeded();
973*41ae8e74SKuba Mracek     }
974*41ae8e74SKuba Mracek 
975*41ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
976*41ae8e74SKuba Mracek       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
977*41ae8e74SKuba Mracek                                    m_cmd_name.c_str());
978*41ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
979*41ae8e74SKuba Mracek       return false;
980*41ae8e74SKuba Mracek     }
981*41ae8e74SKuba Mracek 
982*41ae8e74SKuba Mracek     uint32_t recognizer_id =
983*41ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
984*41ae8e74SKuba Mracek 
985*41ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
986*41ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
987*41ae8e74SKuba Mracek     return result.Succeeded();
988*41ae8e74SKuba Mracek   }
989*41ae8e74SKuba Mracek };
990*41ae8e74SKuba Mracek 
991*41ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed {
992*41ae8e74SKuba Mracek  public:
993*41ae8e74SKuba Mracek   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
994*41ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer list",
995*41ae8e74SKuba Mracek                             "Show a list of active frame recognizers.",
996*41ae8e74SKuba Mracek                             nullptr) {}
997*41ae8e74SKuba Mracek 
998*41ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerList() override = default;
999*41ae8e74SKuba Mracek 
1000*41ae8e74SKuba Mracek  protected:
1001*41ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
1002*41ae8e74SKuba Mracek     bool any_printed = false;
1003*41ae8e74SKuba Mracek     StackFrameRecognizerManager::ForEach(
1004*41ae8e74SKuba Mracek         [&result, &any_printed](uint32_t recognizer_id, std::string name,
1005*41ae8e74SKuba Mracek                                 std::string function, std::string symbol,
1006*41ae8e74SKuba Mracek                                 bool regexp) {
1007*41ae8e74SKuba Mracek           if (name == "") name = "(internal)";
1008*41ae8e74SKuba Mracek           result.GetOutputStream().Printf(
1009*41ae8e74SKuba Mracek               "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(),
1010*41ae8e74SKuba Mracek               function.c_str(), symbol.c_str(), regexp ? " (regexp)" : "");
1011*41ae8e74SKuba Mracek           any_printed = true;
1012*41ae8e74SKuba Mracek         });
1013*41ae8e74SKuba Mracek 
1014*41ae8e74SKuba Mracek     if (any_printed)
1015*41ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
1016*41ae8e74SKuba Mracek     else {
1017*41ae8e74SKuba Mracek       result.GetOutputStream().PutCString("no matching results found.\n");
1018*41ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1019*41ae8e74SKuba Mracek     }
1020*41ae8e74SKuba Mracek     return result.Succeeded();
1021*41ae8e74SKuba Mracek   }
1022*41ae8e74SKuba Mracek };
1023*41ae8e74SKuba Mracek 
1024*41ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
1025*41ae8e74SKuba Mracek  public:
1026*41ae8e74SKuba Mracek   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
1027*41ae8e74SKuba Mracek       : CommandObjectParsed(
1028*41ae8e74SKuba Mracek             interpreter, "frame recognizer info",
1029*41ae8e74SKuba Mracek             "Show which frame recognizer is applied a stack frame (if any).",
1030*41ae8e74SKuba Mracek             nullptr) {
1031*41ae8e74SKuba Mracek     CommandArgumentEntry arg;
1032*41ae8e74SKuba Mracek     CommandArgumentData index_arg;
1033*41ae8e74SKuba Mracek 
1034*41ae8e74SKuba Mracek     // Define the first (and only) variant of this arg.
1035*41ae8e74SKuba Mracek     index_arg.arg_type = eArgTypeFrameIndex;
1036*41ae8e74SKuba Mracek     index_arg.arg_repetition = eArgRepeatPlain;
1037*41ae8e74SKuba Mracek 
1038*41ae8e74SKuba Mracek     // There is only one variant this argument could be; put it into the
1039*41ae8e74SKuba Mracek     // argument entry.
1040*41ae8e74SKuba Mracek     arg.push_back(index_arg);
1041*41ae8e74SKuba Mracek 
1042*41ae8e74SKuba Mracek     // Push the data for the first argument into the m_arguments vector.
1043*41ae8e74SKuba Mracek     m_arguments.push_back(arg);
1044*41ae8e74SKuba Mracek   }
1045*41ae8e74SKuba Mracek 
1046*41ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerInfo() override = default;
1047*41ae8e74SKuba Mracek 
1048*41ae8e74SKuba Mracek  protected:
1049*41ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
1050*41ae8e74SKuba Mracek     Process *process = m_exe_ctx.GetProcessPtr();
1051*41ae8e74SKuba Mracek     if (process == nullptr) {
1052*41ae8e74SKuba Mracek       result.AppendError("no process");
1053*41ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
1054*41ae8e74SKuba Mracek       return false;
1055*41ae8e74SKuba Mracek     }
1056*41ae8e74SKuba Mracek     Thread *thread = m_exe_ctx.GetThreadPtr();
1057*41ae8e74SKuba Mracek     if (thread == nullptr) {
1058*41ae8e74SKuba Mracek       result.AppendError("no thread");
1059*41ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
1060*41ae8e74SKuba Mracek       return false;
1061*41ae8e74SKuba Mracek     }
1062*41ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
1063*41ae8e74SKuba Mracek       result.AppendErrorWithFormat(
1064*41ae8e74SKuba Mracek           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
1065*41ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
1066*41ae8e74SKuba Mracek       return false;
1067*41ae8e74SKuba Mracek     }
1068*41ae8e74SKuba Mracek 
1069*41ae8e74SKuba Mracek     uint32_t frame_index =
1070*41ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
1071*41ae8e74SKuba Mracek     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
1072*41ae8e74SKuba Mracek     if (!frame_sp) {
1073*41ae8e74SKuba Mracek       result.AppendErrorWithFormat("no frame with index %u", frame_index);
1074*41ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
1075*41ae8e74SKuba Mracek       return false;
1076*41ae8e74SKuba Mracek     }
1077*41ae8e74SKuba Mracek 
1078*41ae8e74SKuba Mracek     auto recognizer =
1079*41ae8e74SKuba Mracek         StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
1080*41ae8e74SKuba Mracek 
1081*41ae8e74SKuba Mracek     Stream &output_stream = result.GetOutputStream();
1082*41ae8e74SKuba Mracek     output_stream.Printf("frame %d ", frame_index);
1083*41ae8e74SKuba Mracek     if (recognizer) {
1084*41ae8e74SKuba Mracek       output_stream << "is recognized by ";
1085*41ae8e74SKuba Mracek       output_stream << recognizer->GetName();
1086*41ae8e74SKuba Mracek     } else {
1087*41ae8e74SKuba Mracek       output_stream << "not recognized by any recognizer";
1088*41ae8e74SKuba Mracek     }
1089*41ae8e74SKuba Mracek     output_stream.EOL();
1090*41ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
1091*41ae8e74SKuba Mracek     return result.Succeeded();
1092*41ae8e74SKuba Mracek   }
1093*41ae8e74SKuba Mracek };
1094*41ae8e74SKuba Mracek 
1095*41ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword {
1096*41ae8e74SKuba Mracek  public:
1097*41ae8e74SKuba Mracek   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
1098*41ae8e74SKuba Mracek       : CommandObjectMultiword(
1099*41ae8e74SKuba Mracek             interpreter, "frame recognizer",
1100*41ae8e74SKuba Mracek             "Commands for editing and viewing frame recognizers.",
1101*41ae8e74SKuba Mracek             "frame recognizer [<sub-command-options>] ") {
1102*41ae8e74SKuba Mracek     LoadSubCommand(
1103*41ae8e74SKuba Mracek         "add",
1104*41ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter)));
1105*41ae8e74SKuba Mracek     LoadSubCommand(
1106*41ae8e74SKuba Mracek         "clear",
1107*41ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
1108*41ae8e74SKuba Mracek     LoadSubCommand(
1109*41ae8e74SKuba Mracek         "delete",
1110*41ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1111*41ae8e74SKuba Mracek     LoadSubCommand(
1112*41ae8e74SKuba Mracek         "list",
1113*41ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter)));
1114*41ae8e74SKuba Mracek     LoadSubCommand(
1115*41ae8e74SKuba Mracek         "info",
1116*41ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerInfo(interpreter)));
1117*41ae8e74SKuba Mracek   }
1118*41ae8e74SKuba Mracek 
1119*41ae8e74SKuba Mracek   ~CommandObjectFrameRecognizer() override = default;
1120*41ae8e74SKuba Mracek };
1121*41ae8e74SKuba Mracek 
112230fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
112330fdc8d8SChris Lattner 
112430fdc8d8SChris Lattner //-------------------------------------------------------------------------
112530fdc8d8SChris Lattner // CommandObjectMultiwordFrame
112630fdc8d8SChris Lattner //-------------------------------------------------------------------------
112730fdc8d8SChris Lattner 
1128b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1129b9c1b51eSKate Stone     CommandInterpreter &interpreter)
1130b9c1b51eSKate Stone     : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and "
1131b9c1b51eSKate Stone                                                    "examing the current "
1132b9c1b51eSKate Stone                                                    "thread's stack frames.",
1133b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
1134b9c1b51eSKate Stone   LoadSubCommand("diagnose",
1135b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1136b9c1b51eSKate Stone   LoadSubCommand("info",
1137b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1138b9c1b51eSKate Stone   LoadSubCommand("select",
1139b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1140b9c1b51eSKate Stone   LoadSubCommand("variable",
1141b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1142*41ae8e74SKuba Mracek #ifndef LLDB_DISABLE_PYTHON
1143*41ae8e74SKuba Mracek   LoadSubCommand(
1144*41ae8e74SKuba Mracek       "recognizer",
1145*41ae8e74SKuba Mracek       CommandObjectSP(new CommandObjectFrameRecognizer(interpreter)));
1146*41ae8e74SKuba Mracek #endif
114730fdc8d8SChris Lattner }
114830fdc8d8SChris Lattner 
1149c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1150