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"
1759998b7bSJonas Devlieghere #include "lldb/Host/Config.h"
187fb56d0aSGreg Clayton #include "lldb/Host/Host.h"
193eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h"
2041ae8e74SKuba Mracek #include "lldb/Host/StringConvert.h"
2130fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h"
2230fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h"
231deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h"
242837b766SJim Ingham #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
25715c2365SGreg Clayton #include "lldb/Interpreter/OptionGroupVariable.h"
26b9c1b51eSKate Stone #include "lldb/Interpreter/Options.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 
57ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_diag
58ec67e734SRaphael Isemann #include "CommandOptions.inc"
591f0f5b5bSZachary Turner 
60b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed {
614740a734SSean Callanan public:
62b9c1b51eSKate Stone   class CommandOptions : public Options {
634740a734SSean Callanan   public:
64b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
654740a734SSean Callanan 
664740a734SSean Callanan     ~CommandOptions() override = default;
674740a734SSean Callanan 
6897206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
69b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
7097206d57SZachary Turner       Status error;
714740a734SSean Callanan       const int short_option = m_getopt_table[option_idx].val;
72b9c1b51eSKate Stone       switch (short_option) {
734740a734SSean Callanan       case 'r':
744740a734SSean Callanan         reg = ConstString(option_arg);
754740a734SSean Callanan         break;
764740a734SSean Callanan 
77b9c1b51eSKate Stone       case 'a': {
78fe11483bSZachary Turner         address.emplace();
79fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *address)) {
804740a734SSean Callanan           address.reset();
81b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid address argument '%s'",
82fe11483bSZachary Turner                                          option_arg.str().c_str());
834740a734SSean Callanan         }
84b9c1b51eSKate Stone       } break;
854740a734SSean Callanan 
86b9c1b51eSKate Stone       case 'o': {
87fe11483bSZachary Turner         offset.emplace();
88fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *offset)) {
894740a734SSean Callanan           offset.reset();
90b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid offset argument '%s'",
91fe11483bSZachary Turner                                          option_arg.str().c_str());
924740a734SSean Callanan         }
93b9c1b51eSKate Stone       } break;
944740a734SSean Callanan 
954740a734SSean Callanan       default:
9636162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
974740a734SSean Callanan       }
984740a734SSean Callanan 
994740a734SSean Callanan       return error;
1004740a734SSean Callanan     }
1014740a734SSean Callanan 
102b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
1034740a734SSean Callanan       address.reset();
1044740a734SSean Callanan       reg.reset();
1054740a734SSean Callanan       offset.reset();
1064740a734SSean Callanan     }
1074740a734SSean Callanan 
1081f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
10970602439SZachary Turner       return llvm::makeArrayRef(g_frame_diag_options);
1101f0f5b5bSZachary Turner     }
1114740a734SSean Callanan 
1124740a734SSean Callanan     // Options.
1134740a734SSean Callanan     llvm::Optional<lldb::addr_t> address;
1144740a734SSean Callanan     llvm::Optional<ConstString> reg;
1154740a734SSean Callanan     llvm::Optional<int64_t> offset;
1164740a734SSean Callanan   };
1174740a734SSean Callanan 
1184740a734SSean Callanan   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
1194740a734SSean Callanan       : CommandObjectParsed(interpreter, "frame diagnose",
120b9c1b51eSKate Stone                             "Try to determine what path path the current stop "
121b9c1b51eSKate Stone                             "location used to get to a register or address",
122b9c1b51eSKate Stone                             nullptr,
123b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
124b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched |
1254740a734SSean Callanan                                 eCommandProcessMustBePaused),
126b9c1b51eSKate Stone         m_options() {
1274740a734SSean Callanan     CommandArgumentEntry arg;
1284740a734SSean Callanan     CommandArgumentData index_arg;
1294740a734SSean Callanan 
1304740a734SSean Callanan     // Define the first (and only) variant of this arg.
1314740a734SSean Callanan     index_arg.arg_type = eArgTypeFrameIndex;
1324740a734SSean Callanan     index_arg.arg_repetition = eArgRepeatOptional;
1334740a734SSean Callanan 
134b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
135b9c1b51eSKate Stone     // argument entry.
1364740a734SSean Callanan     arg.push_back(index_arg);
1374740a734SSean Callanan 
1384740a734SSean Callanan     // Push the data for the first argument into the m_arguments vector.
1394740a734SSean Callanan     m_arguments.push_back(arg);
1404740a734SSean Callanan   }
1414740a734SSean Callanan 
1424740a734SSean Callanan   ~CommandObjectFrameDiagnose() override = default;
1434740a734SSean Callanan 
144b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
1454740a734SSean Callanan 
1464740a734SSean Callanan protected:
147b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1484740a734SSean Callanan     Thread *thread = m_exe_ctx.GetThreadPtr();
1494740a734SSean Callanan     StackFrameSP frame_sp = thread->GetSelectedFrame();
1504740a734SSean Callanan 
1514740a734SSean Callanan     ValueObjectSP valobj_sp;
1524740a734SSean Callanan 
153b9c1b51eSKate Stone     if (m_options.address.hasValue()) {
154b9c1b51eSKate Stone       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
155b9c1b51eSKate Stone         result.AppendError(
156b9c1b51eSKate Stone             "`frame diagnose --address` is incompatible with other arguments.");
1574740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1584740a734SSean Callanan         return false;
1594740a734SSean Callanan       }
1604740a734SSean Callanan       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
161b9c1b51eSKate Stone     } else if (m_options.reg.hasValue()) {
162b9c1b51eSKate Stone       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
163b9c1b51eSKate Stone           m_options.reg.getValue(), m_options.offset.getValueOr(0));
164b9c1b51eSKate Stone     } else {
1654740a734SSean Callanan       StopInfoSP stop_info_sp = thread->GetStopInfo();
166b9c1b51eSKate Stone       if (!stop_info_sp) {
1674740a734SSean Callanan         result.AppendError("No arguments provided, and no stop info.");
1684740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1694740a734SSean Callanan         return false;
1704740a734SSean Callanan       }
1714740a734SSean Callanan 
1724740a734SSean Callanan       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
1734740a734SSean Callanan     }
1744740a734SSean Callanan 
175b9c1b51eSKate Stone     if (!valobj_sp) {
1764740a734SSean Callanan       result.AppendError("No diagnosis available.");
1774740a734SSean Callanan       result.SetStatus(eReturnStatusFailed);
1784740a734SSean Callanan       return false;
1794740a734SSean Callanan     }
1804740a734SSean Callanan 
181a925974bSAdrian Prantl     DumpValueObjectOptions::DeclPrintingHelper helper =
182a925974bSAdrian Prantl         [&valobj_sp](ConstString type, ConstString var,
183a925974bSAdrian Prantl                      const DumpValueObjectOptions &opts,
1843bc714b2SZachary Turner                      Stream &stream) -> bool {
185b9c1b51eSKate Stone       const ValueObject::GetExpressionPathFormat format = ValueObject::
186b9c1b51eSKate Stone           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
1875d1f711aSPavel Labath       const bool qualify_cxx_base_classes = false;
1884740a734SSean Callanan       valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
1894740a734SSean Callanan       stream.PutCString(" =");
1904740a734SSean Callanan       return true;
1914740a734SSean Callanan     };
1924740a734SSean Callanan 
1934740a734SSean Callanan     DumpValueObjectOptions options;
1944740a734SSean Callanan     options.SetDeclPrintingHelper(helper);
195b9c1b51eSKate Stone     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
196b9c1b51eSKate Stone                                options);
1974740a734SSean Callanan     printer.PrintValueObject();
1984740a734SSean Callanan 
1994740a734SSean Callanan     return true;
2004740a734SSean Callanan   }
2014740a734SSean Callanan 
2024740a734SSean Callanan protected:
2034740a734SSean Callanan   CommandOptions m_options;
2044740a734SSean Callanan };
2054740a734SSean Callanan 
20630fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo
20730fdc8d8SChris Lattner 
20830fdc8d8SChris Lattner // CommandObjectFrameInfo
20930fdc8d8SChris Lattner 
210b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed {
21130fdc8d8SChris Lattner public:
2127428a18cSKate Stone   CommandObjectFrameInfo(CommandInterpreter &interpreter)
213a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame info",
214a925974bSAdrian Prantl                             "List information about the current "
215b9c1b51eSKate Stone                             "stack frame in the current thread.",
216b9c1b51eSKate Stone                             "frame info",
217b9c1b51eSKate Stone                             eCommandRequiresFrame | eCommandTryTargetAPILock |
218a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
219a925974bSAdrian Prantl                                 eCommandProcessMustBePaused) {}
22030fdc8d8SChris Lattner 
221c8ecc2a9SEugene Zelenko   ~CommandObjectFrameInfo() override = default;
22230fdc8d8SChris Lattner 
2235a988416SJim Ingham protected:
224b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
225f9fc609fSGreg Clayton     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
22630fdc8d8SChris Lattner     result.SetStatus(eReturnStatusSuccessFinishResult);
22730fdc8d8SChris Lattner     return result.Succeeded();
22830fdc8d8SChris Lattner   }
22930fdc8d8SChris Lattner };
23030fdc8d8SChris Lattner 
23130fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect
23230fdc8d8SChris Lattner 
23330fdc8d8SChris Lattner // CommandObjectFrameSelect
23430fdc8d8SChris Lattner 
235ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_select
236ec67e734SRaphael Isemann #include "CommandOptions.inc"
2371f0f5b5bSZachary Turner 
238b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed {
23930fdc8d8SChris Lattner public:
240b9c1b51eSKate Stone   class CommandOptions : public Options {
241864174e1SGreg Clayton   public:
242b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
243864174e1SGreg Clayton 
244c8ecc2a9SEugene Zelenko     ~CommandOptions() override = default;
245864174e1SGreg Clayton 
24697206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
247b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
24897206d57SZachary Turner       Status error;
2493bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
250b9c1b51eSKate Stone       switch (short_option) {
251dab6f074SRaphael Isemann       case 'r': {
252dab6f074SRaphael Isemann         int32_t offset = 0;
253dab6f074SRaphael Isemann         if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
254b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
255fe11483bSZachary Turner                                          option_arg.str().c_str());
256dab6f074SRaphael Isemann         } else
257dab6f074SRaphael Isemann           relative_frame_offset = offset;
2585a039d55SRaphael Isemann         break;
259dab6f074SRaphael Isemann       }
260864174e1SGreg Clayton 
261864174e1SGreg Clayton       default:
26236162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
263864174e1SGreg Clayton       }
264864174e1SGreg Clayton 
265864174e1SGreg Clayton       return error;
266864174e1SGreg Clayton     }
267864174e1SGreg Clayton 
2685a039d55SRaphael Isemann     void OptionParsingStarting(ExecutionContext *execution_context) override {
269dab6f074SRaphael Isemann       relative_frame_offset.reset();
2705a039d55SRaphael Isemann     }
271864174e1SGreg Clayton 
2721f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
27370602439SZachary Turner       return llvm::makeArrayRef(g_frame_select_options);
2741f0f5b5bSZachary Turner     }
275864174e1SGreg Clayton 
276dab6f074SRaphael Isemann     llvm::Optional<int32_t> relative_frame_offset;
277864174e1SGreg Clayton   };
278864174e1SGreg Clayton 
2797428a18cSKate Stone   CommandObjectFrameSelect(CommandInterpreter &interpreter)
280a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame select",
281a925974bSAdrian Prantl                             "Select the current stack frame by "
282b9c1b51eSKate Stone                             "index from within the current thread "
283b9c1b51eSKate Stone                             "(see 'thread backtrace'.)",
284b9c1b51eSKate Stone                             nullptr,
285b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
286a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
287a925974bSAdrian Prantl                                 eCommandProcessMustBePaused),
288b9c1b51eSKate Stone         m_options() {
289405fe67fSCaroline Tice     CommandArgumentEntry arg;
290405fe67fSCaroline Tice     CommandArgumentData index_arg;
291405fe67fSCaroline Tice 
292405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
293405fe67fSCaroline Tice     index_arg.arg_type = eArgTypeFrameIndex;
294864174e1SGreg Clayton     index_arg.arg_repetition = eArgRepeatOptional;
295405fe67fSCaroline Tice 
296b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
297b9c1b51eSKate Stone     // argument entry.
298405fe67fSCaroline Tice     arg.push_back(index_arg);
299405fe67fSCaroline Tice 
300405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
301405fe67fSCaroline Tice     m_arguments.push_back(arg);
30230fdc8d8SChris Lattner   }
30330fdc8d8SChris Lattner 
304c8ecc2a9SEugene Zelenko   ~CommandObjectFrameSelect() override = default;
30530fdc8d8SChris Lattner 
306b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
307864174e1SGreg Clayton 
3085a988416SJim Ingham protected:
309b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
310b9c1b51eSKate Stone     // No need to check "thread" for validity as eCommandRequiresThread ensures
311b9c1b51eSKate Stone     // it is valid
312f9fc609fSGreg Clayton     Thread *thread = m_exe_ctx.GetThreadPtr();
313f9fc609fSGreg Clayton 
314864174e1SGreg Clayton     uint32_t frame_idx = UINT32_MAX;
315dab6f074SRaphael Isemann     if (m_options.relative_frame_offset.hasValue()) {
316864174e1SGreg Clayton       // The one and only argument is a signed relative frame index
317c14ee32dSGreg Clayton       frame_idx = thread->GetSelectedFrameIndex();
318864174e1SGreg Clayton       if (frame_idx == UINT32_MAX)
319864174e1SGreg Clayton         frame_idx = 0;
320864174e1SGreg Clayton 
321dab6f074SRaphael Isemann       if (*m_options.relative_frame_offset < 0) {
322dab6f074SRaphael Isemann         if (static_cast<int32_t>(frame_idx) >=
323dab6f074SRaphael Isemann             -*m_options.relative_frame_offset)
324dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
325b9c1b51eSKate Stone         else {
326b9c1b51eSKate Stone           if (frame_idx == 0) {
32705097246SAdrian Prantl             // If you are already at the bottom of the stack, then just warn
32805097246SAdrian Prantl             // and don't reset the frame.
3297428a18cSKate Stone             result.AppendError("Already at the bottom of the stack.");
330213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
331213b4546SJim Ingham             return false;
332b9c1b51eSKate Stone           } else
333864174e1SGreg Clayton             frame_idx = 0;
334864174e1SGreg Clayton         }
335dab6f074SRaphael Isemann       } else if (*m_options.relative_frame_offset > 0) {
336b9c1b51eSKate Stone         // I don't want "up 20" where "20" takes you past the top of the stack
337b9c1b51eSKate Stone         // to produce
338b9c1b51eSKate Stone         // an error, but rather to just go to the top.  So I have to count the
339b9c1b51eSKate Stone         // stack here...
340b0c72a5fSJim Ingham         const uint32_t num_frames = thread->GetStackFrameCount();
341b9c1b51eSKate Stone         if (static_cast<int32_t>(num_frames - frame_idx) >
342dab6f074SRaphael Isemann             *m_options.relative_frame_offset)
343dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
344b9c1b51eSKate Stone         else {
345b9c1b51eSKate Stone           if (frame_idx == num_frames - 1) {
346b9c1b51eSKate Stone             // If we are already at the top of the stack, just warn and don't
347b9c1b51eSKate Stone             // reset the frame.
3487428a18cSKate Stone             result.AppendError("Already at the top of the stack.");
349213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
350213b4546SJim Ingham             return false;
351b9c1b51eSKate Stone           } else
352864174e1SGreg Clayton             frame_idx = num_frames - 1;
353864174e1SGreg Clayton         }
354864174e1SGreg Clayton       }
355b9c1b51eSKate Stone     } else {
356f965cc86SZachary Turner       if (command.GetArgumentCount() > 1) {
357f965cc86SZachary Turner         result.AppendErrorWithFormat(
358f965cc86SZachary Turner             "too many arguments; expected frame-index, saw '%s'.\n",
359867e7d17SZachary Turner             command[0].c_str());
360f965cc86SZachary Turner         m_options.GenerateOptionUsage(
361f965cc86SZachary Turner             result.GetErrorStream(), this,
362f965cc86SZachary Turner             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
363f965cc86SZachary Turner         return false;
364f965cc86SZachary Turner       }
365f965cc86SZachary Turner 
366b9c1b51eSKate Stone       if (command.GetArgumentCount() == 1) {
3670d9a201eSRaphael Isemann         if (command[0].ref().getAsInteger(0, frame_idx)) {
368b9c1b51eSKate Stone           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
369f965cc86SZachary Turner                                        command[0].c_str());
370afbb0af8SJim Ingham           result.SetStatus(eReturnStatusFailed);
371afbb0af8SJim Ingham           return false;
372afbb0af8SJim Ingham         }
373b9c1b51eSKate Stone       } else if (command.GetArgumentCount() == 0) {
37482d4a2b9SJason Molenda         frame_idx = thread->GetSelectedFrameIndex();
375b9c1b51eSKate Stone         if (frame_idx == UINT32_MAX) {
37682d4a2b9SJason Molenda           frame_idx = 0;
37782d4a2b9SJason Molenda         }
378864174e1SGreg Clayton       }
379864174e1SGreg Clayton     }
38030fdc8d8SChris Lattner 
381b9c1b51eSKate Stone     bool success = thread->SetSelectedFrameByIndexNoisily(
382b9c1b51eSKate Stone         frame_idx, result.GetOutputStream());
383b9c1b51eSKate Stone     if (success) {
384f9fc609fSGreg Clayton       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
38530fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
386b9c1b51eSKate Stone     } else {
387b9c1b51eSKate Stone       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
388b9c1b51eSKate Stone                                    frame_idx);
38930fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
39093208b86SJim Ingham     }
39193208b86SJim Ingham 
39293208b86SJim Ingham     return result.Succeeded();
39330fdc8d8SChris Lattner   }
394864174e1SGreg Clayton 
395c8ecc2a9SEugene Zelenko protected:
396864174e1SGreg Clayton   CommandOptions m_options;
397864174e1SGreg Clayton };
398864174e1SGreg Clayton 
3996d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable
4006d56d2ceSJim Ingham // List images with associated information
401b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed {
4026d56d2ceSJim Ingham public:
4037428a18cSKate Stone   CommandObjectFrameVariable(CommandInterpreter &interpreter)
4047428a18cSKate Stone       : CommandObjectParsed(
405b9c1b51eSKate Stone             interpreter, "frame variable",
406b9c1b51eSKate Stone             "Show variables for the current stack frame. Defaults to all "
4077428a18cSKate Stone             "arguments and local variables in scope. Names of argument, "
4087428a18cSKate Stone             "local, file static and file global variables can be specified. "
409ed8a705cSGreg Clayton             "Children of aggregate variables can be specified such as "
410285ae0c0SJim Ingham             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
411285ae0c0SJim Ingham             "not invoke operator overloads if they exist, but directly access "
412285ae0c0SJim Ingham             "the specified element.  If you want to trigger operator overloads "
413285ae0c0SJim Ingham             "use the expression command to print the variable instead."
414285ae0c0SJim Ingham             "\nIt is worth noting that except for overloaded "
415285ae0c0SJim Ingham             "operators, when printing local variables 'expr local_var' and "
416285ae0c0SJim Ingham             "'frame var local_var' produce the same "
417285ae0c0SJim Ingham             "results.  However, 'frame variable' is more efficient, since it "
418285ae0c0SJim Ingham             "uses debug information and memory reads directly, rather than "
419285ae0c0SJim Ingham             "parsing and evaluating an expression, which may even involve "
420285ae0c0SJim Ingham             "JITing and running code in the target program.",
421a925974bSAdrian Prantl             nullptr,
422a925974bSAdrian Prantl             eCommandRequiresFrame | eCommandTryTargetAPILock |
423a925974bSAdrian Prantl                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
424a925974bSAdrian Prantl                 eCommandRequiresProcess),
425e1cfbc79STodd Fiala         m_option_group(),
426b9c1b51eSKate Stone         m_option_variable(
427b9c1b51eSKate Stone             true), // Include the frame specific options by passing "true"
428a925974bSAdrian Prantl         m_option_format(eFormatDefault), m_varobj_options() {
429405fe67fSCaroline Tice     CommandArgumentEntry arg;
430405fe67fSCaroline Tice     CommandArgumentData var_name_arg;
431405fe67fSCaroline Tice 
432405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
433405fe67fSCaroline Tice     var_name_arg.arg_type = eArgTypeVarName;
434405fe67fSCaroline Tice     var_name_arg.arg_repetition = eArgRepeatStar;
435405fe67fSCaroline Tice 
436b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
437b9c1b51eSKate Stone     // argument entry.
438405fe67fSCaroline Tice     arg.push_back(var_name_arg);
439405fe67fSCaroline Tice 
440405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
441405fe67fSCaroline Tice     m_arguments.push_back(arg);
4422837b766SJim Ingham 
443715c2365SGreg Clayton     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
444b9c1b51eSKate Stone     m_option_group.Append(&m_option_format,
445b9c1b51eSKate Stone                           OptionGroupFormat::OPTION_GROUP_FORMAT |
446b9c1b51eSKate Stone                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
447b9c1b51eSKate Stone                           LLDB_OPT_SET_1);
4482837b766SJim Ingham     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
4492837b766SJim Ingham     m_option_group.Finalize();
4506d56d2ceSJim Ingham   }
4516d56d2ceSJim Ingham 
452c8ecc2a9SEugene Zelenko   ~CommandObjectFrameVariable() override = default;
4536d56d2ceSJim Ingham 
454b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
455f21feadcSGreg Clayton 
456ae34ed2cSRaphael Isemann   void
457ae34ed2cSRaphael Isemann   HandleArgumentCompletion(CompletionRequest &request,
4582443bbd4SRaphael Isemann                            OptionElementVector &opt_element_vector) override {
459f21feadcSGreg Clayton     // Arguments are the standard source file completer.
460b9c1b51eSKate Stone     CommandCompletions::InvokeCommonCompletionCallbacks(
461b9c1b51eSKate Stone         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
462a2e76c0bSRaphael Isemann         request, nullptr);
463f21feadcSGreg Clayton   }
4646d56d2ceSJim Ingham 
4655a988416SJim Ingham protected:
46673418dfeSEnrico Granata   llvm::StringRef GetScopeString(VariableSP var_sp) {
46773418dfeSEnrico Granata     if (!var_sp)
46873418dfeSEnrico Granata       return llvm::StringRef::withNullAsEmpty(nullptr);
46973418dfeSEnrico Granata 
47073418dfeSEnrico Granata     switch (var_sp->GetScope()) {
47173418dfeSEnrico Granata     case eValueTypeVariableGlobal:
47273418dfeSEnrico Granata       return "GLOBAL: ";
47373418dfeSEnrico Granata     case eValueTypeVariableStatic:
47473418dfeSEnrico Granata       return "STATIC: ";
47573418dfeSEnrico Granata     case eValueTypeVariableArgument:
47673418dfeSEnrico Granata       return "ARG: ";
47773418dfeSEnrico Granata     case eValueTypeVariableLocal:
47873418dfeSEnrico Granata       return "LOCAL: ";
47973418dfeSEnrico Granata     case eValueTypeVariableThreadLocal:
48073418dfeSEnrico Granata       return "THREAD: ";
48173418dfeSEnrico Granata     default:
48273418dfeSEnrico Granata       break;
48373418dfeSEnrico Granata     }
48473418dfeSEnrico Granata 
48573418dfeSEnrico Granata     return llvm::StringRef::withNullAsEmpty(nullptr);
48673418dfeSEnrico Granata   }
48773418dfeSEnrico Granata 
488b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
48905097246SAdrian Prantl     // No need to check "frame" for validity as eCommandRequiresFrame ensures
49005097246SAdrian Prantl     // it is valid
491b57e4a1bSJason Molenda     StackFrame *frame = m_exe_ctx.GetFramePtr();
4921e49e5e7SJohnny Chen 
493a134cc1bSGreg Clayton     Stream &s = result.GetOutputStream();
4946d56d2ceSJim Ingham 
495b9c1b51eSKate Stone     // Be careful about the stack frame, if any summary formatter runs code, it
49605097246SAdrian Prantl     // might clear the StackFrameList for the thread.  So hold onto a shared
49705097246SAdrian Prantl     // pointer to the frame so it stays alive.
498650543f9SJim Ingham 
499b9c1b51eSKate Stone     VariableList *variable_list =
500b9c1b51eSKate Stone         frame->GetVariableList(m_option_variable.show_globals);
501a134cc1bSGreg Clayton 
5026d56d2ceSJim Ingham     VariableSP var_sp;
5036d56d2ceSJim Ingham     ValueObjectSP valobj_sp;
50478a685aaSJim Ingham 
505061858ceSEnrico Granata     TypeSummaryImplSP summary_format_sp;
50617b11749SEnrico Granata     if (!m_option_variable.summary.IsCurrentValueEmpty())
507b9c1b51eSKate Stone       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
508b9c1b51eSKate Stone           ConstString(m_option_variable.summary.GetCurrentValue()),
509b9c1b51eSKate Stone           summary_format_sp);
51017b11749SEnrico Granata     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
511796ac80bSJonas Devlieghere       summary_format_sp = std::make_shared<StringSummaryFormat>(
512b9c1b51eSKate Stone           TypeSummaryImpl::Flags(),
513796ac80bSJonas Devlieghere           m_option_variable.summary_string.GetCurrentValue());
514f9fa6ee5SEnrico Granata 
515b9c1b51eSKate Stone     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
516b9c1b51eSKate Stone         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
517b9c1b51eSKate Stone         summary_format_sp));
518379447a7SEnrico Granata 
519b9c1b51eSKate Stone     const SymbolContext &sym_ctx =
520b9c1b51eSKate Stone         frame->GetSymbolContext(eSymbolContextFunction);
5216754e04fSEnrico Granata     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
5226754e04fSEnrico Granata       m_option_variable.show_globals = true;
5236754e04fSEnrico Granata 
524b9c1b51eSKate Stone     if (variable_list) {
5251deb7962SGreg Clayton       const Format format = m_option_format.GetFormat();
5260c489f58SEnrico Granata       options.SetFormat(format);
5271deb7962SGreg Clayton 
52811eb9c64SZachary Turner       if (!command.empty()) {
52946747022SGreg Clayton         VariableList regex_var_list;
53046747022SGreg Clayton 
53105097246SAdrian Prantl         // If we have any args to the variable command, we will make variable
53205097246SAdrian Prantl         // objects from them...
533f965cc86SZachary Turner         for (auto &entry : command) {
534b9c1b51eSKate Stone           if (m_option_variable.use_regex) {
535c7bece56SGreg Clayton             const size_t regex_start_index = regex_var_list.GetSize();
5360d9a201eSRaphael Isemann             llvm::StringRef name_str = entry.ref();
53795eae423SZachary Turner             RegularExpression regex(name_str);
538f9d90bc5SJan Kratochvil             if (regex.IsValid()) {
53946747022SGreg Clayton               size_t num_matches = 0;
540b9c1b51eSKate Stone               const size_t num_new_regex_vars =
541b9c1b51eSKate Stone                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
54278a685aaSJim Ingham                                                          num_matches);
543b9c1b51eSKate Stone               if (num_new_regex_vars > 0) {
544b9c1b51eSKate Stone                 for (size_t regex_idx = regex_start_index,
545b9c1b51eSKate Stone                             end_index = regex_var_list.GetSize();
546b9c1b51eSKate Stone                      regex_idx < end_index; ++regex_idx) {
54746747022SGreg Clayton                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
548b9c1b51eSKate Stone                   if (var_sp) {
549b9c1b51eSKate Stone                     valobj_sp = frame->GetValueObjectForFrameVariable(
550b9c1b51eSKate Stone                         var_sp, m_varobj_options.use_dynamic);
551b9c1b51eSKate Stone                     if (valobj_sp) {
55273418dfeSEnrico Granata                       std::string scope_string;
55373418dfeSEnrico Granata                       if (m_option_variable.show_scope)
55473418dfeSEnrico Granata                         scope_string = GetScopeString(var_sp).str();
55573418dfeSEnrico Granata 
55673418dfeSEnrico Granata                       if (!scope_string.empty())
557771ef6d4SMalcolm Parsons                         s.PutCString(scope_string);
55873418dfeSEnrico Granata 
559b9c1b51eSKate Stone                       if (m_option_variable.show_decl &&
560b9c1b51eSKate Stone                           var_sp->GetDeclaration().GetFile()) {
56145ba8543SGreg Clayton                         bool show_fullpaths = false;
56245ba8543SGreg Clayton                         bool show_module = true;
563b9c1b51eSKate Stone                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
564b9c1b51eSKate Stone                                                     show_module))
56546747022SGreg Clayton                           s.PutCString(": ");
56646747022SGreg Clayton                       }
5674d93b8cdSEnrico Granata                       valobj_sp->Dump(result.GetOutputStream(), options);
56846747022SGreg Clayton                     }
56946747022SGreg Clayton                   }
57046747022SGreg Clayton                 }
571b9c1b51eSKate Stone               } else if (num_matches == 0) {
572b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: no variables matched "
573b9c1b51eSKate Stone                                                "the regular expression '%s'.\n",
574f965cc86SZachary Turner                                                entry.c_str());
57546747022SGreg Clayton               }
576b9c1b51eSKate Stone             } else {
5773af3f1e8SJonas Devlieghere               if (llvm::Error err = regex.GetError())
5783af3f1e8SJonas Devlieghere                 result.GetErrorStream().Printf(
5793af3f1e8SJonas Devlieghere                     "error: %s\n", llvm::toString(std::move(err)).c_str());
58046747022SGreg Clayton               else
581b9c1b51eSKate Stone                 result.GetErrorStream().Printf(
582b9c1b51eSKate Stone                     "error: unknown regex error when compiling '%s'\n",
583f965cc86SZachary Turner                     entry.c_str());
58446747022SGreg Clayton             }
585b9c1b51eSKate Stone           } else // No regex, either exact variable names or variable
586b9c1b51eSKate Stone                  // expressions.
58746747022SGreg Clayton           {
58897206d57SZachary Turner             Status error;
589b9c1b51eSKate Stone             uint32_t expr_path_options =
590b9c1b51eSKate Stone                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
59146252398SEnrico Granata                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
59246252398SEnrico Granata                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
5932837b766SJim Ingham             lldb::VariableSP var_sp;
594b9c1b51eSKate Stone             valobj_sp = frame->GetValueForVariableExpressionPath(
5950d9a201eSRaphael Isemann                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
596b9c1b51eSKate Stone                 var_sp, error);
597b9c1b51eSKate Stone             if (valobj_sp) {
59873418dfeSEnrico Granata               std::string scope_string;
59973418dfeSEnrico Granata               if (m_option_variable.show_scope)
60073418dfeSEnrico Granata                 scope_string = GetScopeString(var_sp).str();
60173418dfeSEnrico Granata 
60273418dfeSEnrico Granata               if (!scope_string.empty())
603771ef6d4SMalcolm Parsons                 s.PutCString(scope_string);
604b9c1b51eSKate Stone               if (m_option_variable.show_decl && var_sp &&
605b9c1b51eSKate Stone                   var_sp->GetDeclaration().GetFile()) {
606a134cc1bSGreg Clayton                 var_sp->GetDeclaration().DumpStopContext(&s, false);
607a134cc1bSGreg Clayton                 s.PutCString(": ");
608a134cc1bSGreg Clayton               }
6090c489f58SEnrico Granata 
6100c489f58SEnrico Granata               options.SetFormat(format);
611b9c1b51eSKate Stone               options.SetVariableFormatDisplayLanguage(
612b9c1b51eSKate Stone                   valobj_sp->GetPreferredDisplayLanguage());
613887062aeSJohnny Chen 
614887062aeSJohnny Chen               Stream &output_stream = result.GetOutputStream();
615f965cc86SZachary Turner               options.SetRootValueObjectName(
616f965cc86SZachary Turner                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
6174d93b8cdSEnrico Granata               valobj_sp->Dump(output_stream, options);
618b9c1b51eSKate Stone             } else {
619c8ecc2a9SEugene Zelenko               const char *error_cstr = error.AsCString(nullptr);
62054979cddSGreg Clayton               if (error_cstr)
62154979cddSGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
62254979cddSGreg Clayton               else
623b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: unable to find any "
624b9c1b51eSKate Stone                                                "variable expression path that "
625b9c1b51eSKate Stone                                                "matches '%s'.\n",
626f965cc86SZachary Turner                                                entry.c_str());
6276d56d2ceSJim Ingham             }
6286d56d2ceSJim Ingham           }
6296d56d2ceSJim Ingham         }
630b9c1b51eSKate Stone       } else // No command arg specified.  Use variable_list, instead.
6316d56d2ceSJim Ingham       {
632c7bece56SGreg Clayton         const size_t num_variables = variable_list->GetSize();
633b9c1b51eSKate Stone         if (num_variables > 0) {
634b9c1b51eSKate Stone           for (size_t i = 0; i < num_variables; i++) {
6351a65ae11SGreg Clayton             var_sp = variable_list->GetVariableAtIndex(i);
636f955efc0SSylvestre Ledru             switch (var_sp->GetScope()) {
637eb236735SJim Ingham             case eValueTypeVariableGlobal:
638eb236735SJim Ingham               if (!m_option_variable.show_globals)
639eb236735SJim Ingham                 continue;
640eb236735SJim Ingham               break;
641eb236735SJim Ingham             case eValueTypeVariableStatic:
642eb236735SJim Ingham               if (!m_option_variable.show_globals)
643eb236735SJim Ingham                 continue;
644eb236735SJim Ingham               break;
645eb236735SJim Ingham             case eValueTypeVariableArgument:
646eb236735SJim Ingham               if (!m_option_variable.show_args)
647eb236735SJim Ingham                 continue;
648eb236735SJim Ingham               break;
649eb236735SJim Ingham             case eValueTypeVariableLocal:
650eb236735SJim Ingham               if (!m_option_variable.show_locals)
651eb236735SJim Ingham                 continue;
652eb236735SJim Ingham               break;
653eb236735SJim Ingham             default:
654eb236735SJim Ingham               continue;
655eb236735SJim Ingham               break;
656eb236735SJim Ingham             }
657560558ebSEnrico Granata             std::string scope_string;
658eb236735SJim Ingham             if (m_option_variable.show_scope)
65973418dfeSEnrico Granata               scope_string = GetScopeString(var_sp).str();
6606d56d2ceSJim Ingham 
66105097246SAdrian Prantl             // Use the variable object code to make sure we are using the same
66205097246SAdrian Prantl             // APIs as the public API will be using...
663b9c1b51eSKate Stone             valobj_sp = frame->GetValueObjectForFrameVariable(
664b9c1b51eSKate Stone                 var_sp, m_varobj_options.use_dynamic);
665b9c1b51eSKate Stone             if (valobj_sp) {
66605097246SAdrian Prantl               // When dumping all variables, don't print any variables that are
66705097246SAdrian Prantl               // not in scope to avoid extra unneeded output
668b9c1b51eSKate Stone               if (valobj_sp->IsInScope()) {
669b9c1b51eSKate Stone                 if (!valobj_sp->GetTargetSP()
670b9c1b51eSKate Stone                          ->GetDisplayRuntimeSupportValues() &&
671c8ecc2a9SEugene Zelenko                     valobj_sp->IsRuntimeSupportValue())
672560558ebSEnrico Granata                   continue;
673560558ebSEnrico Granata 
674560558ebSEnrico Granata                 if (!scope_string.empty())
675771ef6d4SMalcolm Parsons                   s.PutCString(scope_string);
676560558ebSEnrico Granata 
677b9c1b51eSKate Stone                 if (m_option_variable.show_decl &&
678b9c1b51eSKate Stone                     var_sp->GetDeclaration().GetFile()) {
679a134cc1bSGreg Clayton                   var_sp->GetDeclaration().DumpStopContext(&s, false);
680a134cc1bSGreg Clayton                   s.PutCString(": ");
681a134cc1bSGreg Clayton                 }
6820c489f58SEnrico Granata 
6830c489f58SEnrico Granata                 options.SetFormat(format);
684b9c1b51eSKate Stone                 options.SetVariableFormatDisplayLanguage(
685b9c1b51eSKate Stone                     valobj_sp->GetPreferredDisplayLanguage());
686f965cc86SZachary Turner                 options.SetRootValueObjectName(
687f965cc86SZachary Turner                     var_sp ? var_sp->GetName().AsCString() : nullptr);
6884d93b8cdSEnrico Granata                 valobj_sp->Dump(result.GetOutputStream(), options);
689a134cc1bSGreg Clayton               }
690a134cc1bSGreg Clayton             }
6916d56d2ceSJim Ingham           }
6926d56d2ceSJim Ingham         }
6936d56d2ceSJim Ingham       }
6946d56d2ceSJim Ingham       result.SetStatus(eReturnStatusSuccessFinishResult);
6956d56d2ceSJim Ingham     }
69661a80ba6SEnrico Granata 
69741ae8e74SKuba Mracek     if (m_option_variable.show_recognized_args) {
69841ae8e74SKuba Mracek       auto recognized_frame = frame->GetRecognizedFrame();
69941ae8e74SKuba Mracek       if (recognized_frame) {
70041ae8e74SKuba Mracek         ValueObjectListSP recognized_arg_list =
70141ae8e74SKuba Mracek             recognized_frame->GetRecognizedArguments();
70241ae8e74SKuba Mracek         if (recognized_arg_list) {
70341ae8e74SKuba Mracek           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
70441ae8e74SKuba Mracek             options.SetFormat(m_option_format.GetFormat());
70541ae8e74SKuba Mracek             options.SetVariableFormatDisplayLanguage(
70641ae8e74SKuba Mracek                 rec_value_sp->GetPreferredDisplayLanguage());
70741ae8e74SKuba Mracek             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
70841ae8e74SKuba Mracek             rec_value_sp->Dump(result.GetOutputStream(), options);
70941ae8e74SKuba Mracek           }
71041ae8e74SKuba Mracek         }
71141ae8e74SKuba Mracek       }
71241ae8e74SKuba Mracek     }
71341ae8e74SKuba Mracek 
714b9c1b51eSKate Stone     if (m_interpreter.TruncationWarningNecessary()) {
71561a80ba6SEnrico Granata       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
71661a80ba6SEnrico Granata                                       m_cmd_name.c_str());
71761a80ba6SEnrico Granata       m_interpreter.TruncationWarningGiven();
71861a80ba6SEnrico Granata     }
71961a80ba6SEnrico Granata 
72024fff242SDavide Italiano     // Increment statistics.
72124fff242SDavide Italiano     bool res = result.Succeeded();
722cb2380c9SRaphael Isemann     Target &target = GetSelectedOrDummyTarget();
72324fff242SDavide Italiano     if (res)
724cb2380c9SRaphael Isemann       target.IncrementStats(StatisticKind::FrameVarSuccess);
72524fff242SDavide Italiano     else
726cb2380c9SRaphael Isemann       target.IncrementStats(StatisticKind::FrameVarFailure);
72724fff242SDavide Italiano     return res;
7286d56d2ceSJim Ingham   }
7296d56d2ceSJim Ingham 
730c8ecc2a9SEugene Zelenko protected:
7312837b766SJim Ingham   OptionGroupOptions m_option_group;
732715c2365SGreg Clayton   OptionGroupVariable m_option_variable;
7331deb7962SGreg Clayton   OptionGroupFormat m_option_format;
7342837b766SJim Ingham   OptionGroupValueObjectDisplay m_varobj_options;
7356d56d2ceSJim Ingham };
7366d56d2ceSJim Ingham 
73741ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer
73841ae8e74SKuba Mracek 
739ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_recognizer_add
740ec67e734SRaphael Isemann #include "CommandOptions.inc"
74141ae8e74SKuba Mracek 
74241ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
74341ae8e74SKuba Mracek private:
74441ae8e74SKuba Mracek   class CommandOptions : public Options {
74541ae8e74SKuba Mracek   public:
74641ae8e74SKuba Mracek     CommandOptions() : Options() {}
74741ae8e74SKuba Mracek     ~CommandOptions() override = default;
74841ae8e74SKuba Mracek 
74941ae8e74SKuba Mracek     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
75041ae8e74SKuba Mracek                           ExecutionContext *execution_context) override {
75141ae8e74SKuba Mracek       Status error;
75241ae8e74SKuba Mracek       const int short_option = m_getopt_table[option_idx].val;
75341ae8e74SKuba Mracek 
75441ae8e74SKuba Mracek       switch (short_option) {
75541ae8e74SKuba Mracek       case 'l':
75641ae8e74SKuba Mracek         m_class_name = std::string(option_arg);
75741ae8e74SKuba Mracek         break;
75841ae8e74SKuba Mracek       case 's':
75941ae8e74SKuba Mracek         m_module = std::string(option_arg);
76041ae8e74SKuba Mracek         break;
76141ae8e74SKuba Mracek       case 'n':
76241ae8e74SKuba Mracek         m_function = std::string(option_arg);
76341ae8e74SKuba Mracek         break;
76441ae8e74SKuba Mracek       case 'x':
76541ae8e74SKuba Mracek         m_regex = true;
76641ae8e74SKuba Mracek         break;
76741ae8e74SKuba Mracek       default:
76836162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
76941ae8e74SKuba Mracek       }
77041ae8e74SKuba Mracek 
77141ae8e74SKuba Mracek       return error;
77241ae8e74SKuba Mracek     }
77341ae8e74SKuba Mracek 
77441ae8e74SKuba Mracek     void OptionParsingStarting(ExecutionContext *execution_context) override {
77541ae8e74SKuba Mracek       m_module = "";
77641ae8e74SKuba Mracek       m_function = "";
77741ae8e74SKuba Mracek       m_class_name = "";
77841ae8e74SKuba Mracek       m_regex = false;
77941ae8e74SKuba Mracek     }
78041ae8e74SKuba Mracek 
78141ae8e74SKuba Mracek     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
78241ae8e74SKuba Mracek       return llvm::makeArrayRef(g_frame_recognizer_add_options);
78341ae8e74SKuba Mracek     }
78441ae8e74SKuba Mracek 
78541ae8e74SKuba Mracek     // Instance variables to hold the values for command options.
78641ae8e74SKuba Mracek     std::string m_class_name;
78741ae8e74SKuba Mracek     std::string m_module;
78841ae8e74SKuba Mracek     std::string m_function;
78941ae8e74SKuba Mracek     bool m_regex;
79041ae8e74SKuba Mracek   };
79141ae8e74SKuba Mracek 
79241ae8e74SKuba Mracek   CommandOptions m_options;
79341ae8e74SKuba Mracek 
79441ae8e74SKuba Mracek   Options *GetOptions() override { return &m_options; }
79541ae8e74SKuba Mracek 
79641ae8e74SKuba Mracek protected:
79741ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override;
79841ae8e74SKuba Mracek 
79941ae8e74SKuba Mracek public:
80041ae8e74SKuba Mracek   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
80141ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer add",
80241ae8e74SKuba Mracek                             "Add a new frame recognizer.", nullptr),
80341ae8e74SKuba Mracek         m_options() {
80441ae8e74SKuba Mracek     SetHelpLong(R"(
80541ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on
80641ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source
80741ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments
80841ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments.
80941ae8e74SKuba Mracek 
81041ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class
81141ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a
81241ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type
81341ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize.
81441ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that
81541ae8e74SKuba Mracek represent the recognized arguments.
81641ae8e74SKuba Mracek 
81741ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc
81841ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows:
81941ae8e74SKuba Mracek 
82041ae8e74SKuba Mracek   class LibcFdRecognizer(object):
82141ae8e74SKuba Mracek     def get_recognized_arguments(self, frame):
82241ae8e74SKuba Mracek       if frame.name in ["read", "write", "close"]:
82341ae8e74SKuba Mracek         fd = frame.EvaluateExpression("$arg1").unsigned
82441ae8e74SKuba Mracek         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
82541ae8e74SKuba Mracek         return [value]
82641ae8e74SKuba Mracek       return []
82741ae8e74SKuba Mracek 
82841ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script
82941ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'.
83041ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is
83141ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
83241ae8e74SKuba Mracek in other modules:
83341ae8e74SKuba Mracek 
83441ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py
83541ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
83641ae8e74SKuba Mracek 
83741ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we
83841ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable':
83941ae8e74SKuba Mracek 
84041ae8e74SKuba Mracek (lldb) b read
84141ae8e74SKuba Mracek (lldb) r
84241ae8e74SKuba Mracek Process 1234 stopped
84341ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
84441ae8e74SKuba Mracek     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
84541ae8e74SKuba Mracek (lldb) frame variable
84641ae8e74SKuba Mracek (int) fd = 3
84741ae8e74SKuba Mracek 
84841ae8e74SKuba Mracek     )");
84941ae8e74SKuba Mracek   }
85041ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerAdd() override = default;
85141ae8e74SKuba Mracek };
85241ae8e74SKuba Mracek 
85341ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
85441ae8e74SKuba Mracek                                                 CommandReturnObject &result) {
855*4e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
85641ae8e74SKuba Mracek   if (m_options.m_class_name.empty()) {
85741ae8e74SKuba Mracek     result.AppendErrorWithFormat(
85841ae8e74SKuba Mracek         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
85941ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
86041ae8e74SKuba Mracek     return false;
86141ae8e74SKuba Mracek   }
86241ae8e74SKuba Mracek 
86341ae8e74SKuba Mracek   if (m_options.m_module.empty()) {
86441ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
86541ae8e74SKuba Mracek                                  m_cmd_name.c_str());
86641ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
86741ae8e74SKuba Mracek     return false;
86841ae8e74SKuba Mracek   }
86941ae8e74SKuba Mracek 
87041ae8e74SKuba Mracek   if (m_options.m_function.empty()) {
87141ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a function name (-n argument).\n",
87241ae8e74SKuba Mracek                                  m_cmd_name.c_str());
87341ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
87441ae8e74SKuba Mracek     return false;
87541ae8e74SKuba Mracek   }
87641ae8e74SKuba Mracek 
8772b29b432SJonas Devlieghere   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
87841ae8e74SKuba Mracek 
87941ae8e74SKuba Mracek   if (interpreter &&
88041ae8e74SKuba Mracek       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
881a925974bSAdrian Prantl     result.AppendWarning("The provided class does not exist - please define it "
88241ae8e74SKuba Mracek                          "before attempting to use this frame recognizer");
88341ae8e74SKuba Mracek   }
88441ae8e74SKuba Mracek 
88541ae8e74SKuba Mracek   StackFrameRecognizerSP recognizer_sp =
88641ae8e74SKuba Mracek       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
88741ae8e74SKuba Mracek           interpreter, m_options.m_class_name.c_str()));
88841ae8e74SKuba Mracek   if (m_options.m_regex) {
88941ae8e74SKuba Mracek     auto module =
89041ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_module));
89141ae8e74SKuba Mracek     auto func =
89241ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_function));
89341ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
89441ae8e74SKuba Mracek   } else {
89541ae8e74SKuba Mracek     auto module = ConstString(m_options.m_module);
89641ae8e74SKuba Mracek     auto func = ConstString(m_options.m_function);
89741ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
89841ae8e74SKuba Mracek   }
899f80d2655SKuba Mracek #endif
90041ae8e74SKuba Mracek 
90141ae8e74SKuba Mracek   result.SetStatus(eReturnStatusSuccessFinishNoResult);
90241ae8e74SKuba Mracek   return result.Succeeded();
90341ae8e74SKuba Mracek }
90441ae8e74SKuba Mracek 
90541ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
90641ae8e74SKuba Mracek public:
90741ae8e74SKuba Mracek   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
90841ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer clear",
90941ae8e74SKuba Mracek                             "Delete all frame recognizers.", nullptr) {}
91041ae8e74SKuba Mracek 
91141ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerClear() override = default;
91241ae8e74SKuba Mracek 
91341ae8e74SKuba Mracek protected:
91441ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
91541ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveAllRecognizers();
91641ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
91741ae8e74SKuba Mracek     return result.Succeeded();
91841ae8e74SKuba Mracek   }
91941ae8e74SKuba Mracek };
92041ae8e74SKuba Mracek 
92141ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
92241ae8e74SKuba Mracek public:
92341ae8e74SKuba Mracek   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
92441ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer delete",
92541ae8e74SKuba Mracek                             "Delete an existing frame recognizer.", nullptr) {}
92641ae8e74SKuba Mracek 
92741ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerDelete() override = default;
92841ae8e74SKuba Mracek 
92941ae8e74SKuba Mracek protected:
93041ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
93141ae8e74SKuba Mracek     if (command.GetArgumentCount() == 0) {
93241ae8e74SKuba Mracek       if (!m_interpreter.Confirm(
93341ae8e74SKuba Mracek               "About to delete all frame recognizers, do you want to do that?",
93441ae8e74SKuba Mracek               true)) {
93541ae8e74SKuba Mracek         result.AppendMessage("Operation cancelled...");
93641ae8e74SKuba Mracek         result.SetStatus(eReturnStatusFailed);
93741ae8e74SKuba Mracek         return false;
93841ae8e74SKuba Mracek       }
93941ae8e74SKuba Mracek 
94041ae8e74SKuba Mracek       StackFrameRecognizerManager::RemoveAllRecognizers();
94141ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
94241ae8e74SKuba Mracek       return result.Succeeded();
94341ae8e74SKuba Mracek     }
94441ae8e74SKuba Mracek 
94541ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
94641ae8e74SKuba Mracek       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
94741ae8e74SKuba Mracek                                    m_cmd_name.c_str());
94841ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
94941ae8e74SKuba Mracek       return false;
95041ae8e74SKuba Mracek     }
95141ae8e74SKuba Mracek 
95241ae8e74SKuba Mracek     uint32_t recognizer_id =
95341ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
95441ae8e74SKuba Mracek 
95541ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
95641ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
95741ae8e74SKuba Mracek     return result.Succeeded();
95841ae8e74SKuba Mracek   }
95941ae8e74SKuba Mracek };
96041ae8e74SKuba Mracek 
96141ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed {
96241ae8e74SKuba Mracek public:
96341ae8e74SKuba Mracek   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
96441ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer list",
96541ae8e74SKuba Mracek                             "Show a list of active frame recognizers.",
96641ae8e74SKuba Mracek                             nullptr) {}
96741ae8e74SKuba Mracek 
96841ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerList() override = default;
96941ae8e74SKuba Mracek 
97041ae8e74SKuba Mracek protected:
97141ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
97241ae8e74SKuba Mracek     bool any_printed = false;
97341ae8e74SKuba Mracek     StackFrameRecognizerManager::ForEach(
97441ae8e74SKuba Mracek         [&result, &any_printed](uint32_t recognizer_id, std::string name,
97541ae8e74SKuba Mracek                                 std::string function, std::string symbol,
97641ae8e74SKuba Mracek                                 bool regexp) {
977a925974bSAdrian Prantl           if (name == "")
978a925974bSAdrian Prantl             name = "(internal)";
97941ae8e74SKuba Mracek           result.GetOutputStream().Printf(
98041ae8e74SKuba Mracek               "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(),
98141ae8e74SKuba Mracek               function.c_str(), symbol.c_str(), regexp ? " (regexp)" : "");
98241ae8e74SKuba Mracek           any_printed = true;
98341ae8e74SKuba Mracek         });
98441ae8e74SKuba Mracek 
98541ae8e74SKuba Mracek     if (any_printed)
98641ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
98741ae8e74SKuba Mracek     else {
98841ae8e74SKuba Mracek       result.GetOutputStream().PutCString("no matching results found.\n");
98941ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishNoResult);
99041ae8e74SKuba Mracek     }
99141ae8e74SKuba Mracek     return result.Succeeded();
99241ae8e74SKuba Mracek   }
99341ae8e74SKuba Mracek };
99441ae8e74SKuba Mracek 
99541ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
99641ae8e74SKuba Mracek public:
99741ae8e74SKuba Mracek   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
99841ae8e74SKuba Mracek       : CommandObjectParsed(
99941ae8e74SKuba Mracek             interpreter, "frame recognizer info",
100041ae8e74SKuba Mracek             "Show which frame recognizer is applied a stack frame (if any).",
100141ae8e74SKuba Mracek             nullptr) {
100241ae8e74SKuba Mracek     CommandArgumentEntry arg;
100341ae8e74SKuba Mracek     CommandArgumentData index_arg;
100441ae8e74SKuba Mracek 
100541ae8e74SKuba Mracek     // Define the first (and only) variant of this arg.
100641ae8e74SKuba Mracek     index_arg.arg_type = eArgTypeFrameIndex;
100741ae8e74SKuba Mracek     index_arg.arg_repetition = eArgRepeatPlain;
100841ae8e74SKuba Mracek 
100941ae8e74SKuba Mracek     // There is only one variant this argument could be; put it into the
101041ae8e74SKuba Mracek     // argument entry.
101141ae8e74SKuba Mracek     arg.push_back(index_arg);
101241ae8e74SKuba Mracek 
101341ae8e74SKuba Mracek     // Push the data for the first argument into the m_arguments vector.
101441ae8e74SKuba Mracek     m_arguments.push_back(arg);
101541ae8e74SKuba Mracek   }
101641ae8e74SKuba Mracek 
101741ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerInfo() override = default;
101841ae8e74SKuba Mracek 
101941ae8e74SKuba Mracek protected:
102041ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
102141ae8e74SKuba Mracek     Process *process = m_exe_ctx.GetProcessPtr();
102241ae8e74SKuba Mracek     if (process == nullptr) {
102341ae8e74SKuba Mracek       result.AppendError("no process");
102441ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
102541ae8e74SKuba Mracek       return false;
102641ae8e74SKuba Mracek     }
102741ae8e74SKuba Mracek     Thread *thread = m_exe_ctx.GetThreadPtr();
102841ae8e74SKuba Mracek     if (thread == nullptr) {
102941ae8e74SKuba Mracek       result.AppendError("no thread");
103041ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
103141ae8e74SKuba Mracek       return false;
103241ae8e74SKuba Mracek     }
103341ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
103441ae8e74SKuba Mracek       result.AppendErrorWithFormat(
103541ae8e74SKuba Mracek           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
103641ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
103741ae8e74SKuba Mracek       return false;
103841ae8e74SKuba Mracek     }
103941ae8e74SKuba Mracek 
104041ae8e74SKuba Mracek     uint32_t frame_index =
104141ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
104241ae8e74SKuba Mracek     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
104341ae8e74SKuba Mracek     if (!frame_sp) {
104441ae8e74SKuba Mracek       result.AppendErrorWithFormat("no frame with index %u", frame_index);
104541ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
104641ae8e74SKuba Mracek       return false;
104741ae8e74SKuba Mracek     }
104841ae8e74SKuba Mracek 
104941ae8e74SKuba Mracek     auto recognizer =
105041ae8e74SKuba Mracek         StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
105141ae8e74SKuba Mracek 
105241ae8e74SKuba Mracek     Stream &output_stream = result.GetOutputStream();
105341ae8e74SKuba Mracek     output_stream.Printf("frame %d ", frame_index);
105441ae8e74SKuba Mracek     if (recognizer) {
105541ae8e74SKuba Mracek       output_stream << "is recognized by ";
105641ae8e74SKuba Mracek       output_stream << recognizer->GetName();
105741ae8e74SKuba Mracek     } else {
105841ae8e74SKuba Mracek       output_stream << "not recognized by any recognizer";
105941ae8e74SKuba Mracek     }
106041ae8e74SKuba Mracek     output_stream.EOL();
106141ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
106241ae8e74SKuba Mracek     return result.Succeeded();
106341ae8e74SKuba Mracek   }
106441ae8e74SKuba Mracek };
106541ae8e74SKuba Mracek 
106641ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword {
106741ae8e74SKuba Mracek public:
106841ae8e74SKuba Mracek   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
106941ae8e74SKuba Mracek       : CommandObjectMultiword(
107041ae8e74SKuba Mracek             interpreter, "frame recognizer",
107141ae8e74SKuba Mracek             "Commands for editing and viewing frame recognizers.",
107241ae8e74SKuba Mracek             "frame recognizer [<sub-command-options>] ") {
1073a925974bSAdrian Prantl     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1074a925974bSAdrian Prantl                               interpreter)));
107541ae8e74SKuba Mracek     LoadSubCommand(
107641ae8e74SKuba Mracek         "clear",
107741ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
107841ae8e74SKuba Mracek     LoadSubCommand(
107941ae8e74SKuba Mracek         "delete",
108041ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1081a925974bSAdrian Prantl     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1082a925974bSAdrian Prantl                                interpreter)));
1083a925974bSAdrian Prantl     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1084a925974bSAdrian Prantl                                interpreter)));
108541ae8e74SKuba Mracek   }
108641ae8e74SKuba Mracek 
108741ae8e74SKuba Mracek   ~CommandObjectFrameRecognizer() override = default;
108841ae8e74SKuba Mracek };
108941ae8e74SKuba Mracek 
109030fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
109130fdc8d8SChris Lattner 
109230fdc8d8SChris Lattner // CommandObjectMultiwordFrame
109330fdc8d8SChris Lattner 
1094b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1095b9c1b51eSKate Stone     CommandInterpreter &interpreter)
1096a925974bSAdrian Prantl     : CommandObjectMultiword(interpreter, "frame",
1097a925974bSAdrian Prantl                              "Commands for selecting and "
1098b9c1b51eSKate Stone                              "examing the current "
1099b9c1b51eSKate Stone                              "thread's stack frames.",
1100b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
1101b9c1b51eSKate Stone   LoadSubCommand("diagnose",
1102b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1103b9c1b51eSKate Stone   LoadSubCommand("info",
1104b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1105b9c1b51eSKate Stone   LoadSubCommand("select",
1106b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1107b9c1b51eSKate Stone   LoadSubCommand("variable",
1108b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
1109*4e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
1110a925974bSAdrian Prantl   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1111a925974bSAdrian Prantl                                    interpreter)));
111241ae8e74SKuba Mracek #endif
111330fdc8d8SChris Lattner }
111430fdc8d8SChris Lattner 
1115c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1116