130fdc8d8SChris Lattner //===-- CommandObjectFrame.cpp ----------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
8c8ecc2a9SEugene Zelenko #include "CommandObjectFrame.h"
930fdc8d8SChris Lattner #include "lldb/Core/Debugger.h"
106d56d2ceSJim Ingham #include "lldb/Core/Module.h"
116d56d2ceSJim Ingham #include "lldb/Core/StreamFile.h"
126d56d2ceSJim Ingham #include "lldb/Core/Value.h"
136d56d2ceSJim Ingham #include "lldb/Core/ValueObject.h"
146d56d2ceSJim Ingham #include "lldb/Core/ValueObjectVariable.h"
155548cb50SEnrico Granata #include "lldb/DataFormatters/DataVisualization.h"
164d93b8cdSEnrico Granata #include "lldb/DataFormatters/ValueObjectPrinter.h"
177fb56d0aSGreg Clayton #include "lldb/Host/Host.h"
183eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h"
1941ae8e74SKuba Mracek #include "lldb/Host/StringConvert.h"
2030fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h"
2130fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h"
221deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h"
232837b766SJim Ingham #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
24715c2365SGreg Clayton #include "lldb/Interpreter/OptionGroupVariable.h"
25b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h"
266d56d2ceSJim Ingham #include "lldb/Symbol/ClangASTContext.h"
27b9c1b51eSKate Stone #include "lldb/Symbol/CompilerType.h"
286754e04fSEnrico Granata #include "lldb/Symbol/Function.h"
296d56d2ceSJim Ingham #include "lldb/Symbol/ObjectFile.h"
306d56d2ceSJim Ingham #include "lldb/Symbol/SymbolContext.h"
316d56d2ceSJim Ingham #include "lldb/Symbol/Type.h"
326d56d2ceSJim Ingham #include "lldb/Symbol/Variable.h"
336d56d2ceSJim Ingham #include "lldb/Symbol/VariableList.h"
3430fdc8d8SChris Lattner #include "lldb/Target/Process.h"
35b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h"
3641ae8e74SKuba Mracek #include "lldb/Target/StackFrameRecognizer.h"
374740a734SSean Callanan #include "lldb/Target/StopInfo.h"
386d56d2ceSJim Ingham #include "lldb/Target/Target.h"
39b9c1b51eSKate Stone #include "lldb/Target/Thread.h"
40145d95c9SPavel Labath #include "lldb/Utility/Args.h"
414740a734SSean Callanan #include "lldb/Utility/LLDBAssert.h"
42bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
4338d0632eSPavel Labath #include "lldb/Utility/Timer.h"
4430fdc8d8SChris Lattner 
45796ac80bSJonas Devlieghere #include <memory>
46796ac80bSJonas Devlieghere #include <string>
47796ac80bSJonas Devlieghere 
4830fdc8d8SChris Lattner using namespace lldb;
4930fdc8d8SChris Lattner using namespace lldb_private;
5030fdc8d8SChris Lattner 
514740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose
524740a734SSean Callanan 
534740a734SSean Callanan // CommandObjectFrameInfo
544740a734SSean Callanan 
554740a734SSean Callanan // CommandObjectFrameDiagnose
564740a734SSean Callanan 
578fe53c49STatyana Krasnukha static constexpr OptionDefinition g_frame_diag_options[] = {
581f0f5b5bSZachary Turner     // clang-format off
598fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "register", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeRegisterName,    "A register to diagnose." },
608fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "address",  'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddress,         "An address to diagnose." },
618fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "offset",   'o', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset,          "An optional offset.  Requires --register." }
621f0f5b5bSZachary Turner     // clang-format on
631f0f5b5bSZachary Turner };
641f0f5b5bSZachary Turner 
65b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed {
664740a734SSean Callanan public:
67b9c1b51eSKate Stone   class CommandOptions : public Options {
684740a734SSean Callanan   public:
69b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
704740a734SSean Callanan 
714740a734SSean Callanan     ~CommandOptions() override = default;
724740a734SSean Callanan 
7397206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
74b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
7597206d57SZachary Turner       Status error;
764740a734SSean Callanan       const int short_option = m_getopt_table[option_idx].val;
77b9c1b51eSKate Stone       switch (short_option) {
784740a734SSean Callanan       case 'r':
794740a734SSean Callanan         reg = ConstString(option_arg);
804740a734SSean Callanan         break;
814740a734SSean Callanan 
82b9c1b51eSKate Stone       case 'a': {
83fe11483bSZachary Turner         address.emplace();
84fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *address)) {
854740a734SSean Callanan           address.reset();
86b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid address argument '%s'",
87fe11483bSZachary Turner                                          option_arg.str().c_str());
884740a734SSean Callanan         }
89b9c1b51eSKate Stone       } break;
904740a734SSean Callanan 
91b9c1b51eSKate Stone       case 'o': {
92fe11483bSZachary Turner         offset.emplace();
93fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *offset)) {
944740a734SSean Callanan           offset.reset();
95b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid offset argument '%s'",
96fe11483bSZachary Turner                                          option_arg.str().c_str());
974740a734SSean Callanan         }
98b9c1b51eSKate Stone       } break;
994740a734SSean Callanan 
1004740a734SSean Callanan       default:
101b9c1b51eSKate Stone         error.SetErrorStringWithFormat("invalid short option character '%c'",
102b9c1b51eSKate Stone                                        short_option);
1034740a734SSean Callanan         break;
1044740a734SSean Callanan       }
1054740a734SSean Callanan 
1064740a734SSean Callanan       return error;
1074740a734SSean Callanan     }
1084740a734SSean Callanan 
109b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
1104740a734SSean Callanan       address.reset();
1114740a734SSean Callanan       reg.reset();
1124740a734SSean Callanan       offset.reset();
1134740a734SSean Callanan     }
1144740a734SSean Callanan 
1151f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
11670602439SZachary Turner       return llvm::makeArrayRef(g_frame_diag_options);
1171f0f5b5bSZachary Turner     }
1184740a734SSean Callanan 
1194740a734SSean Callanan     // Options.
1204740a734SSean Callanan     llvm::Optional<lldb::addr_t> address;
1214740a734SSean Callanan     llvm::Optional<ConstString> reg;
1224740a734SSean Callanan     llvm::Optional<int64_t> offset;
1234740a734SSean Callanan   };
1244740a734SSean Callanan 
1254740a734SSean Callanan   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
1264740a734SSean Callanan       : CommandObjectParsed(interpreter, "frame diagnose",
127b9c1b51eSKate Stone                             "Try to determine what path path the current stop "
128b9c1b51eSKate Stone                             "location used to get to a register or address",
129b9c1b51eSKate Stone                             nullptr,
130b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
131b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched |
1324740a734SSean Callanan                                 eCommandProcessMustBePaused),
133b9c1b51eSKate Stone         m_options() {
1344740a734SSean Callanan     CommandArgumentEntry arg;
1354740a734SSean Callanan     CommandArgumentData index_arg;
1364740a734SSean Callanan 
1374740a734SSean Callanan     // Define the first (and only) variant of this arg.
1384740a734SSean Callanan     index_arg.arg_type = eArgTypeFrameIndex;
1394740a734SSean Callanan     index_arg.arg_repetition = eArgRepeatOptional;
1404740a734SSean Callanan 
141b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
142b9c1b51eSKate Stone     // argument entry.
1434740a734SSean Callanan     arg.push_back(index_arg);
1444740a734SSean Callanan 
1454740a734SSean Callanan     // Push the data for the first argument into the m_arguments vector.
1464740a734SSean Callanan     m_arguments.push_back(arg);
1474740a734SSean Callanan   }
1484740a734SSean Callanan 
1494740a734SSean Callanan   ~CommandObjectFrameDiagnose() override = default;
1504740a734SSean Callanan 
151b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
1524740a734SSean Callanan 
1534740a734SSean Callanan protected:
154b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1554740a734SSean Callanan     Thread *thread = m_exe_ctx.GetThreadPtr();
1564740a734SSean Callanan     StackFrameSP frame_sp = thread->GetSelectedFrame();
1574740a734SSean Callanan 
1584740a734SSean Callanan     ValueObjectSP valobj_sp;
1594740a734SSean Callanan 
160b9c1b51eSKate Stone     if (m_options.address.hasValue()) {
161b9c1b51eSKate Stone       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
162b9c1b51eSKate Stone         result.AppendError(
163b9c1b51eSKate Stone             "`frame diagnose --address` is incompatible with other arguments.");
1644740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1654740a734SSean Callanan         return false;
1664740a734SSean Callanan       }
1674740a734SSean Callanan       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
168b9c1b51eSKate Stone     } else if (m_options.reg.hasValue()) {
169b9c1b51eSKate Stone       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
170b9c1b51eSKate Stone           m_options.reg.getValue(), m_options.offset.getValueOr(0));
171b9c1b51eSKate Stone     } else {
1724740a734SSean Callanan       StopInfoSP stop_info_sp = thread->GetStopInfo();
173b9c1b51eSKate Stone       if (!stop_info_sp) {
1744740a734SSean Callanan         result.AppendError("No arguments provided, and no stop info.");
1754740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1764740a734SSean Callanan         return false;
1774740a734SSean Callanan       }
1784740a734SSean Callanan 
1794740a734SSean Callanan       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
1804740a734SSean Callanan     }
1814740a734SSean Callanan 
182b9c1b51eSKate Stone     if (!valobj_sp) {
1834740a734SSean Callanan       result.AppendError("No diagnosis available.");
1844740a734SSean Callanan       result.SetStatus(eReturnStatusFailed);
1854740a734SSean Callanan       return false;
1864740a734SSean Callanan     }
1874740a734SSean Callanan 
1884740a734SSean Callanan 
1893bc714b2SZachary Turner     DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp](
1903bc714b2SZachary Turner         ConstString type, ConstString var, const DumpValueObjectOptions &opts,
1913bc714b2SZachary Turner         Stream &stream) -> bool {
192b9c1b51eSKate Stone       const ValueObject::GetExpressionPathFormat format = ValueObject::
193b9c1b51eSKate Stone           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
1945d1f711aSPavel Labath       const bool qualify_cxx_base_classes = false;
1954740a734SSean Callanan       valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
1964740a734SSean Callanan       stream.PutCString(" =");
1974740a734SSean Callanan       return true;
1984740a734SSean Callanan     };
1994740a734SSean Callanan 
2004740a734SSean Callanan     DumpValueObjectOptions options;
2014740a734SSean Callanan     options.SetDeclPrintingHelper(helper);
202b9c1b51eSKate Stone     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
203b9c1b51eSKate Stone                                options);
2044740a734SSean Callanan     printer.PrintValueObject();
2054740a734SSean Callanan 
2064740a734SSean Callanan     return true;
2074740a734SSean Callanan   }
2084740a734SSean Callanan 
2094740a734SSean Callanan protected:
2104740a734SSean Callanan   CommandOptions m_options;
2114740a734SSean Callanan };
2124740a734SSean Callanan 
21330fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo
21430fdc8d8SChris Lattner 
21530fdc8d8SChris Lattner // CommandObjectFrameInfo
21630fdc8d8SChris Lattner 
217b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed {
21830fdc8d8SChris Lattner public:
2197428a18cSKate Stone   CommandObjectFrameInfo(CommandInterpreter &interpreter)
220b9c1b51eSKate Stone       : CommandObjectParsed(
221b9c1b51eSKate Stone             interpreter, "frame info", "List information about the current "
222b9c1b51eSKate Stone                                        "stack frame in the current thread.",
223b9c1b51eSKate Stone             "frame info",
224b9c1b51eSKate Stone             eCommandRequiresFrame | eCommandTryTargetAPILock |
225b9c1b51eSKate Stone                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
22630fdc8d8SChris Lattner 
227c8ecc2a9SEugene Zelenko   ~CommandObjectFrameInfo() override = default;
22830fdc8d8SChris Lattner 
2295a988416SJim Ingham protected:
230b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
231f9fc609fSGreg Clayton     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
23230fdc8d8SChris Lattner     result.SetStatus(eReturnStatusSuccessFinishResult);
23330fdc8d8SChris Lattner     return result.Succeeded();
23430fdc8d8SChris Lattner   }
23530fdc8d8SChris Lattner };
23630fdc8d8SChris Lattner 
23730fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect
23830fdc8d8SChris Lattner 
23930fdc8d8SChris Lattner // CommandObjectFrameSelect
24030fdc8d8SChris Lattner 
2411f0f5b5bSZachary Turner static OptionDefinition g_frame_select_options[] = {
2421f0f5b5bSZachary Turner     // clang-format off
2438fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset, "A relative frame index offset from the current frame index." },
2441f0f5b5bSZachary Turner     // clang-format on
2451f0f5b5bSZachary Turner };
2461f0f5b5bSZachary Turner 
247b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed {
24830fdc8d8SChris Lattner public:
249b9c1b51eSKate Stone   class CommandOptions : public Options {
250864174e1SGreg Clayton   public:
251b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
252864174e1SGreg Clayton 
253c8ecc2a9SEugene Zelenko     ~CommandOptions() override = default;
254864174e1SGreg Clayton 
25597206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
256b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
25797206d57SZachary Turner       Status error;
2583bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
259b9c1b51eSKate Stone       switch (short_option) {
260864174e1SGreg Clayton       case 'r':
261fe11483bSZachary Turner         if (option_arg.getAsInteger(0, relative_frame_offset)) {
262fe11483bSZachary Turner           relative_frame_offset = INT32_MIN;
263b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
264fe11483bSZachary Turner                                          option_arg.str().c_str());
265fe11483bSZachary Turner         }
266864174e1SGreg Clayton         break;
267864174e1SGreg Clayton 
268864174e1SGreg Clayton       default:
269b9c1b51eSKate Stone         error.SetErrorStringWithFormat("invalid short option character '%c'",
270b9c1b51eSKate Stone                                        short_option);
271864174e1SGreg Clayton         break;
272864174e1SGreg Clayton       }
273864174e1SGreg Clayton 
274864174e1SGreg Clayton       return error;
275864174e1SGreg Clayton     }
276864174e1SGreg Clayton 
277b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
278864174e1SGreg Clayton       relative_frame_offset = INT32_MIN;
279864174e1SGreg Clayton     }
280864174e1SGreg Clayton 
2811f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
28270602439SZachary Turner       return llvm::makeArrayRef(g_frame_select_options);
2831f0f5b5bSZachary Turner     }
284864174e1SGreg Clayton 
285864174e1SGreg Clayton     int32_t relative_frame_offset;
286864174e1SGreg Clayton   };
287864174e1SGreg Clayton 
2887428a18cSKate Stone   CommandObjectFrameSelect(CommandInterpreter &interpreter)
2897428a18cSKate Stone       : CommandObjectParsed(
290b9c1b51eSKate Stone             interpreter, "frame select", "Select the current stack frame by "
291b9c1b51eSKate Stone                                          "index from within the current thread "
292b9c1b51eSKate Stone                                          "(see 'thread backtrace'.)",
293b9c1b51eSKate Stone             nullptr,
294b9c1b51eSKate Stone             eCommandRequiresThread | eCommandTryTargetAPILock |
295b9c1b51eSKate Stone                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
296b9c1b51eSKate Stone         m_options() {
297405fe67fSCaroline Tice     CommandArgumentEntry arg;
298405fe67fSCaroline Tice     CommandArgumentData index_arg;
299405fe67fSCaroline Tice 
300405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
301405fe67fSCaroline Tice     index_arg.arg_type = eArgTypeFrameIndex;
302864174e1SGreg Clayton     index_arg.arg_repetition = eArgRepeatOptional;
303405fe67fSCaroline Tice 
304b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
305b9c1b51eSKate Stone     // argument entry.
306405fe67fSCaroline Tice     arg.push_back(index_arg);
307405fe67fSCaroline Tice 
308405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
309405fe67fSCaroline Tice     m_arguments.push_back(arg);
31030fdc8d8SChris Lattner   }
31130fdc8d8SChris Lattner 
312c8ecc2a9SEugene Zelenko   ~CommandObjectFrameSelect() override = default;
31330fdc8d8SChris Lattner 
314b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
315864174e1SGreg Clayton 
3165a988416SJim Ingham protected:
317b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
318b9c1b51eSKate Stone     // No need to check "thread" for validity as eCommandRequiresThread ensures
319b9c1b51eSKate Stone     // it is valid
320f9fc609fSGreg Clayton     Thread *thread = m_exe_ctx.GetThreadPtr();
321f9fc609fSGreg Clayton 
322864174e1SGreg Clayton     uint32_t frame_idx = UINT32_MAX;
323b9c1b51eSKate Stone     if (m_options.relative_frame_offset != INT32_MIN) {
324864174e1SGreg Clayton       // The one and only argument is a signed relative frame index
325c14ee32dSGreg Clayton       frame_idx = thread->GetSelectedFrameIndex();
326864174e1SGreg Clayton       if (frame_idx == UINT32_MAX)
327864174e1SGreg Clayton         frame_idx = 0;
328864174e1SGreg Clayton 
329b9c1b51eSKate Stone       if (m_options.relative_frame_offset < 0) {
3303985c8c6SSaleem Abdulrasool         if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset)
331864174e1SGreg Clayton           frame_idx += m_options.relative_frame_offset;
332b9c1b51eSKate Stone         else {
333b9c1b51eSKate Stone           if (frame_idx == 0) {
33405097246SAdrian Prantl             // If you are already at the bottom of the stack, then just warn
33505097246SAdrian Prantl             // and don't reset the frame.
3367428a18cSKate Stone             result.AppendError("Already at the bottom of the stack.");
337213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
338213b4546SJim Ingham             return false;
339b9c1b51eSKate Stone           } else
340864174e1SGreg Clayton             frame_idx = 0;
341864174e1SGreg Clayton         }
342b9c1b51eSKate Stone       } else if (m_options.relative_frame_offset > 0) {
343b9c1b51eSKate Stone         // I don't want "up 20" where "20" takes you past the top of the stack
344b9c1b51eSKate Stone         // to produce
345b9c1b51eSKate Stone         // an error, but rather to just go to the top.  So I have to count the
346b9c1b51eSKate Stone         // stack here...
347b0c72a5fSJim Ingham         const uint32_t num_frames = thread->GetStackFrameCount();
348b9c1b51eSKate Stone         if (static_cast<int32_t>(num_frames - frame_idx) >
349b9c1b51eSKate Stone             m_options.relative_frame_offset)
350864174e1SGreg Clayton           frame_idx += m_options.relative_frame_offset;
351b9c1b51eSKate Stone         else {
352b9c1b51eSKate Stone           if (frame_idx == num_frames - 1) {
353b9c1b51eSKate Stone             // If we are already at the top of the stack, just warn and don't
354b9c1b51eSKate Stone             // reset the frame.
3557428a18cSKate Stone             result.AppendError("Already at the top of the stack.");
356213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
357213b4546SJim Ingham             return false;
358b9c1b51eSKate Stone           } else
359864174e1SGreg Clayton             frame_idx = num_frames - 1;
360864174e1SGreg Clayton         }
361864174e1SGreg Clayton       }
362b9c1b51eSKate Stone     } else {
363f965cc86SZachary Turner       if (command.GetArgumentCount() > 1) {
364f965cc86SZachary Turner         result.AppendErrorWithFormat(
365f965cc86SZachary Turner             "too many arguments; expected frame-index, saw '%s'.\n",
366867e7d17SZachary Turner             command[0].c_str());
367f965cc86SZachary Turner         m_options.GenerateOptionUsage(
368f965cc86SZachary Turner             result.GetErrorStream(), this,
369f965cc86SZachary Turner             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
370f965cc86SZachary Turner         return false;
371f965cc86SZachary Turner       }
372f965cc86SZachary Turner 
373b9c1b51eSKate Stone       if (command.GetArgumentCount() == 1) {
374f965cc86SZachary Turner         if (command[0].ref.getAsInteger(0, frame_idx)) {
375b9c1b51eSKate Stone           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
376f965cc86SZachary Turner                                        command[0].c_str());
377afbb0af8SJim Ingham           result.SetStatus(eReturnStatusFailed);
378afbb0af8SJim Ingham           return false;
379afbb0af8SJim Ingham         }
380b9c1b51eSKate Stone       } else if (command.GetArgumentCount() == 0) {
38182d4a2b9SJason Molenda         frame_idx = thread->GetSelectedFrameIndex();
382b9c1b51eSKate Stone         if (frame_idx == UINT32_MAX) {
38382d4a2b9SJason Molenda           frame_idx = 0;
38482d4a2b9SJason Molenda         }
385864174e1SGreg Clayton       }
386864174e1SGreg Clayton     }
38730fdc8d8SChris Lattner 
388b9c1b51eSKate Stone     bool success = thread->SetSelectedFrameByIndexNoisily(
389b9c1b51eSKate Stone         frame_idx, result.GetOutputStream());
390b9c1b51eSKate Stone     if (success) {
391f9fc609fSGreg Clayton       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
39230fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
393b9c1b51eSKate Stone     } else {
394b9c1b51eSKate Stone       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
395b9c1b51eSKate Stone                                    frame_idx);
39630fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
39793208b86SJim Ingham     }
39893208b86SJim Ingham 
39993208b86SJim Ingham     return result.Succeeded();
40030fdc8d8SChris Lattner   }
401864174e1SGreg Clayton 
402c8ecc2a9SEugene Zelenko protected:
403864174e1SGreg Clayton   CommandOptions m_options;
404864174e1SGreg Clayton };
405864174e1SGreg Clayton 
4066d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable
4076d56d2ceSJim Ingham // List images with associated information
408b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed {
4096d56d2ceSJim Ingham public:
4107428a18cSKate Stone   CommandObjectFrameVariable(CommandInterpreter &interpreter)
4117428a18cSKate Stone       : CommandObjectParsed(
412b9c1b51eSKate Stone             interpreter, "frame variable",
413b9c1b51eSKate Stone             "Show variables for the current stack frame. Defaults to all "
4147428a18cSKate Stone             "arguments and local variables in scope. Names of argument, "
4157428a18cSKate Stone             "local, file static and file global variables can be specified. "
416ed8a705cSGreg Clayton             "Children of aggregate variables can be specified such as "
417285ae0c0SJim Ingham             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
418285ae0c0SJim Ingham             "not invoke operator overloads if they exist, but directly access "
419285ae0c0SJim Ingham             "the specified element.  If you want to trigger operator overloads "
420285ae0c0SJim Ingham             "use the expression command to print the variable instead."
421285ae0c0SJim Ingham             "\nIt is worth noting that except for overloaded "
422285ae0c0SJim Ingham             "operators, when printing local variables 'expr local_var' and "
423285ae0c0SJim Ingham             "'frame var local_var' produce the same "
424285ae0c0SJim Ingham             "results.  However, 'frame variable' is more efficient, since it "
425285ae0c0SJim Ingham             "uses debug information and memory reads directly, rather than "
426285ae0c0SJim Ingham             "parsing and evaluating an expression, which may even involve "
427285ae0c0SJim Ingham             "JITing and running code in the target program.",
428b9c1b51eSKate Stone             nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock |
429b9c1b51eSKate Stone                          eCommandProcessMustBeLaunched |
4307428a18cSKate Stone                          eCommandProcessMustBePaused | eCommandRequiresProcess),
431e1cfbc79STodd Fiala         m_option_group(),
432b9c1b51eSKate Stone         m_option_variable(
433b9c1b51eSKate Stone             true), // Include the frame specific options by passing "true"
4341deb7962SGreg Clayton         m_option_format(eFormatDefault),
435b9c1b51eSKate Stone         m_varobj_options() {
436405fe67fSCaroline Tice     CommandArgumentEntry arg;
437405fe67fSCaroline Tice     CommandArgumentData var_name_arg;
438405fe67fSCaroline Tice 
439405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
440405fe67fSCaroline Tice     var_name_arg.arg_type = eArgTypeVarName;
441405fe67fSCaroline Tice     var_name_arg.arg_repetition = eArgRepeatStar;
442405fe67fSCaroline Tice 
443b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
444b9c1b51eSKate Stone     // argument entry.
445405fe67fSCaroline Tice     arg.push_back(var_name_arg);
446405fe67fSCaroline Tice 
447405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
448405fe67fSCaroline Tice     m_arguments.push_back(arg);
4492837b766SJim Ingham 
450715c2365SGreg Clayton     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
451b9c1b51eSKate Stone     m_option_group.Append(&m_option_format,
452b9c1b51eSKate Stone                           OptionGroupFormat::OPTION_GROUP_FORMAT |
453b9c1b51eSKate Stone                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
454b9c1b51eSKate Stone                           LLDB_OPT_SET_1);
4552837b766SJim Ingham     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
4562837b766SJim Ingham     m_option_group.Finalize();
4576d56d2ceSJim Ingham   }
4586d56d2ceSJim Ingham 
459c8ecc2a9SEugene Zelenko   ~CommandObjectFrameVariable() override = default;
4606d56d2ceSJim Ingham 
461b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
462f21feadcSGreg Clayton 
4632443bbd4SRaphael Isemann   int HandleArgumentCompletion(
4642443bbd4SRaphael Isemann       CompletionRequest &request,
4652443bbd4SRaphael Isemann       OptionElementVector &opt_element_vector) override {
466f21feadcSGreg Clayton     // Arguments are the standard source file completer.
467b9c1b51eSKate Stone     CommandCompletions::InvokeCommonCompletionCallbacks(
468b9c1b51eSKate Stone         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
469a2e76c0bSRaphael Isemann         request, nullptr);
4701a6d7ab5SRaphael Isemann     return request.GetNumberOfMatches();
471f21feadcSGreg Clayton   }
4726d56d2ceSJim Ingham 
4735a988416SJim Ingham protected:
47473418dfeSEnrico Granata   llvm::StringRef GetScopeString(VariableSP var_sp) {
47573418dfeSEnrico Granata     if (!var_sp)
47673418dfeSEnrico Granata       return llvm::StringRef::withNullAsEmpty(nullptr);
47773418dfeSEnrico Granata 
47873418dfeSEnrico Granata     switch (var_sp->GetScope()) {
47973418dfeSEnrico Granata     case eValueTypeVariableGlobal:
48073418dfeSEnrico Granata       return "GLOBAL: ";
48173418dfeSEnrico Granata     case eValueTypeVariableStatic:
48273418dfeSEnrico Granata       return "STATIC: ";
48373418dfeSEnrico Granata     case eValueTypeVariableArgument:
48473418dfeSEnrico Granata       return "ARG: ";
48573418dfeSEnrico Granata     case eValueTypeVariableLocal:
48673418dfeSEnrico Granata       return "LOCAL: ";
48773418dfeSEnrico Granata     case eValueTypeVariableThreadLocal:
48873418dfeSEnrico Granata       return "THREAD: ";
48973418dfeSEnrico Granata     default:
49073418dfeSEnrico Granata       break;
49173418dfeSEnrico Granata     }
49273418dfeSEnrico Granata 
49373418dfeSEnrico Granata     return llvm::StringRef::withNullAsEmpty(nullptr);
49473418dfeSEnrico Granata   }
49573418dfeSEnrico Granata 
496b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
49705097246SAdrian Prantl     // No need to check "frame" for validity as eCommandRequiresFrame ensures
49805097246SAdrian Prantl     // it is valid
499b57e4a1bSJason Molenda     StackFrame *frame = m_exe_ctx.GetFramePtr();
5001e49e5e7SJohnny Chen 
501a134cc1bSGreg Clayton     Stream &s = result.GetOutputStream();
5026d56d2ceSJim Ingham 
503b9c1b51eSKate Stone     // Be careful about the stack frame, if any summary formatter runs code, it
50405097246SAdrian Prantl     // might clear the StackFrameList for the thread.  So hold onto a shared
50505097246SAdrian Prantl     // pointer to the frame so it stays alive.
506650543f9SJim Ingham 
507b9c1b51eSKate Stone     VariableList *variable_list =
508b9c1b51eSKate Stone         frame->GetVariableList(m_option_variable.show_globals);
509a134cc1bSGreg Clayton 
5106d56d2ceSJim Ingham     VariableSP var_sp;
5116d56d2ceSJim Ingham     ValueObjectSP valobj_sp;
51278a685aaSJim Ingham 
513061858ceSEnrico Granata     TypeSummaryImplSP summary_format_sp;
51417b11749SEnrico Granata     if (!m_option_variable.summary.IsCurrentValueEmpty())
515b9c1b51eSKate Stone       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
516b9c1b51eSKate Stone           ConstString(m_option_variable.summary.GetCurrentValue()),
517b9c1b51eSKate Stone           summary_format_sp);
51817b11749SEnrico Granata     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
519796ac80bSJonas Devlieghere       summary_format_sp = std::make_shared<StringSummaryFormat>(
520b9c1b51eSKate Stone           TypeSummaryImpl::Flags(),
521796ac80bSJonas Devlieghere           m_option_variable.summary_string.GetCurrentValue());
522f9fa6ee5SEnrico Granata 
523b9c1b51eSKate Stone     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
524b9c1b51eSKate Stone         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
525b9c1b51eSKate Stone         summary_format_sp));
526379447a7SEnrico Granata 
527b9c1b51eSKate Stone     const SymbolContext &sym_ctx =
528b9c1b51eSKate Stone         frame->GetSymbolContext(eSymbolContextFunction);
5296754e04fSEnrico Granata     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
5306754e04fSEnrico Granata       m_option_variable.show_globals = true;
5316754e04fSEnrico Granata 
532b9c1b51eSKate Stone     if (variable_list) {
5331deb7962SGreg Clayton       const Format format = m_option_format.GetFormat();
5340c489f58SEnrico Granata       options.SetFormat(format);
5351deb7962SGreg Clayton 
53611eb9c64SZachary Turner       if (!command.empty()) {
53746747022SGreg Clayton         VariableList regex_var_list;
53846747022SGreg Clayton 
53905097246SAdrian Prantl         // If we have any args to the variable command, we will make variable
54005097246SAdrian Prantl         // objects from them...
541f965cc86SZachary Turner         for (auto &entry : command) {
542b9c1b51eSKate Stone           if (m_option_variable.use_regex) {
543c7bece56SGreg Clayton             const size_t regex_start_index = regex_var_list.GetSize();
544f965cc86SZachary Turner             llvm::StringRef name_str = entry.ref;
54595eae423SZachary Turner             RegularExpression regex(name_str);
54695eae423SZachary Turner             if (regex.Compile(name_str)) {
54746747022SGreg Clayton               size_t num_matches = 0;
548b9c1b51eSKate Stone               const size_t num_new_regex_vars =
549b9c1b51eSKate Stone                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
55078a685aaSJim Ingham                                                          num_matches);
551b9c1b51eSKate Stone               if (num_new_regex_vars > 0) {
552b9c1b51eSKate Stone                 for (size_t regex_idx = regex_start_index,
553b9c1b51eSKate Stone                             end_index = regex_var_list.GetSize();
554b9c1b51eSKate Stone                      regex_idx < end_index; ++regex_idx) {
55546747022SGreg Clayton                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
556b9c1b51eSKate Stone                   if (var_sp) {
557b9c1b51eSKate Stone                     valobj_sp = frame->GetValueObjectForFrameVariable(
558b9c1b51eSKate Stone                         var_sp, m_varobj_options.use_dynamic);
559b9c1b51eSKate Stone                     if (valobj_sp) {
56073418dfeSEnrico Granata                       std::string scope_string;
56173418dfeSEnrico Granata                       if (m_option_variable.show_scope)
56273418dfeSEnrico Granata                         scope_string = GetScopeString(var_sp).str();
56373418dfeSEnrico Granata 
56473418dfeSEnrico Granata                       if (!scope_string.empty())
565771ef6d4SMalcolm Parsons                         s.PutCString(scope_string);
56673418dfeSEnrico Granata 
567b9c1b51eSKate Stone                       if (m_option_variable.show_decl &&
568b9c1b51eSKate Stone                           var_sp->GetDeclaration().GetFile()) {
56945ba8543SGreg Clayton                         bool show_fullpaths = false;
57045ba8543SGreg Clayton                         bool show_module = true;
571b9c1b51eSKate Stone                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
572b9c1b51eSKate Stone                                                     show_module))
57346747022SGreg Clayton                           s.PutCString(": ");
57446747022SGreg Clayton                       }
5754d93b8cdSEnrico Granata                       valobj_sp->Dump(result.GetOutputStream(), options);
57646747022SGreg Clayton                     }
57746747022SGreg Clayton                   }
57846747022SGreg Clayton                 }
579b9c1b51eSKate Stone               } else if (num_matches == 0) {
580b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: no variables matched "
581b9c1b51eSKate Stone                                                "the regular expression '%s'.\n",
582f965cc86SZachary Turner                                                entry.c_str());
58346747022SGreg Clayton               }
584b9c1b51eSKate Stone             } else {
58546747022SGreg Clayton               char regex_error[1024];
58646747022SGreg Clayton               if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
58746747022SGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", regex_error);
58846747022SGreg Clayton               else
589b9c1b51eSKate Stone                 result.GetErrorStream().Printf(
590b9c1b51eSKate Stone                     "error: unknown regex error when compiling '%s'\n",
591f965cc86SZachary Turner                     entry.c_str());
59246747022SGreg Clayton             }
593b9c1b51eSKate Stone           } else // No regex, either exact variable names or variable
594b9c1b51eSKate Stone                  // expressions.
59546747022SGreg Clayton           {
59697206d57SZachary Turner             Status error;
597b9c1b51eSKate Stone             uint32_t expr_path_options =
598b9c1b51eSKate Stone                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
59946252398SEnrico Granata                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
60046252398SEnrico Granata                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
6012837b766SJim Ingham             lldb::VariableSP var_sp;
602b9c1b51eSKate Stone             valobj_sp = frame->GetValueForVariableExpressionPath(
603f965cc86SZachary Turner                 entry.ref, m_varobj_options.use_dynamic, expr_path_options,
604b9c1b51eSKate Stone                 var_sp, error);
605b9c1b51eSKate Stone             if (valobj_sp) {
60673418dfeSEnrico Granata               std::string scope_string;
60773418dfeSEnrico Granata               if (m_option_variable.show_scope)
60873418dfeSEnrico Granata                 scope_string = GetScopeString(var_sp).str();
60973418dfeSEnrico Granata 
61073418dfeSEnrico Granata               if (!scope_string.empty())
611771ef6d4SMalcolm Parsons                 s.PutCString(scope_string);
612b9c1b51eSKate Stone               if (m_option_variable.show_decl && var_sp &&
613b9c1b51eSKate Stone                   var_sp->GetDeclaration().GetFile()) {
614a134cc1bSGreg Clayton                 var_sp->GetDeclaration().DumpStopContext(&s, false);
615a134cc1bSGreg Clayton                 s.PutCString(": ");
616a134cc1bSGreg Clayton               }
6170c489f58SEnrico Granata 
6180c489f58SEnrico Granata               options.SetFormat(format);
619b9c1b51eSKate Stone               options.SetVariableFormatDisplayLanguage(
620b9c1b51eSKate Stone                   valobj_sp->GetPreferredDisplayLanguage());
621887062aeSJohnny Chen 
622887062aeSJohnny Chen               Stream &output_stream = result.GetOutputStream();
623f965cc86SZachary Turner               options.SetRootValueObjectName(
624f965cc86SZachary Turner                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
6254d93b8cdSEnrico Granata               valobj_sp->Dump(output_stream, options);
626b9c1b51eSKate Stone             } else {
627c8ecc2a9SEugene Zelenko               const char *error_cstr = error.AsCString(nullptr);
62854979cddSGreg Clayton               if (error_cstr)
62954979cddSGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
63054979cddSGreg Clayton               else
631b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: unable to find any "
632b9c1b51eSKate Stone                                                "variable expression path that "
633b9c1b51eSKate Stone                                                "matches '%s'.\n",
634f965cc86SZachary Turner                                                entry.c_str());
6356d56d2ceSJim Ingham             }
6366d56d2ceSJim Ingham           }
6376d56d2ceSJim Ingham         }
638b9c1b51eSKate Stone       } else // No command arg specified.  Use variable_list, instead.
6396d56d2ceSJim Ingham       {
640c7bece56SGreg Clayton         const size_t num_variables = variable_list->GetSize();
641b9c1b51eSKate Stone         if (num_variables > 0) {
642b9c1b51eSKate Stone           for (size_t i = 0; i < num_variables; i++) {
6431a65ae11SGreg Clayton             var_sp = variable_list->GetVariableAtIndex(i);
644f955efc0SSylvestre Ledru             switch (var_sp->GetScope()) {
645eb236735SJim Ingham             case eValueTypeVariableGlobal:
646eb236735SJim Ingham               if (!m_option_variable.show_globals)
647eb236735SJim Ingham                 continue;
648eb236735SJim Ingham               break;
649eb236735SJim Ingham             case eValueTypeVariableStatic:
650eb236735SJim Ingham               if (!m_option_variable.show_globals)
651eb236735SJim Ingham                 continue;
652eb236735SJim Ingham               break;
653eb236735SJim Ingham             case eValueTypeVariableArgument:
654eb236735SJim Ingham               if (!m_option_variable.show_args)
655eb236735SJim Ingham                 continue;
656eb236735SJim Ingham               break;
657eb236735SJim Ingham             case eValueTypeVariableLocal:
658eb236735SJim Ingham               if (!m_option_variable.show_locals)
659eb236735SJim Ingham                 continue;
660eb236735SJim Ingham               break;
661eb236735SJim Ingham             default:
662eb236735SJim Ingham               continue;
663eb236735SJim Ingham               break;
664eb236735SJim Ingham             }
665560558ebSEnrico Granata             std::string scope_string;
666eb236735SJim Ingham             if (m_option_variable.show_scope)
66773418dfeSEnrico Granata               scope_string = GetScopeString(var_sp).str();
6686d56d2ceSJim Ingham 
66905097246SAdrian Prantl             // Use the variable object code to make sure we are using the same
67005097246SAdrian Prantl             // APIs as the public API will be using...
671b9c1b51eSKate Stone             valobj_sp = frame->GetValueObjectForFrameVariable(
672b9c1b51eSKate Stone                 var_sp, m_varobj_options.use_dynamic);
673b9c1b51eSKate Stone             if (valobj_sp) {
67405097246SAdrian Prantl               // When dumping all variables, don't print any variables that are
67505097246SAdrian Prantl               // not in scope to avoid extra unneeded output
676b9c1b51eSKate Stone               if (valobj_sp->IsInScope()) {
677b9c1b51eSKate Stone                 if (!valobj_sp->GetTargetSP()
678b9c1b51eSKate Stone                          ->GetDisplayRuntimeSupportValues() &&
679c8ecc2a9SEugene Zelenko                     valobj_sp->IsRuntimeSupportValue())
680560558ebSEnrico Granata                   continue;
681560558ebSEnrico Granata 
682560558ebSEnrico Granata                 if (!scope_string.empty())
683771ef6d4SMalcolm Parsons                   s.PutCString(scope_string);
684560558ebSEnrico Granata 
685b9c1b51eSKate Stone                 if (m_option_variable.show_decl &&
686b9c1b51eSKate Stone                     var_sp->GetDeclaration().GetFile()) {
687a134cc1bSGreg Clayton                   var_sp->GetDeclaration().DumpStopContext(&s, false);
688a134cc1bSGreg Clayton                   s.PutCString(": ");
689a134cc1bSGreg Clayton                 }
6900c489f58SEnrico Granata 
6910c489f58SEnrico Granata                 options.SetFormat(format);
692b9c1b51eSKate Stone                 options.SetVariableFormatDisplayLanguage(
693b9c1b51eSKate Stone                     valobj_sp->GetPreferredDisplayLanguage());
694f965cc86SZachary Turner                 options.SetRootValueObjectName(
695f965cc86SZachary Turner                     var_sp ? var_sp->GetName().AsCString() : nullptr);
6964d93b8cdSEnrico Granata                 valobj_sp->Dump(result.GetOutputStream(), options);
697a134cc1bSGreg Clayton               }
698a134cc1bSGreg Clayton             }
6996d56d2ceSJim Ingham           }
7006d56d2ceSJim Ingham         }
7016d56d2ceSJim Ingham       }
7026d56d2ceSJim Ingham       result.SetStatus(eReturnStatusSuccessFinishResult);
7036d56d2ceSJim Ingham     }
70461a80ba6SEnrico Granata 
70541ae8e74SKuba Mracek     if (m_option_variable.show_recognized_args) {
70641ae8e74SKuba Mracek       auto recognized_frame = frame->GetRecognizedFrame();
70741ae8e74SKuba Mracek       if (recognized_frame) {
70841ae8e74SKuba Mracek         ValueObjectListSP recognized_arg_list =
70941ae8e74SKuba Mracek             recognized_frame->GetRecognizedArguments();
71041ae8e74SKuba Mracek         if (recognized_arg_list) {
71141ae8e74SKuba Mracek           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
71241ae8e74SKuba Mracek             options.SetFormat(m_option_format.GetFormat());
71341ae8e74SKuba Mracek             options.SetVariableFormatDisplayLanguage(
71441ae8e74SKuba Mracek                 rec_value_sp->GetPreferredDisplayLanguage());
71541ae8e74SKuba Mracek             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
71641ae8e74SKuba Mracek             rec_value_sp->Dump(result.GetOutputStream(), options);
71741ae8e74SKuba Mracek           }
71841ae8e74SKuba Mracek         }
71941ae8e74SKuba Mracek       }
72041ae8e74SKuba Mracek     }
72141ae8e74SKuba Mracek 
722b9c1b51eSKate Stone     if (m_interpreter.TruncationWarningNecessary()) {
72361a80ba6SEnrico Granata       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
72461a80ba6SEnrico Granata                                       m_cmd_name.c_str());
72561a80ba6SEnrico Granata       m_interpreter.TruncationWarningGiven();
72661a80ba6SEnrico Granata     }
72761a80ba6SEnrico Granata 
72824fff242SDavide Italiano     // Increment statistics.
72924fff242SDavide Italiano     bool res = result.Succeeded();
7300df817aaSDavide Italiano     Target *target = GetSelectedOrDummyTarget();
73124fff242SDavide Italiano     if (res)
73224fff242SDavide Italiano       target->IncrementStats(StatisticKind::FrameVarSuccess);
73324fff242SDavide Italiano     else
73424fff242SDavide Italiano       target->IncrementStats(StatisticKind::FrameVarFailure);
73524fff242SDavide Italiano     return res;
7366d56d2ceSJim Ingham   }
7376d56d2ceSJim Ingham 
738c8ecc2a9SEugene Zelenko protected:
7392837b766SJim Ingham   OptionGroupOptions m_option_group;
740715c2365SGreg Clayton   OptionGroupVariable m_option_variable;
7411deb7962SGreg Clayton   OptionGroupFormat m_option_format;
7422837b766SJim Ingham   OptionGroupValueObjectDisplay m_varobj_options;
7436d56d2ceSJim Ingham };
7446d56d2ceSJim Ingham 
74541ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer
74641ae8e74SKuba Mracek 
74741ae8e74SKuba Mracek static OptionDefinition g_frame_recognizer_add_options[] = {
74841ae8e74SKuba Mracek     // clang-format off
74941ae8e74SKuba 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." },
75041ae8e74SKuba Mracek   { LLDB_OPT_SET_ALL, false, "function",      'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeName,        "Name of the function that this recognizer applies to." },
75141ae8e74SKuba 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." },
75241ae8e74SKuba Mracek   { LLDB_OPT_SET_ALL, false, "regex",         'x', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,        "Function name and module name are actually regular expressions." }
75341ae8e74SKuba Mracek     // clang-format on
75441ae8e74SKuba Mracek };
75541ae8e74SKuba Mracek 
75641ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
75741ae8e74SKuba Mracek private:
75841ae8e74SKuba Mracek   class CommandOptions : public Options {
75941ae8e74SKuba Mracek   public:
76041ae8e74SKuba Mracek     CommandOptions() : Options() {}
76141ae8e74SKuba Mracek     ~CommandOptions() override = default;
76241ae8e74SKuba Mracek 
76341ae8e74SKuba Mracek     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
76441ae8e74SKuba Mracek                           ExecutionContext *execution_context) override {
76541ae8e74SKuba Mracek       Status error;
76641ae8e74SKuba Mracek       const int short_option = m_getopt_table[option_idx].val;
76741ae8e74SKuba Mracek 
76841ae8e74SKuba Mracek       switch (short_option) {
76941ae8e74SKuba Mracek       case 'l':
77041ae8e74SKuba Mracek         m_class_name = std::string(option_arg);
77141ae8e74SKuba Mracek         break;
77241ae8e74SKuba Mracek       case 's':
77341ae8e74SKuba Mracek         m_module = std::string(option_arg);
77441ae8e74SKuba Mracek         break;
77541ae8e74SKuba Mracek       case 'n':
77641ae8e74SKuba Mracek         m_function = std::string(option_arg);
77741ae8e74SKuba Mracek         break;
77841ae8e74SKuba Mracek       case 'x':
77941ae8e74SKuba Mracek         m_regex = true;
78041ae8e74SKuba Mracek         break;
78141ae8e74SKuba Mracek       default:
78241ae8e74SKuba Mracek         error.SetErrorStringWithFormat("unrecognized option '%c'",
78341ae8e74SKuba Mracek                                        short_option);
78441ae8e74SKuba Mracek         break;
78541ae8e74SKuba Mracek       }
78641ae8e74SKuba Mracek 
78741ae8e74SKuba Mracek       return error;
78841ae8e74SKuba Mracek     }
78941ae8e74SKuba Mracek 
79041ae8e74SKuba Mracek     void OptionParsingStarting(ExecutionContext *execution_context) override {
79141ae8e74SKuba Mracek       m_module = "";
79241ae8e74SKuba Mracek       m_function = "";
79341ae8e74SKuba Mracek       m_class_name = "";
79441ae8e74SKuba Mracek       m_regex = false;
79541ae8e74SKuba Mracek     }
79641ae8e74SKuba Mracek 
79741ae8e74SKuba Mracek     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
79841ae8e74SKuba Mracek       return llvm::makeArrayRef(g_frame_recognizer_add_options);
79941ae8e74SKuba Mracek     }
80041ae8e74SKuba Mracek 
80141ae8e74SKuba Mracek     // Instance variables to hold the values for command options.
80241ae8e74SKuba Mracek     std::string m_class_name;
80341ae8e74SKuba Mracek     std::string m_module;
80441ae8e74SKuba Mracek     std::string m_function;
80541ae8e74SKuba Mracek     bool m_regex;
80641ae8e74SKuba Mracek   };
80741ae8e74SKuba Mracek 
80841ae8e74SKuba Mracek   CommandOptions m_options;
80941ae8e74SKuba Mracek 
81041ae8e74SKuba Mracek   Options *GetOptions() override { return &m_options; }
81141ae8e74SKuba Mracek 
81241ae8e74SKuba Mracek protected:
81341ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override;
81441ae8e74SKuba Mracek 
81541ae8e74SKuba Mracek public:
81641ae8e74SKuba Mracek   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
81741ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer add",
81841ae8e74SKuba Mracek                             "Add a new frame recognizer.", nullptr),
81941ae8e74SKuba Mracek         m_options() {
82041ae8e74SKuba Mracek     SetHelpLong(R"(
82141ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on
82241ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source
82341ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments
82441ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments.
82541ae8e74SKuba Mracek 
82641ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class
82741ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a
82841ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type
82941ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize.
83041ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that
83141ae8e74SKuba Mracek represent the recognized arguments.
83241ae8e74SKuba Mracek 
83341ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc
83441ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows:
83541ae8e74SKuba Mracek 
83641ae8e74SKuba Mracek   class LibcFdRecognizer(object):
83741ae8e74SKuba Mracek     def get_recognized_arguments(self, frame):
83841ae8e74SKuba Mracek       if frame.name in ["read", "write", "close"]:
83941ae8e74SKuba Mracek         fd = frame.EvaluateExpression("$arg1").unsigned
84041ae8e74SKuba Mracek         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
84141ae8e74SKuba Mracek         return [value]
84241ae8e74SKuba Mracek       return []
84341ae8e74SKuba Mracek 
84441ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script
84541ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'.
84641ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is
84741ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
84841ae8e74SKuba Mracek in other modules:
84941ae8e74SKuba Mracek 
85041ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py
85141ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
85241ae8e74SKuba Mracek 
85341ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we
85441ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable':
85541ae8e74SKuba Mracek 
85641ae8e74SKuba Mracek (lldb) b read
85741ae8e74SKuba Mracek (lldb) r
85841ae8e74SKuba Mracek Process 1234 stopped
85941ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
86041ae8e74SKuba Mracek     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
86141ae8e74SKuba Mracek (lldb) frame variable
86241ae8e74SKuba Mracek (int) fd = 3
86341ae8e74SKuba Mracek 
86441ae8e74SKuba Mracek     )");
86541ae8e74SKuba Mracek   }
86641ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerAdd() override = default;
86741ae8e74SKuba Mracek };
86841ae8e74SKuba Mracek 
86941ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
87041ae8e74SKuba Mracek                                                 CommandReturnObject &result) {
871f80d2655SKuba Mracek #ifndef LLDB_DISABLE_PYTHON
87241ae8e74SKuba Mracek   if (m_options.m_class_name.empty()) {
87341ae8e74SKuba Mracek     result.AppendErrorWithFormat(
87441ae8e74SKuba Mracek         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
87541ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
87641ae8e74SKuba Mracek     return false;
87741ae8e74SKuba Mracek   }
87841ae8e74SKuba Mracek 
87941ae8e74SKuba Mracek   if (m_options.m_module.empty()) {
88041ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
88141ae8e74SKuba Mracek                                  m_cmd_name.c_str());
88241ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
88341ae8e74SKuba Mracek     return false;
88441ae8e74SKuba Mracek   }
88541ae8e74SKuba Mracek 
88641ae8e74SKuba Mracek   if (m_options.m_function.empty()) {
88741ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a function name (-n argument).\n",
88841ae8e74SKuba Mracek                                  m_cmd_name.c_str());
88941ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
89041ae8e74SKuba Mracek     return false;
89141ae8e74SKuba Mracek   }
89241ae8e74SKuba Mracek 
893*2b29b432SJonas Devlieghere   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
89441ae8e74SKuba Mracek 
89541ae8e74SKuba Mracek   if (interpreter &&
89641ae8e74SKuba Mracek       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
89741ae8e74SKuba Mracek     result.AppendWarning(
89841ae8e74SKuba Mracek         "The provided class does not exist - please define it "
89941ae8e74SKuba Mracek         "before attempting to use this frame recognizer");
90041ae8e74SKuba Mracek   }
90141ae8e74SKuba Mracek 
90241ae8e74SKuba Mracek   StackFrameRecognizerSP recognizer_sp =
90341ae8e74SKuba Mracek       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
90441ae8e74SKuba Mracek           interpreter, m_options.m_class_name.c_str()));
90541ae8e74SKuba Mracek   if (m_options.m_regex) {
90641ae8e74SKuba Mracek     auto module =
90741ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_module));
90841ae8e74SKuba Mracek     auto func =
90941ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_function));
91041ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
91141ae8e74SKuba Mracek   } else {
91241ae8e74SKuba Mracek     auto module = ConstString(m_options.m_module);
91341ae8e74SKuba Mracek     auto func = ConstString(m_options.m_function);
91441ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
91541ae8e74SKuba Mracek   }
916f80d2655SKuba Mracek #endif
91741ae8e74SKuba Mracek 
91841ae8e74SKuba Mracek   result.SetStatus(eReturnStatusSuccessFinishNoResult);
91941ae8e74SKuba Mracek   return result.Succeeded();
92041ae8e74SKuba Mracek }
92141ae8e74SKuba Mracek 
92241ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
92341ae8e74SKuba Mracek public:
92441ae8e74SKuba Mracek   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
92541ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer clear",
92641ae8e74SKuba Mracek                            "Delete all frame recognizers.", nullptr) {}
92741ae8e74SKuba Mracek 
92841ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerClear() override = default;
92941ae8e74SKuba Mracek 
93041ae8e74SKuba Mracek protected:
93141ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
93241ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveAllRecognizers();
93341ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
93441ae8e74SKuba Mracek     return result.Succeeded();
93541ae8e74SKuba Mracek   }
93641ae8e74SKuba Mracek };
93741ae8e74SKuba Mracek 
93841ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
93941ae8e74SKuba Mracek  public:
94041ae8e74SKuba Mracek   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
94141ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer delete",
94241ae8e74SKuba Mracek                             "Delete an existing frame recognizer.", nullptr) {}
94341ae8e74SKuba Mracek 
94441ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerDelete() override = default;
94541ae8e74SKuba Mracek 
94641ae8e74SKuba Mracek  protected:
94741ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
94841ae8e74SKuba Mracek     if (command.GetArgumentCount() == 0) {
94941ae8e74SKuba Mracek       if (!m_interpreter.Confirm(
95041ae8e74SKuba Mracek               "About to delete all frame recognizers, do you want to do that?",
95141ae8e74SKuba Mracek               true)) {
95241ae8e74SKuba Mracek         result.AppendMessage("Operation cancelled...");
95341ae8e74SKuba Mracek         result.SetStatus(eReturnStatusFailed);
95441ae8e74SKuba Mracek         return false;
95541ae8e74SKuba Mracek       }
95641ae8e74SKuba Mracek 
95741ae8e74SKuba Mracek       StackFrameRecognizerManager::RemoveAllRecognizers();
95841ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
95941ae8e74SKuba Mracek       return result.Succeeded();
96041ae8e74SKuba Mracek     }
96141ae8e74SKuba Mracek 
96241ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
96341ae8e74SKuba Mracek       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
96441ae8e74SKuba Mracek                                    m_cmd_name.c_str());
96541ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
96641ae8e74SKuba Mracek       return false;
96741ae8e74SKuba Mracek     }
96841ae8e74SKuba Mracek 
96941ae8e74SKuba Mracek     uint32_t recognizer_id =
97041ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
97141ae8e74SKuba Mracek 
97241ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
97341ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
97441ae8e74SKuba Mracek     return result.Succeeded();
97541ae8e74SKuba Mracek   }
97641ae8e74SKuba Mracek };
97741ae8e74SKuba Mracek 
97841ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed {
97941ae8e74SKuba Mracek  public:
98041ae8e74SKuba Mracek   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
98141ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer list",
98241ae8e74SKuba Mracek                             "Show a list of active frame recognizers.",
98341ae8e74SKuba Mracek                             nullptr) {}
98441ae8e74SKuba Mracek 
98541ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerList() override = default;
98641ae8e74SKuba Mracek 
98741ae8e74SKuba Mracek  protected:
98841ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
98941ae8e74SKuba Mracek     bool any_printed = false;
99041ae8e74SKuba Mracek     StackFrameRecognizerManager::ForEach(
99141ae8e74SKuba Mracek         [&result, &any_printed](uint32_t recognizer_id, std::string name,
99241ae8e74SKuba Mracek                                 std::string function, std::string symbol,
99341ae8e74SKuba Mracek                                 bool regexp) {
99441ae8e74SKuba Mracek           if (name == "") name = "(internal)";
99541ae8e74SKuba Mracek           result.GetOutputStream().Printf(
99641ae8e74SKuba Mracek               "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(),
99741ae8e74SKuba Mracek               function.c_str(), symbol.c_str(), regexp ? " (regexp)" : "");
99841ae8e74SKuba Mracek           any_printed = true;
99941ae8e74SKuba Mracek         });
100041ae8e74SKuba Mracek 
100141ae8e74SKuba Mracek     if (any_printed)
100241ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
100341ae8e74SKuba Mracek     else {
100441ae8e74SKuba Mracek       result.GetOutputStream().PutCString("no matching results found.\n");
100541ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishNoResult);
100641ae8e74SKuba Mracek     }
100741ae8e74SKuba Mracek     return result.Succeeded();
100841ae8e74SKuba Mracek   }
100941ae8e74SKuba Mracek };
101041ae8e74SKuba Mracek 
101141ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
101241ae8e74SKuba Mracek  public:
101341ae8e74SKuba Mracek   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
101441ae8e74SKuba Mracek       : CommandObjectParsed(
101541ae8e74SKuba Mracek             interpreter, "frame recognizer info",
101641ae8e74SKuba Mracek             "Show which frame recognizer is applied a stack frame (if any).",
101741ae8e74SKuba Mracek             nullptr) {
101841ae8e74SKuba Mracek     CommandArgumentEntry arg;
101941ae8e74SKuba Mracek     CommandArgumentData index_arg;
102041ae8e74SKuba Mracek 
102141ae8e74SKuba Mracek     // Define the first (and only) variant of this arg.
102241ae8e74SKuba Mracek     index_arg.arg_type = eArgTypeFrameIndex;
102341ae8e74SKuba Mracek     index_arg.arg_repetition = eArgRepeatPlain;
102441ae8e74SKuba Mracek 
102541ae8e74SKuba Mracek     // There is only one variant this argument could be; put it into the
102641ae8e74SKuba Mracek     // argument entry.
102741ae8e74SKuba Mracek     arg.push_back(index_arg);
102841ae8e74SKuba Mracek 
102941ae8e74SKuba Mracek     // Push the data for the first argument into the m_arguments vector.
103041ae8e74SKuba Mracek     m_arguments.push_back(arg);
103141ae8e74SKuba Mracek   }
103241ae8e74SKuba Mracek 
103341ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerInfo() override = default;
103441ae8e74SKuba Mracek 
103541ae8e74SKuba Mracek  protected:
103641ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
103741ae8e74SKuba Mracek     Process *process = m_exe_ctx.GetProcessPtr();
103841ae8e74SKuba Mracek     if (process == nullptr) {
103941ae8e74SKuba Mracek       result.AppendError("no process");
104041ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
104141ae8e74SKuba Mracek       return false;
104241ae8e74SKuba Mracek     }
104341ae8e74SKuba Mracek     Thread *thread = m_exe_ctx.GetThreadPtr();
104441ae8e74SKuba Mracek     if (thread == nullptr) {
104541ae8e74SKuba Mracek       result.AppendError("no thread");
104641ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
104741ae8e74SKuba Mracek       return false;
104841ae8e74SKuba Mracek     }
104941ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
105041ae8e74SKuba Mracek       result.AppendErrorWithFormat(
105141ae8e74SKuba Mracek           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
105241ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
105341ae8e74SKuba Mracek       return false;
105441ae8e74SKuba Mracek     }
105541ae8e74SKuba Mracek 
105641ae8e74SKuba Mracek     uint32_t frame_index =
105741ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
105841ae8e74SKuba Mracek     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
105941ae8e74SKuba Mracek     if (!frame_sp) {
106041ae8e74SKuba Mracek       result.AppendErrorWithFormat("no frame with index %u", frame_index);
106141ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
106241ae8e74SKuba Mracek       return false;
106341ae8e74SKuba Mracek     }
106441ae8e74SKuba Mracek 
106541ae8e74SKuba Mracek     auto recognizer =
106641ae8e74SKuba Mracek         StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
106741ae8e74SKuba Mracek 
106841ae8e74SKuba Mracek     Stream &output_stream = result.GetOutputStream();
106941ae8e74SKuba Mracek     output_stream.Printf("frame %d ", frame_index);
107041ae8e74SKuba Mracek     if (recognizer) {
107141ae8e74SKuba Mracek       output_stream << "is recognized by ";
107241ae8e74SKuba Mracek       output_stream << recognizer->GetName();
107341ae8e74SKuba Mracek     } else {
107441ae8e74SKuba Mracek       output_stream << "not recognized by any recognizer";
107541ae8e74SKuba Mracek     }
107641ae8e74SKuba Mracek     output_stream.EOL();
107741ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
107841ae8e74SKuba Mracek     return result.Succeeded();
107941ae8e74SKuba Mracek   }
108041ae8e74SKuba Mracek };
108141ae8e74SKuba Mracek 
108241ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword {
108341ae8e74SKuba Mracek  public:
108441ae8e74SKuba Mracek   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
108541ae8e74SKuba Mracek       : CommandObjectMultiword(
108641ae8e74SKuba Mracek             interpreter, "frame recognizer",
108741ae8e74SKuba Mracek             "Commands for editing and viewing frame recognizers.",
108841ae8e74SKuba Mracek             "frame recognizer [<sub-command-options>] ") {
108941ae8e74SKuba Mracek     LoadSubCommand(
109041ae8e74SKuba Mracek         "add",
109141ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter)));
109241ae8e74SKuba Mracek     LoadSubCommand(
109341ae8e74SKuba Mracek         "clear",
109441ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
109541ae8e74SKuba Mracek     LoadSubCommand(
109641ae8e74SKuba Mracek         "delete",
109741ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
109841ae8e74SKuba Mracek     LoadSubCommand(
109941ae8e74SKuba Mracek         "list",
110041ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter)));
110141ae8e74SKuba Mracek     LoadSubCommand(
110241ae8e74SKuba Mracek         "info",
110341ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerInfo(interpreter)));
110441ae8e74SKuba Mracek   }
110541ae8e74SKuba Mracek 
110641ae8e74SKuba Mracek   ~CommandObjectFrameRecognizer() override = default;
110741ae8e74SKuba Mracek };
110841ae8e74SKuba Mracek 
110930fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
111030fdc8d8SChris Lattner 
111130fdc8d8SChris Lattner // CommandObjectMultiwordFrame
111230fdc8d8SChris Lattner 
1113b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1114b9c1b51eSKate Stone     CommandInterpreter &interpreter)
1115b9c1b51eSKate Stone     : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and "
1116b9c1b51eSKate Stone                                                    "examing the current "
1117b9c1b51eSKate Stone                                                    "thread's stack frames.",
1118b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
1119b9c1b51eSKate Stone   LoadSubCommand("diagnose",
1120b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1121b9c1b51eSKate Stone   LoadSubCommand("info",
1122b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1123b9c1b51eSKate Stone   LoadSubCommand("select",
1124b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1125b9c1b51eSKate Stone   LoadSubCommand("variable",
1126b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
112741ae8e74SKuba Mracek #ifndef LLDB_DISABLE_PYTHON
112841ae8e74SKuba Mracek   LoadSubCommand(
112941ae8e74SKuba Mracek       "recognizer",
113041ae8e74SKuba Mracek       CommandObjectSP(new CommandObjectFrameRecognizer(interpreter)));
113141ae8e74SKuba Mracek #endif
113230fdc8d8SChris Lattner }
113330fdc8d8SChris Lattner 
1134c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1135