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 
45*796ac80bSJonas Devlieghere #include <memory>
46*796ac80bSJonas Devlieghere #include <string>
47*796ac80bSJonas Devlieghere 
4830fdc8d8SChris Lattner using namespace lldb;
4930fdc8d8SChris Lattner using namespace lldb_private;
5030fdc8d8SChris Lattner 
514740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose
524740a734SSean Callanan 
534740a734SSean Callanan //-------------------------------------------------------------------------
544740a734SSean Callanan // CommandObjectFrameInfo
554740a734SSean Callanan //-------------------------------------------------------------------------
564740a734SSean Callanan 
574740a734SSean Callanan //-------------------------------------------------------------------------
584740a734SSean Callanan // CommandObjectFrameDiagnose
594740a734SSean Callanan //-------------------------------------------------------------------------
604740a734SSean Callanan 
618fe53c49STatyana Krasnukha static constexpr OptionDefinition g_frame_diag_options[] = {
621f0f5b5bSZachary Turner     // clang-format off
638fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "register", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeRegisterName,    "A register to diagnose." },
648fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "address",  'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeAddress,         "An address to diagnose." },
658fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "offset",   'o', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset,          "An optional offset.  Requires --register." }
661f0f5b5bSZachary Turner     // clang-format on
671f0f5b5bSZachary Turner };
681f0f5b5bSZachary Turner 
69b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed {
704740a734SSean Callanan public:
71b9c1b51eSKate Stone   class CommandOptions : public Options {
724740a734SSean Callanan   public:
73b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
744740a734SSean Callanan 
754740a734SSean Callanan     ~CommandOptions() override = default;
764740a734SSean Callanan 
7797206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
78b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
7997206d57SZachary Turner       Status error;
804740a734SSean Callanan       const int short_option = m_getopt_table[option_idx].val;
81b9c1b51eSKate Stone       switch (short_option) {
824740a734SSean Callanan       case 'r':
834740a734SSean Callanan         reg = ConstString(option_arg);
844740a734SSean Callanan         break;
854740a734SSean Callanan 
86b9c1b51eSKate Stone       case 'a': {
87fe11483bSZachary Turner         address.emplace();
88fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *address)) {
894740a734SSean Callanan           address.reset();
90b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid address argument '%s'",
91fe11483bSZachary Turner                                          option_arg.str().c_str());
924740a734SSean Callanan         }
93b9c1b51eSKate Stone       } break;
944740a734SSean Callanan 
95b9c1b51eSKate Stone       case 'o': {
96fe11483bSZachary Turner         offset.emplace();
97fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *offset)) {
984740a734SSean Callanan           offset.reset();
99b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid offset argument '%s'",
100fe11483bSZachary Turner                                          option_arg.str().c_str());
1014740a734SSean Callanan         }
102b9c1b51eSKate Stone       } break;
1034740a734SSean Callanan 
1044740a734SSean Callanan       default:
105b9c1b51eSKate Stone         error.SetErrorStringWithFormat("invalid short option character '%c'",
106b9c1b51eSKate Stone                                        short_option);
1074740a734SSean Callanan         break;
1084740a734SSean Callanan       }
1094740a734SSean Callanan 
1104740a734SSean Callanan       return error;
1114740a734SSean Callanan     }
1124740a734SSean Callanan 
113b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
1144740a734SSean Callanan       address.reset();
1154740a734SSean Callanan       reg.reset();
1164740a734SSean Callanan       offset.reset();
1174740a734SSean Callanan     }
1184740a734SSean Callanan 
1191f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
12070602439SZachary Turner       return llvm::makeArrayRef(g_frame_diag_options);
1211f0f5b5bSZachary Turner     }
1224740a734SSean Callanan 
1234740a734SSean Callanan     // Options.
1244740a734SSean Callanan     llvm::Optional<lldb::addr_t> address;
1254740a734SSean Callanan     llvm::Optional<ConstString> reg;
1264740a734SSean Callanan     llvm::Optional<int64_t> offset;
1274740a734SSean Callanan   };
1284740a734SSean Callanan 
1294740a734SSean Callanan   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
1304740a734SSean Callanan       : CommandObjectParsed(interpreter, "frame diagnose",
131b9c1b51eSKate Stone                             "Try to determine what path path the current stop "
132b9c1b51eSKate Stone                             "location used to get to a register or address",
133b9c1b51eSKate Stone                             nullptr,
134b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
135b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched |
1364740a734SSean Callanan                                 eCommandProcessMustBePaused),
137b9c1b51eSKate Stone         m_options() {
1384740a734SSean Callanan     CommandArgumentEntry arg;
1394740a734SSean Callanan     CommandArgumentData index_arg;
1404740a734SSean Callanan 
1414740a734SSean Callanan     // Define the first (and only) variant of this arg.
1424740a734SSean Callanan     index_arg.arg_type = eArgTypeFrameIndex;
1434740a734SSean Callanan     index_arg.arg_repetition = eArgRepeatOptional;
1444740a734SSean Callanan 
145b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
146b9c1b51eSKate Stone     // argument entry.
1474740a734SSean Callanan     arg.push_back(index_arg);
1484740a734SSean Callanan 
1494740a734SSean Callanan     // Push the data for the first argument into the m_arguments vector.
1504740a734SSean Callanan     m_arguments.push_back(arg);
1514740a734SSean Callanan   }
1524740a734SSean Callanan 
1534740a734SSean Callanan   ~CommandObjectFrameDiagnose() override = default;
1544740a734SSean Callanan 
155b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
1564740a734SSean Callanan 
1574740a734SSean Callanan protected:
158b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1594740a734SSean Callanan     Thread *thread = m_exe_ctx.GetThreadPtr();
1604740a734SSean Callanan     StackFrameSP frame_sp = thread->GetSelectedFrame();
1614740a734SSean Callanan 
1624740a734SSean Callanan     ValueObjectSP valobj_sp;
1634740a734SSean Callanan 
164b9c1b51eSKate Stone     if (m_options.address.hasValue()) {
165b9c1b51eSKate Stone       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
166b9c1b51eSKate Stone         result.AppendError(
167b9c1b51eSKate Stone             "`frame diagnose --address` is incompatible with other arguments.");
1684740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1694740a734SSean Callanan         return false;
1704740a734SSean Callanan       }
1714740a734SSean Callanan       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
172b9c1b51eSKate Stone     } else if (m_options.reg.hasValue()) {
173b9c1b51eSKate Stone       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
174b9c1b51eSKate Stone           m_options.reg.getValue(), m_options.offset.getValueOr(0));
175b9c1b51eSKate Stone     } else {
1764740a734SSean Callanan       StopInfoSP stop_info_sp = thread->GetStopInfo();
177b9c1b51eSKate Stone       if (!stop_info_sp) {
1784740a734SSean Callanan         result.AppendError("No arguments provided, and no stop info.");
1794740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1804740a734SSean Callanan         return false;
1814740a734SSean Callanan       }
1824740a734SSean Callanan 
1834740a734SSean Callanan       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
1844740a734SSean Callanan     }
1854740a734SSean Callanan 
186b9c1b51eSKate Stone     if (!valobj_sp) {
1874740a734SSean Callanan       result.AppendError("No diagnosis available.");
1884740a734SSean Callanan       result.SetStatus(eReturnStatusFailed);
1894740a734SSean Callanan       return false;
1904740a734SSean Callanan     }
1914740a734SSean Callanan 
1924740a734SSean Callanan 
1933bc714b2SZachary Turner     DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp](
1943bc714b2SZachary Turner         ConstString type, ConstString var, const DumpValueObjectOptions &opts,
1953bc714b2SZachary Turner         Stream &stream) -> bool {
196b9c1b51eSKate Stone       const ValueObject::GetExpressionPathFormat format = ValueObject::
197b9c1b51eSKate Stone           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
1985d1f711aSPavel Labath       const bool qualify_cxx_base_classes = false;
1994740a734SSean Callanan       valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
2004740a734SSean Callanan       stream.PutCString(" =");
2014740a734SSean Callanan       return true;
2024740a734SSean Callanan     };
2034740a734SSean Callanan 
2044740a734SSean Callanan     DumpValueObjectOptions options;
2054740a734SSean Callanan     options.SetDeclPrintingHelper(helper);
206b9c1b51eSKate Stone     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
207b9c1b51eSKate Stone                                options);
2084740a734SSean Callanan     printer.PrintValueObject();
2094740a734SSean Callanan 
2104740a734SSean Callanan     return true;
2114740a734SSean Callanan   }
2124740a734SSean Callanan 
2134740a734SSean Callanan protected:
2144740a734SSean Callanan   CommandOptions m_options;
2154740a734SSean Callanan };
2164740a734SSean Callanan 
21730fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo
21830fdc8d8SChris Lattner 
21930fdc8d8SChris Lattner //-------------------------------------------------------------------------
22030fdc8d8SChris Lattner // CommandObjectFrameInfo
22130fdc8d8SChris Lattner //-------------------------------------------------------------------------
22230fdc8d8SChris Lattner 
223b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed {
22430fdc8d8SChris Lattner public:
2257428a18cSKate Stone   CommandObjectFrameInfo(CommandInterpreter &interpreter)
226b9c1b51eSKate Stone       : CommandObjectParsed(
227b9c1b51eSKate Stone             interpreter, "frame info", "List information about the current "
228b9c1b51eSKate Stone                                        "stack frame in the current thread.",
229b9c1b51eSKate Stone             "frame info",
230b9c1b51eSKate Stone             eCommandRequiresFrame | eCommandTryTargetAPILock |
231b9c1b51eSKate Stone                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
23230fdc8d8SChris Lattner 
233c8ecc2a9SEugene Zelenko   ~CommandObjectFrameInfo() override = default;
23430fdc8d8SChris Lattner 
2355a988416SJim Ingham protected:
236b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
237f9fc609fSGreg Clayton     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
23830fdc8d8SChris Lattner     result.SetStatus(eReturnStatusSuccessFinishResult);
23930fdc8d8SChris Lattner     return result.Succeeded();
24030fdc8d8SChris Lattner   }
24130fdc8d8SChris Lattner };
24230fdc8d8SChris Lattner 
24330fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect
24430fdc8d8SChris Lattner 
24530fdc8d8SChris Lattner //-------------------------------------------------------------------------
24630fdc8d8SChris Lattner // CommandObjectFrameSelect
24730fdc8d8SChris Lattner //-------------------------------------------------------------------------
24830fdc8d8SChris Lattner 
2491f0f5b5bSZachary Turner static OptionDefinition g_frame_select_options[] = {
2501f0f5b5bSZachary Turner     // clang-format off
2518fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOffset, "A relative frame index offset from the current frame index." },
2521f0f5b5bSZachary Turner     // clang-format on
2531f0f5b5bSZachary Turner };
2541f0f5b5bSZachary Turner 
255b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed {
25630fdc8d8SChris Lattner public:
257b9c1b51eSKate Stone   class CommandOptions : public Options {
258864174e1SGreg Clayton   public:
259b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
260864174e1SGreg Clayton 
261c8ecc2a9SEugene Zelenko     ~CommandOptions() override = default;
262864174e1SGreg Clayton 
26397206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
264b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
26597206d57SZachary Turner       Status error;
2663bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
267b9c1b51eSKate Stone       switch (short_option) {
268864174e1SGreg Clayton       case 'r':
269fe11483bSZachary Turner         if (option_arg.getAsInteger(0, relative_frame_offset)) {
270fe11483bSZachary Turner           relative_frame_offset = INT32_MIN;
271b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
272fe11483bSZachary Turner                                          option_arg.str().c_str());
273fe11483bSZachary Turner         }
274864174e1SGreg Clayton         break;
275864174e1SGreg Clayton 
276864174e1SGreg Clayton       default:
277b9c1b51eSKate Stone         error.SetErrorStringWithFormat("invalid short option character '%c'",
278b9c1b51eSKate Stone                                        short_option);
279864174e1SGreg Clayton         break;
280864174e1SGreg Clayton       }
281864174e1SGreg Clayton 
282864174e1SGreg Clayton       return error;
283864174e1SGreg Clayton     }
284864174e1SGreg Clayton 
285b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
286864174e1SGreg Clayton       relative_frame_offset = INT32_MIN;
287864174e1SGreg Clayton     }
288864174e1SGreg Clayton 
2891f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
29070602439SZachary Turner       return llvm::makeArrayRef(g_frame_select_options);
2911f0f5b5bSZachary Turner     }
292864174e1SGreg Clayton 
293864174e1SGreg Clayton     int32_t relative_frame_offset;
294864174e1SGreg Clayton   };
295864174e1SGreg Clayton 
2967428a18cSKate Stone   CommandObjectFrameSelect(CommandInterpreter &interpreter)
2977428a18cSKate Stone       : CommandObjectParsed(
298b9c1b51eSKate Stone             interpreter, "frame select", "Select the current stack frame by "
299b9c1b51eSKate Stone                                          "index from within the current thread "
300b9c1b51eSKate Stone                                          "(see 'thread backtrace'.)",
301b9c1b51eSKate Stone             nullptr,
302b9c1b51eSKate Stone             eCommandRequiresThread | eCommandTryTargetAPILock |
303b9c1b51eSKate Stone                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
304b9c1b51eSKate Stone         m_options() {
305405fe67fSCaroline Tice     CommandArgumentEntry arg;
306405fe67fSCaroline Tice     CommandArgumentData index_arg;
307405fe67fSCaroline Tice 
308405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
309405fe67fSCaroline Tice     index_arg.arg_type = eArgTypeFrameIndex;
310864174e1SGreg Clayton     index_arg.arg_repetition = eArgRepeatOptional;
311405fe67fSCaroline Tice 
312b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
313b9c1b51eSKate Stone     // argument entry.
314405fe67fSCaroline Tice     arg.push_back(index_arg);
315405fe67fSCaroline Tice 
316405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
317405fe67fSCaroline Tice     m_arguments.push_back(arg);
31830fdc8d8SChris Lattner   }
31930fdc8d8SChris Lattner 
320c8ecc2a9SEugene Zelenko   ~CommandObjectFrameSelect() override = default;
32130fdc8d8SChris Lattner 
322b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
323864174e1SGreg Clayton 
3245a988416SJim Ingham protected:
325b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
326b9c1b51eSKate Stone     // No need to check "thread" for validity as eCommandRequiresThread ensures
327b9c1b51eSKate Stone     // it is valid
328f9fc609fSGreg Clayton     Thread *thread = m_exe_ctx.GetThreadPtr();
329f9fc609fSGreg Clayton 
330864174e1SGreg Clayton     uint32_t frame_idx = UINT32_MAX;
331b9c1b51eSKate Stone     if (m_options.relative_frame_offset != INT32_MIN) {
332864174e1SGreg Clayton       // The one and only argument is a signed relative frame index
333c14ee32dSGreg Clayton       frame_idx = thread->GetSelectedFrameIndex();
334864174e1SGreg Clayton       if (frame_idx == UINT32_MAX)
335864174e1SGreg Clayton         frame_idx = 0;
336864174e1SGreg Clayton 
337b9c1b51eSKate Stone       if (m_options.relative_frame_offset < 0) {
3383985c8c6SSaleem Abdulrasool         if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset)
339864174e1SGreg Clayton           frame_idx += m_options.relative_frame_offset;
340b9c1b51eSKate Stone         else {
341b9c1b51eSKate Stone           if (frame_idx == 0) {
34205097246SAdrian Prantl             // If you are already at the bottom of the stack, then just warn
34305097246SAdrian Prantl             // and don't reset the frame.
3447428a18cSKate Stone             result.AppendError("Already at the bottom of the stack.");
345213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
346213b4546SJim Ingham             return false;
347b9c1b51eSKate Stone           } else
348864174e1SGreg Clayton             frame_idx = 0;
349864174e1SGreg Clayton         }
350b9c1b51eSKate Stone       } else if (m_options.relative_frame_offset > 0) {
351b9c1b51eSKate Stone         // I don't want "up 20" where "20" takes you past the top of the stack
352b9c1b51eSKate Stone         // to produce
353b9c1b51eSKate Stone         // an error, but rather to just go to the top.  So I have to count the
354b9c1b51eSKate Stone         // stack here...
355b0c72a5fSJim Ingham         const uint32_t num_frames = thread->GetStackFrameCount();
356b9c1b51eSKate Stone         if (static_cast<int32_t>(num_frames - frame_idx) >
357b9c1b51eSKate Stone             m_options.relative_frame_offset)
358864174e1SGreg Clayton           frame_idx += m_options.relative_frame_offset;
359b9c1b51eSKate Stone         else {
360b9c1b51eSKate Stone           if (frame_idx == num_frames - 1) {
361b9c1b51eSKate Stone             // If we are already at the top of the stack, just warn and don't
362b9c1b51eSKate Stone             // reset the frame.
3637428a18cSKate Stone             result.AppendError("Already at the top of the stack.");
364213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
365213b4546SJim Ingham             return false;
366b9c1b51eSKate Stone           } else
367864174e1SGreg Clayton             frame_idx = num_frames - 1;
368864174e1SGreg Clayton         }
369864174e1SGreg Clayton       }
370b9c1b51eSKate Stone     } else {
371f965cc86SZachary Turner       if (command.GetArgumentCount() > 1) {
372f965cc86SZachary Turner         result.AppendErrorWithFormat(
373f965cc86SZachary Turner             "too many arguments; expected frame-index, saw '%s'.\n",
374867e7d17SZachary Turner             command[0].c_str());
375f965cc86SZachary Turner         m_options.GenerateOptionUsage(
376f965cc86SZachary Turner             result.GetErrorStream(), this,
377f965cc86SZachary Turner             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
378f965cc86SZachary Turner         return false;
379f965cc86SZachary Turner       }
380f965cc86SZachary Turner 
381b9c1b51eSKate Stone       if (command.GetArgumentCount() == 1) {
382f965cc86SZachary Turner         if (command[0].ref.getAsInteger(0, frame_idx)) {
383b9c1b51eSKate Stone           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
384f965cc86SZachary Turner                                        command[0].c_str());
385afbb0af8SJim Ingham           result.SetStatus(eReturnStatusFailed);
386afbb0af8SJim Ingham           return false;
387afbb0af8SJim Ingham         }
388b9c1b51eSKate Stone       } else if (command.GetArgumentCount() == 0) {
38982d4a2b9SJason Molenda         frame_idx = thread->GetSelectedFrameIndex();
390b9c1b51eSKate Stone         if (frame_idx == UINT32_MAX) {
39182d4a2b9SJason Molenda           frame_idx = 0;
39282d4a2b9SJason Molenda         }
393864174e1SGreg Clayton       }
394864174e1SGreg Clayton     }
39530fdc8d8SChris Lattner 
396b9c1b51eSKate Stone     bool success = thread->SetSelectedFrameByIndexNoisily(
397b9c1b51eSKate Stone         frame_idx, result.GetOutputStream());
398b9c1b51eSKate Stone     if (success) {
399f9fc609fSGreg Clayton       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
40030fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
401b9c1b51eSKate Stone     } else {
402b9c1b51eSKate Stone       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
403b9c1b51eSKate Stone                                    frame_idx);
40430fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
40593208b86SJim Ingham     }
40693208b86SJim Ingham 
40793208b86SJim Ingham     return result.Succeeded();
40830fdc8d8SChris Lattner   }
409864174e1SGreg Clayton 
410c8ecc2a9SEugene Zelenko protected:
411864174e1SGreg Clayton   CommandOptions m_options;
412864174e1SGreg Clayton };
413864174e1SGreg Clayton 
4146d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable
4156d56d2ceSJim Ingham //----------------------------------------------------------------------
4166d56d2ceSJim Ingham // List images with associated information
4176d56d2ceSJim Ingham //----------------------------------------------------------------------
418b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed {
4196d56d2ceSJim Ingham public:
4207428a18cSKate Stone   CommandObjectFrameVariable(CommandInterpreter &interpreter)
4217428a18cSKate Stone       : CommandObjectParsed(
422b9c1b51eSKate Stone             interpreter, "frame variable",
423b9c1b51eSKate Stone             "Show variables for the current stack frame. Defaults to all "
4247428a18cSKate Stone             "arguments and local variables in scope. Names of argument, "
4257428a18cSKate Stone             "local, file static and file global variables can be specified. "
426ed8a705cSGreg Clayton             "Children of aggregate variables can be specified such as "
427285ae0c0SJim Ingham             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
428285ae0c0SJim Ingham             "not invoke operator overloads if they exist, but directly access "
429285ae0c0SJim Ingham             "the specified element.  If you want to trigger operator overloads "
430285ae0c0SJim Ingham             "use the expression command to print the variable instead."
431285ae0c0SJim Ingham             "\nIt is worth noting that except for overloaded "
432285ae0c0SJim Ingham             "operators, when printing local variables 'expr local_var' and "
433285ae0c0SJim Ingham             "'frame var local_var' produce the same "
434285ae0c0SJim Ingham             "results.  However, 'frame variable' is more efficient, since it "
435285ae0c0SJim Ingham             "uses debug information and memory reads directly, rather than "
436285ae0c0SJim Ingham             "parsing and evaluating an expression, which may even involve "
437285ae0c0SJim Ingham             "JITing and running code in the target program.",
438b9c1b51eSKate Stone             nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock |
439b9c1b51eSKate Stone                          eCommandProcessMustBeLaunched |
4407428a18cSKate Stone                          eCommandProcessMustBePaused | eCommandRequiresProcess),
441e1cfbc79STodd Fiala         m_option_group(),
442b9c1b51eSKate Stone         m_option_variable(
443b9c1b51eSKate Stone             true), // Include the frame specific options by passing "true"
4441deb7962SGreg Clayton         m_option_format(eFormatDefault),
445b9c1b51eSKate Stone         m_varobj_options() {
446405fe67fSCaroline Tice     CommandArgumentEntry arg;
447405fe67fSCaroline Tice     CommandArgumentData var_name_arg;
448405fe67fSCaroline Tice 
449405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
450405fe67fSCaroline Tice     var_name_arg.arg_type = eArgTypeVarName;
451405fe67fSCaroline Tice     var_name_arg.arg_repetition = eArgRepeatStar;
452405fe67fSCaroline Tice 
453b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
454b9c1b51eSKate Stone     // argument entry.
455405fe67fSCaroline Tice     arg.push_back(var_name_arg);
456405fe67fSCaroline Tice 
457405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
458405fe67fSCaroline Tice     m_arguments.push_back(arg);
4592837b766SJim Ingham 
460715c2365SGreg Clayton     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
461b9c1b51eSKate Stone     m_option_group.Append(&m_option_format,
462b9c1b51eSKate Stone                           OptionGroupFormat::OPTION_GROUP_FORMAT |
463b9c1b51eSKate Stone                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
464b9c1b51eSKate Stone                           LLDB_OPT_SET_1);
4652837b766SJim Ingham     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
4662837b766SJim Ingham     m_option_group.Finalize();
4676d56d2ceSJim Ingham   }
4686d56d2ceSJim Ingham 
469c8ecc2a9SEugene Zelenko   ~CommandObjectFrameVariable() override = default;
4706d56d2ceSJim Ingham 
471b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
472f21feadcSGreg Clayton 
4732443bbd4SRaphael Isemann   int HandleArgumentCompletion(
4742443bbd4SRaphael Isemann       CompletionRequest &request,
4752443bbd4SRaphael Isemann       OptionElementVector &opt_element_vector) override {
476f21feadcSGreg Clayton     // Arguments are the standard source file completer.
477b9c1b51eSKate Stone     CommandCompletions::InvokeCommonCompletionCallbacks(
478b9c1b51eSKate Stone         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
479a2e76c0bSRaphael Isemann         request, nullptr);
4801a6d7ab5SRaphael Isemann     return request.GetNumberOfMatches();
481f21feadcSGreg Clayton   }
4826d56d2ceSJim Ingham 
4835a988416SJim Ingham protected:
48473418dfeSEnrico Granata   llvm::StringRef GetScopeString(VariableSP var_sp) {
48573418dfeSEnrico Granata     if (!var_sp)
48673418dfeSEnrico Granata       return llvm::StringRef::withNullAsEmpty(nullptr);
48773418dfeSEnrico Granata 
48873418dfeSEnrico Granata     switch (var_sp->GetScope()) {
48973418dfeSEnrico Granata     case eValueTypeVariableGlobal:
49073418dfeSEnrico Granata       return "GLOBAL: ";
49173418dfeSEnrico Granata     case eValueTypeVariableStatic:
49273418dfeSEnrico Granata       return "STATIC: ";
49373418dfeSEnrico Granata     case eValueTypeVariableArgument:
49473418dfeSEnrico Granata       return "ARG: ";
49573418dfeSEnrico Granata     case eValueTypeVariableLocal:
49673418dfeSEnrico Granata       return "LOCAL: ";
49773418dfeSEnrico Granata     case eValueTypeVariableThreadLocal:
49873418dfeSEnrico Granata       return "THREAD: ";
49973418dfeSEnrico Granata     default:
50073418dfeSEnrico Granata       break;
50173418dfeSEnrico Granata     }
50273418dfeSEnrico Granata 
50373418dfeSEnrico Granata     return llvm::StringRef::withNullAsEmpty(nullptr);
50473418dfeSEnrico Granata   }
50573418dfeSEnrico Granata 
506b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
50705097246SAdrian Prantl     // No need to check "frame" for validity as eCommandRequiresFrame ensures
50805097246SAdrian Prantl     // it is valid
509b57e4a1bSJason Molenda     StackFrame *frame = m_exe_ctx.GetFramePtr();
5101e49e5e7SJohnny Chen 
511a134cc1bSGreg Clayton     Stream &s = result.GetOutputStream();
5126d56d2ceSJim Ingham 
513b9c1b51eSKate Stone     // Be careful about the stack frame, if any summary formatter runs code, it
51405097246SAdrian Prantl     // might clear the StackFrameList for the thread.  So hold onto a shared
51505097246SAdrian Prantl     // pointer to the frame so it stays alive.
516650543f9SJim Ingham 
517b9c1b51eSKate Stone     VariableList *variable_list =
518b9c1b51eSKate Stone         frame->GetVariableList(m_option_variable.show_globals);
519a134cc1bSGreg Clayton 
5206d56d2ceSJim Ingham     VariableSP var_sp;
5216d56d2ceSJim Ingham     ValueObjectSP valobj_sp;
52278a685aaSJim Ingham 
523061858ceSEnrico Granata     TypeSummaryImplSP summary_format_sp;
52417b11749SEnrico Granata     if (!m_option_variable.summary.IsCurrentValueEmpty())
525b9c1b51eSKate Stone       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
526b9c1b51eSKate Stone           ConstString(m_option_variable.summary.GetCurrentValue()),
527b9c1b51eSKate Stone           summary_format_sp);
52817b11749SEnrico Granata     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
529*796ac80bSJonas Devlieghere       summary_format_sp = std::make_shared<StringSummaryFormat>(
530b9c1b51eSKate Stone           TypeSummaryImpl::Flags(),
531*796ac80bSJonas Devlieghere           m_option_variable.summary_string.GetCurrentValue());
532f9fa6ee5SEnrico Granata 
533b9c1b51eSKate Stone     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
534b9c1b51eSKate Stone         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
535b9c1b51eSKate Stone         summary_format_sp));
536379447a7SEnrico Granata 
537b9c1b51eSKate Stone     const SymbolContext &sym_ctx =
538b9c1b51eSKate Stone         frame->GetSymbolContext(eSymbolContextFunction);
5396754e04fSEnrico Granata     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
5406754e04fSEnrico Granata       m_option_variable.show_globals = true;
5416754e04fSEnrico Granata 
542b9c1b51eSKate Stone     if (variable_list) {
5431deb7962SGreg Clayton       const Format format = m_option_format.GetFormat();
5440c489f58SEnrico Granata       options.SetFormat(format);
5451deb7962SGreg Clayton 
54611eb9c64SZachary Turner       if (!command.empty()) {
54746747022SGreg Clayton         VariableList regex_var_list;
54846747022SGreg Clayton 
54905097246SAdrian Prantl         // If we have any args to the variable command, we will make variable
55005097246SAdrian Prantl         // objects from them...
551f965cc86SZachary Turner         for (auto &entry : command) {
552b9c1b51eSKate Stone           if (m_option_variable.use_regex) {
553c7bece56SGreg Clayton             const size_t regex_start_index = regex_var_list.GetSize();
554f965cc86SZachary Turner             llvm::StringRef name_str = entry.ref;
55595eae423SZachary Turner             RegularExpression regex(name_str);
55695eae423SZachary Turner             if (regex.Compile(name_str)) {
55746747022SGreg Clayton               size_t num_matches = 0;
558b9c1b51eSKate Stone               const size_t num_new_regex_vars =
559b9c1b51eSKate Stone                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
56078a685aaSJim Ingham                                                          num_matches);
561b9c1b51eSKate Stone               if (num_new_regex_vars > 0) {
562b9c1b51eSKate Stone                 for (size_t regex_idx = regex_start_index,
563b9c1b51eSKate Stone                             end_index = regex_var_list.GetSize();
564b9c1b51eSKate Stone                      regex_idx < end_index; ++regex_idx) {
56546747022SGreg Clayton                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
566b9c1b51eSKate Stone                   if (var_sp) {
567b9c1b51eSKate Stone                     valobj_sp = frame->GetValueObjectForFrameVariable(
568b9c1b51eSKate Stone                         var_sp, m_varobj_options.use_dynamic);
569b9c1b51eSKate Stone                     if (valobj_sp) {
57073418dfeSEnrico Granata                       std::string scope_string;
57173418dfeSEnrico Granata                       if (m_option_variable.show_scope)
57273418dfeSEnrico Granata                         scope_string = GetScopeString(var_sp).str();
57373418dfeSEnrico Granata 
57473418dfeSEnrico Granata                       if (!scope_string.empty())
575771ef6d4SMalcolm Parsons                         s.PutCString(scope_string);
57673418dfeSEnrico Granata 
577b9c1b51eSKate Stone                       if (m_option_variable.show_decl &&
578b9c1b51eSKate Stone                           var_sp->GetDeclaration().GetFile()) {
57945ba8543SGreg Clayton                         bool show_fullpaths = false;
58045ba8543SGreg Clayton                         bool show_module = true;
581b9c1b51eSKate Stone                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
582b9c1b51eSKate Stone                                                     show_module))
58346747022SGreg Clayton                           s.PutCString(": ");
58446747022SGreg Clayton                       }
5854d93b8cdSEnrico Granata                       valobj_sp->Dump(result.GetOutputStream(), options);
58646747022SGreg Clayton                     }
58746747022SGreg Clayton                   }
58846747022SGreg Clayton                 }
589b9c1b51eSKate Stone               } else if (num_matches == 0) {
590b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: no variables matched "
591b9c1b51eSKate Stone                                                "the regular expression '%s'.\n",
592f965cc86SZachary Turner                                                entry.c_str());
59346747022SGreg Clayton               }
594b9c1b51eSKate Stone             } else {
59546747022SGreg Clayton               char regex_error[1024];
59646747022SGreg Clayton               if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
59746747022SGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", regex_error);
59846747022SGreg Clayton               else
599b9c1b51eSKate Stone                 result.GetErrorStream().Printf(
600b9c1b51eSKate Stone                     "error: unknown regex error when compiling '%s'\n",
601f965cc86SZachary Turner                     entry.c_str());
60246747022SGreg Clayton             }
603b9c1b51eSKate Stone           } else // No regex, either exact variable names or variable
604b9c1b51eSKate Stone                  // expressions.
60546747022SGreg Clayton           {
60697206d57SZachary Turner             Status error;
607b9c1b51eSKate Stone             uint32_t expr_path_options =
608b9c1b51eSKate Stone                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
60946252398SEnrico Granata                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
61046252398SEnrico Granata                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
6112837b766SJim Ingham             lldb::VariableSP var_sp;
612b9c1b51eSKate Stone             valobj_sp = frame->GetValueForVariableExpressionPath(
613f965cc86SZachary Turner                 entry.ref, m_varobj_options.use_dynamic, expr_path_options,
614b9c1b51eSKate Stone                 var_sp, error);
615b9c1b51eSKate Stone             if (valobj_sp) {
61673418dfeSEnrico Granata               std::string scope_string;
61773418dfeSEnrico Granata               if (m_option_variable.show_scope)
61873418dfeSEnrico Granata                 scope_string = GetScopeString(var_sp).str();
61973418dfeSEnrico Granata 
62073418dfeSEnrico Granata               if (!scope_string.empty())
621771ef6d4SMalcolm Parsons                 s.PutCString(scope_string);
622b9c1b51eSKate Stone               if (m_option_variable.show_decl && var_sp &&
623b9c1b51eSKate Stone                   var_sp->GetDeclaration().GetFile()) {
624a134cc1bSGreg Clayton                 var_sp->GetDeclaration().DumpStopContext(&s, false);
625a134cc1bSGreg Clayton                 s.PutCString(": ");
626a134cc1bSGreg Clayton               }
6270c489f58SEnrico Granata 
6280c489f58SEnrico Granata               options.SetFormat(format);
629b9c1b51eSKate Stone               options.SetVariableFormatDisplayLanguage(
630b9c1b51eSKate Stone                   valobj_sp->GetPreferredDisplayLanguage());
631887062aeSJohnny Chen 
632887062aeSJohnny Chen               Stream &output_stream = result.GetOutputStream();
633f965cc86SZachary Turner               options.SetRootValueObjectName(
634f965cc86SZachary Turner                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
6354d93b8cdSEnrico Granata               valobj_sp->Dump(output_stream, options);
636b9c1b51eSKate Stone             } else {
637c8ecc2a9SEugene Zelenko               const char *error_cstr = error.AsCString(nullptr);
63854979cddSGreg Clayton               if (error_cstr)
63954979cddSGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
64054979cddSGreg Clayton               else
641b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: unable to find any "
642b9c1b51eSKate Stone                                                "variable expression path that "
643b9c1b51eSKate Stone                                                "matches '%s'.\n",
644f965cc86SZachary Turner                                                entry.c_str());
6456d56d2ceSJim Ingham             }
6466d56d2ceSJim Ingham           }
6476d56d2ceSJim Ingham         }
648b9c1b51eSKate Stone       } else // No command arg specified.  Use variable_list, instead.
6496d56d2ceSJim Ingham       {
650c7bece56SGreg Clayton         const size_t num_variables = variable_list->GetSize();
651b9c1b51eSKate Stone         if (num_variables > 0) {
652b9c1b51eSKate Stone           for (size_t i = 0; i < num_variables; i++) {
6531a65ae11SGreg Clayton             var_sp = variable_list->GetVariableAtIndex(i);
654f955efc0SSylvestre Ledru             switch (var_sp->GetScope()) {
655eb236735SJim Ingham             case eValueTypeVariableGlobal:
656eb236735SJim Ingham               if (!m_option_variable.show_globals)
657eb236735SJim Ingham                 continue;
658eb236735SJim Ingham               break;
659eb236735SJim Ingham             case eValueTypeVariableStatic:
660eb236735SJim Ingham               if (!m_option_variable.show_globals)
661eb236735SJim Ingham                 continue;
662eb236735SJim Ingham               break;
663eb236735SJim Ingham             case eValueTypeVariableArgument:
664eb236735SJim Ingham               if (!m_option_variable.show_args)
665eb236735SJim Ingham                 continue;
666eb236735SJim Ingham               break;
667eb236735SJim Ingham             case eValueTypeVariableLocal:
668eb236735SJim Ingham               if (!m_option_variable.show_locals)
669eb236735SJim Ingham                 continue;
670eb236735SJim Ingham               break;
671eb236735SJim Ingham             default:
672eb236735SJim Ingham               continue;
673eb236735SJim Ingham               break;
674eb236735SJim Ingham             }
675560558ebSEnrico Granata             std::string scope_string;
676eb236735SJim Ingham             if (m_option_variable.show_scope)
67773418dfeSEnrico Granata               scope_string = GetScopeString(var_sp).str();
6786d56d2ceSJim Ingham 
67905097246SAdrian Prantl             // Use the variable object code to make sure we are using the same
68005097246SAdrian Prantl             // APIs as the public API will be using...
681b9c1b51eSKate Stone             valobj_sp = frame->GetValueObjectForFrameVariable(
682b9c1b51eSKate Stone                 var_sp, m_varobj_options.use_dynamic);
683b9c1b51eSKate Stone             if (valobj_sp) {
68405097246SAdrian Prantl               // When dumping all variables, don't print any variables that are
68505097246SAdrian Prantl               // not in scope to avoid extra unneeded output
686b9c1b51eSKate Stone               if (valobj_sp->IsInScope()) {
687b9c1b51eSKate Stone                 if (!valobj_sp->GetTargetSP()
688b9c1b51eSKate Stone                          ->GetDisplayRuntimeSupportValues() &&
689c8ecc2a9SEugene Zelenko                     valobj_sp->IsRuntimeSupportValue())
690560558ebSEnrico Granata                   continue;
691560558ebSEnrico Granata 
692560558ebSEnrico Granata                 if (!scope_string.empty())
693771ef6d4SMalcolm Parsons                   s.PutCString(scope_string);
694560558ebSEnrico Granata 
695b9c1b51eSKate Stone                 if (m_option_variable.show_decl &&
696b9c1b51eSKate Stone                     var_sp->GetDeclaration().GetFile()) {
697a134cc1bSGreg Clayton                   var_sp->GetDeclaration().DumpStopContext(&s, false);
698a134cc1bSGreg Clayton                   s.PutCString(": ");
699a134cc1bSGreg Clayton                 }
7000c489f58SEnrico Granata 
7010c489f58SEnrico Granata                 options.SetFormat(format);
702b9c1b51eSKate Stone                 options.SetVariableFormatDisplayLanguage(
703b9c1b51eSKate Stone                     valobj_sp->GetPreferredDisplayLanguage());
704f965cc86SZachary Turner                 options.SetRootValueObjectName(
705f965cc86SZachary Turner                     var_sp ? var_sp->GetName().AsCString() : nullptr);
7064d93b8cdSEnrico Granata                 valobj_sp->Dump(result.GetOutputStream(), options);
707a134cc1bSGreg Clayton               }
708a134cc1bSGreg Clayton             }
7096d56d2ceSJim Ingham           }
7106d56d2ceSJim Ingham         }
7116d56d2ceSJim Ingham       }
7126d56d2ceSJim Ingham       result.SetStatus(eReturnStatusSuccessFinishResult);
7136d56d2ceSJim Ingham     }
71461a80ba6SEnrico Granata 
71541ae8e74SKuba Mracek     if (m_option_variable.show_recognized_args) {
71641ae8e74SKuba Mracek       auto recognized_frame = frame->GetRecognizedFrame();
71741ae8e74SKuba Mracek       if (recognized_frame) {
71841ae8e74SKuba Mracek         ValueObjectListSP recognized_arg_list =
71941ae8e74SKuba Mracek             recognized_frame->GetRecognizedArguments();
72041ae8e74SKuba Mracek         if (recognized_arg_list) {
72141ae8e74SKuba Mracek           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
72241ae8e74SKuba Mracek             options.SetFormat(m_option_format.GetFormat());
72341ae8e74SKuba Mracek             options.SetVariableFormatDisplayLanguage(
72441ae8e74SKuba Mracek                 rec_value_sp->GetPreferredDisplayLanguage());
72541ae8e74SKuba Mracek             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
72641ae8e74SKuba Mracek             rec_value_sp->Dump(result.GetOutputStream(), options);
72741ae8e74SKuba Mracek           }
72841ae8e74SKuba Mracek         }
72941ae8e74SKuba Mracek       }
73041ae8e74SKuba Mracek     }
73141ae8e74SKuba Mracek 
732b9c1b51eSKate Stone     if (m_interpreter.TruncationWarningNecessary()) {
73361a80ba6SEnrico Granata       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
73461a80ba6SEnrico Granata                                       m_cmd_name.c_str());
73561a80ba6SEnrico Granata       m_interpreter.TruncationWarningGiven();
73661a80ba6SEnrico Granata     }
73761a80ba6SEnrico Granata 
73824fff242SDavide Italiano     // Increment statistics.
73924fff242SDavide Italiano     bool res = result.Succeeded();
7400df817aaSDavide Italiano     Target *target = GetSelectedOrDummyTarget();
74124fff242SDavide Italiano     if (res)
74224fff242SDavide Italiano       target->IncrementStats(StatisticKind::FrameVarSuccess);
74324fff242SDavide Italiano     else
74424fff242SDavide Italiano       target->IncrementStats(StatisticKind::FrameVarFailure);
74524fff242SDavide Italiano     return res;
7466d56d2ceSJim Ingham   }
7476d56d2ceSJim Ingham 
748c8ecc2a9SEugene Zelenko protected:
7492837b766SJim Ingham   OptionGroupOptions m_option_group;
750715c2365SGreg Clayton   OptionGroupVariable m_option_variable;
7511deb7962SGreg Clayton   OptionGroupFormat m_option_format;
7522837b766SJim Ingham   OptionGroupValueObjectDisplay m_varobj_options;
7536d56d2ceSJim Ingham };
7546d56d2ceSJim Ingham 
75541ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer
75641ae8e74SKuba Mracek 
75741ae8e74SKuba Mracek static OptionDefinition g_frame_recognizer_add_options[] = {
75841ae8e74SKuba Mracek     // clang-format off
75941ae8e74SKuba 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." },
76041ae8e74SKuba Mracek   { LLDB_OPT_SET_ALL, false, "function",      'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion, eArgTypeName,        "Name of the function that this recognizer applies to." },
76141ae8e74SKuba 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." },
76241ae8e74SKuba Mracek   { LLDB_OPT_SET_ALL, false, "regex",         'x', OptionParser::eNoArgument,       nullptr, {}, 0,                                     eArgTypeNone,        "Function name and module name are actually regular expressions." }
76341ae8e74SKuba Mracek     // clang-format on
76441ae8e74SKuba Mracek };
76541ae8e74SKuba Mracek 
76641ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
76741ae8e74SKuba Mracek private:
76841ae8e74SKuba Mracek   class CommandOptions : public Options {
76941ae8e74SKuba Mracek   public:
77041ae8e74SKuba Mracek     CommandOptions() : Options() {}
77141ae8e74SKuba Mracek     ~CommandOptions() override = default;
77241ae8e74SKuba Mracek 
77341ae8e74SKuba Mracek     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
77441ae8e74SKuba Mracek                           ExecutionContext *execution_context) override {
77541ae8e74SKuba Mracek       Status error;
77641ae8e74SKuba Mracek       const int short_option = m_getopt_table[option_idx].val;
77741ae8e74SKuba Mracek 
77841ae8e74SKuba Mracek       switch (short_option) {
77941ae8e74SKuba Mracek       case 'l':
78041ae8e74SKuba Mracek         m_class_name = std::string(option_arg);
78141ae8e74SKuba Mracek         break;
78241ae8e74SKuba Mracek       case 's':
78341ae8e74SKuba Mracek         m_module = std::string(option_arg);
78441ae8e74SKuba Mracek         break;
78541ae8e74SKuba Mracek       case 'n':
78641ae8e74SKuba Mracek         m_function = std::string(option_arg);
78741ae8e74SKuba Mracek         break;
78841ae8e74SKuba Mracek       case 'x':
78941ae8e74SKuba Mracek         m_regex = true;
79041ae8e74SKuba Mracek         break;
79141ae8e74SKuba Mracek       default:
79241ae8e74SKuba Mracek         error.SetErrorStringWithFormat("unrecognized option '%c'",
79341ae8e74SKuba Mracek                                        short_option);
79441ae8e74SKuba Mracek         break;
79541ae8e74SKuba Mracek       }
79641ae8e74SKuba Mracek 
79741ae8e74SKuba Mracek       return error;
79841ae8e74SKuba Mracek     }
79941ae8e74SKuba Mracek 
80041ae8e74SKuba Mracek     void OptionParsingStarting(ExecutionContext *execution_context) override {
80141ae8e74SKuba Mracek       m_module = "";
80241ae8e74SKuba Mracek       m_function = "";
80341ae8e74SKuba Mracek       m_class_name = "";
80441ae8e74SKuba Mracek       m_regex = false;
80541ae8e74SKuba Mracek     }
80641ae8e74SKuba Mracek 
80741ae8e74SKuba Mracek     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
80841ae8e74SKuba Mracek       return llvm::makeArrayRef(g_frame_recognizer_add_options);
80941ae8e74SKuba Mracek     }
81041ae8e74SKuba Mracek 
81141ae8e74SKuba Mracek     // Instance variables to hold the values for command options.
81241ae8e74SKuba Mracek     std::string m_class_name;
81341ae8e74SKuba Mracek     std::string m_module;
81441ae8e74SKuba Mracek     std::string m_function;
81541ae8e74SKuba Mracek     bool m_regex;
81641ae8e74SKuba Mracek   };
81741ae8e74SKuba Mracek 
81841ae8e74SKuba Mracek   CommandOptions m_options;
81941ae8e74SKuba Mracek 
82041ae8e74SKuba Mracek   Options *GetOptions() override { return &m_options; }
82141ae8e74SKuba Mracek 
82241ae8e74SKuba Mracek protected:
82341ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override;
82441ae8e74SKuba Mracek 
82541ae8e74SKuba Mracek public:
82641ae8e74SKuba Mracek   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
82741ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer add",
82841ae8e74SKuba Mracek                             "Add a new frame recognizer.", nullptr),
82941ae8e74SKuba Mracek         m_options() {
83041ae8e74SKuba Mracek     SetHelpLong(R"(
83141ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on
83241ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source
83341ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments
83441ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments.
83541ae8e74SKuba Mracek 
83641ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class
83741ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a
83841ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type
83941ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize.
84041ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that
84141ae8e74SKuba Mracek represent the recognized arguments.
84241ae8e74SKuba Mracek 
84341ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc
84441ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows:
84541ae8e74SKuba Mracek 
84641ae8e74SKuba Mracek   class LibcFdRecognizer(object):
84741ae8e74SKuba Mracek     def get_recognized_arguments(self, frame):
84841ae8e74SKuba Mracek       if frame.name in ["read", "write", "close"]:
84941ae8e74SKuba Mracek         fd = frame.EvaluateExpression("$arg1").unsigned
85041ae8e74SKuba Mracek         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
85141ae8e74SKuba Mracek         return [value]
85241ae8e74SKuba Mracek       return []
85341ae8e74SKuba Mracek 
85441ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script
85541ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'.
85641ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is
85741ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
85841ae8e74SKuba Mracek in other modules:
85941ae8e74SKuba Mracek 
86041ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py
86141ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
86241ae8e74SKuba Mracek 
86341ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we
86441ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable':
86541ae8e74SKuba Mracek 
86641ae8e74SKuba Mracek (lldb) b read
86741ae8e74SKuba Mracek (lldb) r
86841ae8e74SKuba Mracek Process 1234 stopped
86941ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
87041ae8e74SKuba Mracek     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
87141ae8e74SKuba Mracek (lldb) frame variable
87241ae8e74SKuba Mracek (int) fd = 3
87341ae8e74SKuba Mracek 
87441ae8e74SKuba Mracek     )");
87541ae8e74SKuba Mracek   }
87641ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerAdd() override = default;
87741ae8e74SKuba Mracek };
87841ae8e74SKuba Mracek 
87941ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
88041ae8e74SKuba Mracek                                                 CommandReturnObject &result) {
881f80d2655SKuba Mracek #ifndef LLDB_DISABLE_PYTHON
88241ae8e74SKuba Mracek   if (m_options.m_class_name.empty()) {
88341ae8e74SKuba Mracek     result.AppendErrorWithFormat(
88441ae8e74SKuba Mracek         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
88541ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
88641ae8e74SKuba Mracek     return false;
88741ae8e74SKuba Mracek   }
88841ae8e74SKuba Mracek 
88941ae8e74SKuba Mracek   if (m_options.m_module.empty()) {
89041ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
89141ae8e74SKuba Mracek                                  m_cmd_name.c_str());
89241ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
89341ae8e74SKuba Mracek     return false;
89441ae8e74SKuba Mracek   }
89541ae8e74SKuba Mracek 
89641ae8e74SKuba Mracek   if (m_options.m_function.empty()) {
89741ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a function name (-n argument).\n",
89841ae8e74SKuba Mracek                                  m_cmd_name.c_str());
89941ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
90041ae8e74SKuba Mracek     return false;
90141ae8e74SKuba Mracek   }
90241ae8e74SKuba Mracek 
90341ae8e74SKuba Mracek   ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
90441ae8e74SKuba Mracek 
90541ae8e74SKuba Mracek   if (interpreter &&
90641ae8e74SKuba Mracek       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
90741ae8e74SKuba Mracek     result.AppendWarning(
90841ae8e74SKuba Mracek         "The provided class does not exist - please define it "
90941ae8e74SKuba Mracek         "before attempting to use this frame recognizer");
91041ae8e74SKuba Mracek   }
91141ae8e74SKuba Mracek 
91241ae8e74SKuba Mracek   StackFrameRecognizerSP recognizer_sp =
91341ae8e74SKuba Mracek       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
91441ae8e74SKuba Mracek           interpreter, m_options.m_class_name.c_str()));
91541ae8e74SKuba Mracek   if (m_options.m_regex) {
91641ae8e74SKuba Mracek     auto module =
91741ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_module));
91841ae8e74SKuba Mracek     auto func =
91941ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_function));
92041ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
92141ae8e74SKuba Mracek   } else {
92241ae8e74SKuba Mracek     auto module = ConstString(m_options.m_module);
92341ae8e74SKuba Mracek     auto func = ConstString(m_options.m_function);
92441ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
92541ae8e74SKuba Mracek   }
926f80d2655SKuba Mracek #endif
92741ae8e74SKuba Mracek 
92841ae8e74SKuba Mracek   result.SetStatus(eReturnStatusSuccessFinishNoResult);
92941ae8e74SKuba Mracek   return result.Succeeded();
93041ae8e74SKuba Mracek }
93141ae8e74SKuba Mracek 
93241ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
93341ae8e74SKuba Mracek public:
93441ae8e74SKuba Mracek   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
93541ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer clear",
93641ae8e74SKuba Mracek                            "Delete all frame recognizers.", nullptr) {}
93741ae8e74SKuba Mracek 
93841ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerClear() override = default;
93941ae8e74SKuba Mracek 
94041ae8e74SKuba Mracek protected:
94141ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
94241ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveAllRecognizers();
94341ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
94441ae8e74SKuba Mracek     return result.Succeeded();
94541ae8e74SKuba Mracek   }
94641ae8e74SKuba Mracek };
94741ae8e74SKuba Mracek 
94841ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
94941ae8e74SKuba Mracek  public:
95041ae8e74SKuba Mracek   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
95141ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer delete",
95241ae8e74SKuba Mracek                             "Delete an existing frame recognizer.", nullptr) {}
95341ae8e74SKuba Mracek 
95441ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerDelete() override = default;
95541ae8e74SKuba Mracek 
95641ae8e74SKuba Mracek  protected:
95741ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
95841ae8e74SKuba Mracek     if (command.GetArgumentCount() == 0) {
95941ae8e74SKuba Mracek       if (!m_interpreter.Confirm(
96041ae8e74SKuba Mracek               "About to delete all frame recognizers, do you want to do that?",
96141ae8e74SKuba Mracek               true)) {
96241ae8e74SKuba Mracek         result.AppendMessage("Operation cancelled...");
96341ae8e74SKuba Mracek         result.SetStatus(eReturnStatusFailed);
96441ae8e74SKuba Mracek         return false;
96541ae8e74SKuba Mracek       }
96641ae8e74SKuba Mracek 
96741ae8e74SKuba Mracek       StackFrameRecognizerManager::RemoveAllRecognizers();
96841ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
96941ae8e74SKuba Mracek       return result.Succeeded();
97041ae8e74SKuba Mracek     }
97141ae8e74SKuba Mracek 
97241ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
97341ae8e74SKuba Mracek       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
97441ae8e74SKuba Mracek                                    m_cmd_name.c_str());
97541ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
97641ae8e74SKuba Mracek       return false;
97741ae8e74SKuba Mracek     }
97841ae8e74SKuba Mracek 
97941ae8e74SKuba Mracek     uint32_t recognizer_id =
98041ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
98141ae8e74SKuba Mracek 
98241ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
98341ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
98441ae8e74SKuba Mracek     return result.Succeeded();
98541ae8e74SKuba Mracek   }
98641ae8e74SKuba Mracek };
98741ae8e74SKuba Mracek 
98841ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed {
98941ae8e74SKuba Mracek  public:
99041ae8e74SKuba Mracek   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
99141ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer list",
99241ae8e74SKuba Mracek                             "Show a list of active frame recognizers.",
99341ae8e74SKuba Mracek                             nullptr) {}
99441ae8e74SKuba Mracek 
99541ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerList() override = default;
99641ae8e74SKuba Mracek 
99741ae8e74SKuba Mracek  protected:
99841ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
99941ae8e74SKuba Mracek     bool any_printed = false;
100041ae8e74SKuba Mracek     StackFrameRecognizerManager::ForEach(
100141ae8e74SKuba Mracek         [&result, &any_printed](uint32_t recognizer_id, std::string name,
100241ae8e74SKuba Mracek                                 std::string function, std::string symbol,
100341ae8e74SKuba Mracek                                 bool regexp) {
100441ae8e74SKuba Mracek           if (name == "") name = "(internal)";
100541ae8e74SKuba Mracek           result.GetOutputStream().Printf(
100641ae8e74SKuba Mracek               "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(),
100741ae8e74SKuba Mracek               function.c_str(), symbol.c_str(), regexp ? " (regexp)" : "");
100841ae8e74SKuba Mracek           any_printed = true;
100941ae8e74SKuba Mracek         });
101041ae8e74SKuba Mracek 
101141ae8e74SKuba Mracek     if (any_printed)
101241ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
101341ae8e74SKuba Mracek     else {
101441ae8e74SKuba Mracek       result.GetOutputStream().PutCString("no matching results found.\n");
101541ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishNoResult);
101641ae8e74SKuba Mracek     }
101741ae8e74SKuba Mracek     return result.Succeeded();
101841ae8e74SKuba Mracek   }
101941ae8e74SKuba Mracek };
102041ae8e74SKuba Mracek 
102141ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
102241ae8e74SKuba Mracek  public:
102341ae8e74SKuba Mracek   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
102441ae8e74SKuba Mracek       : CommandObjectParsed(
102541ae8e74SKuba Mracek             interpreter, "frame recognizer info",
102641ae8e74SKuba Mracek             "Show which frame recognizer is applied a stack frame (if any).",
102741ae8e74SKuba Mracek             nullptr) {
102841ae8e74SKuba Mracek     CommandArgumentEntry arg;
102941ae8e74SKuba Mracek     CommandArgumentData index_arg;
103041ae8e74SKuba Mracek 
103141ae8e74SKuba Mracek     // Define the first (and only) variant of this arg.
103241ae8e74SKuba Mracek     index_arg.arg_type = eArgTypeFrameIndex;
103341ae8e74SKuba Mracek     index_arg.arg_repetition = eArgRepeatPlain;
103441ae8e74SKuba Mracek 
103541ae8e74SKuba Mracek     // There is only one variant this argument could be; put it into the
103641ae8e74SKuba Mracek     // argument entry.
103741ae8e74SKuba Mracek     arg.push_back(index_arg);
103841ae8e74SKuba Mracek 
103941ae8e74SKuba Mracek     // Push the data for the first argument into the m_arguments vector.
104041ae8e74SKuba Mracek     m_arguments.push_back(arg);
104141ae8e74SKuba Mracek   }
104241ae8e74SKuba Mracek 
104341ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerInfo() override = default;
104441ae8e74SKuba Mracek 
104541ae8e74SKuba Mracek  protected:
104641ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
104741ae8e74SKuba Mracek     Process *process = m_exe_ctx.GetProcessPtr();
104841ae8e74SKuba Mracek     if (process == nullptr) {
104941ae8e74SKuba Mracek       result.AppendError("no process");
105041ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
105141ae8e74SKuba Mracek       return false;
105241ae8e74SKuba Mracek     }
105341ae8e74SKuba Mracek     Thread *thread = m_exe_ctx.GetThreadPtr();
105441ae8e74SKuba Mracek     if (thread == nullptr) {
105541ae8e74SKuba Mracek       result.AppendError("no thread");
105641ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
105741ae8e74SKuba Mracek       return false;
105841ae8e74SKuba Mracek     }
105941ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
106041ae8e74SKuba Mracek       result.AppendErrorWithFormat(
106141ae8e74SKuba Mracek           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
106241ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
106341ae8e74SKuba Mracek       return false;
106441ae8e74SKuba Mracek     }
106541ae8e74SKuba Mracek 
106641ae8e74SKuba Mracek     uint32_t frame_index =
106741ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
106841ae8e74SKuba Mracek     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
106941ae8e74SKuba Mracek     if (!frame_sp) {
107041ae8e74SKuba Mracek       result.AppendErrorWithFormat("no frame with index %u", frame_index);
107141ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
107241ae8e74SKuba Mracek       return false;
107341ae8e74SKuba Mracek     }
107441ae8e74SKuba Mracek 
107541ae8e74SKuba Mracek     auto recognizer =
107641ae8e74SKuba Mracek         StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
107741ae8e74SKuba Mracek 
107841ae8e74SKuba Mracek     Stream &output_stream = result.GetOutputStream();
107941ae8e74SKuba Mracek     output_stream.Printf("frame %d ", frame_index);
108041ae8e74SKuba Mracek     if (recognizer) {
108141ae8e74SKuba Mracek       output_stream << "is recognized by ";
108241ae8e74SKuba Mracek       output_stream << recognizer->GetName();
108341ae8e74SKuba Mracek     } else {
108441ae8e74SKuba Mracek       output_stream << "not recognized by any recognizer";
108541ae8e74SKuba Mracek     }
108641ae8e74SKuba Mracek     output_stream.EOL();
108741ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
108841ae8e74SKuba Mracek     return result.Succeeded();
108941ae8e74SKuba Mracek   }
109041ae8e74SKuba Mracek };
109141ae8e74SKuba Mracek 
109241ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword {
109341ae8e74SKuba Mracek  public:
109441ae8e74SKuba Mracek   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
109541ae8e74SKuba Mracek       : CommandObjectMultiword(
109641ae8e74SKuba Mracek             interpreter, "frame recognizer",
109741ae8e74SKuba Mracek             "Commands for editing and viewing frame recognizers.",
109841ae8e74SKuba Mracek             "frame recognizer [<sub-command-options>] ") {
109941ae8e74SKuba Mracek     LoadSubCommand(
110041ae8e74SKuba Mracek         "add",
110141ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerAdd(interpreter)));
110241ae8e74SKuba Mracek     LoadSubCommand(
110341ae8e74SKuba Mracek         "clear",
110441ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
110541ae8e74SKuba Mracek     LoadSubCommand(
110641ae8e74SKuba Mracek         "delete",
110741ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
110841ae8e74SKuba Mracek     LoadSubCommand(
110941ae8e74SKuba Mracek         "list",
111041ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerList(interpreter)));
111141ae8e74SKuba Mracek     LoadSubCommand(
111241ae8e74SKuba Mracek         "info",
111341ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerInfo(interpreter)));
111441ae8e74SKuba Mracek   }
111541ae8e74SKuba Mracek 
111641ae8e74SKuba Mracek   ~CommandObjectFrameRecognizer() override = default;
111741ae8e74SKuba Mracek };
111841ae8e74SKuba Mracek 
111930fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
112030fdc8d8SChris Lattner 
112130fdc8d8SChris Lattner //-------------------------------------------------------------------------
112230fdc8d8SChris Lattner // CommandObjectMultiwordFrame
112330fdc8d8SChris Lattner //-------------------------------------------------------------------------
112430fdc8d8SChris Lattner 
1125b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1126b9c1b51eSKate Stone     CommandInterpreter &interpreter)
1127b9c1b51eSKate Stone     : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and "
1128b9c1b51eSKate Stone                                                    "examing the current "
1129b9c1b51eSKate Stone                                                    "thread's stack frames.",
1130b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
1131b9c1b51eSKate Stone   LoadSubCommand("diagnose",
1132b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1133b9c1b51eSKate Stone   LoadSubCommand("info",
1134b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1135b9c1b51eSKate Stone   LoadSubCommand("select",
1136b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1137b9c1b51eSKate Stone   LoadSubCommand("variable",
1138b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
113941ae8e74SKuba Mracek #ifndef LLDB_DISABLE_PYTHON
114041ae8e74SKuba Mracek   LoadSubCommand(
114141ae8e74SKuba Mracek       "recognizer",
114241ae8e74SKuba Mracek       CommandObjectSP(new CommandObjectFrameRecognizer(interpreter)));
114341ae8e74SKuba Mracek #endif
114430fdc8d8SChris Lattner }
114530fdc8d8SChris Lattner 
1146c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1147