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"
26b9c1b51eSKate Stone #include "lldb/Symbol/CompilerType.h"
276754e04fSEnrico Granata #include "lldb/Symbol/Function.h"
286d56d2ceSJim Ingham #include "lldb/Symbol/ObjectFile.h"
296d56d2ceSJim Ingham #include "lldb/Symbol/SymbolContext.h"
306d56d2ceSJim Ingham #include "lldb/Symbol/Type.h"
316d56d2ceSJim Ingham #include "lldb/Symbol/Variable.h"
326d56d2ceSJim Ingham #include "lldb/Symbol/VariableList.h"
3330fdc8d8SChris Lattner #include "lldb/Target/Process.h"
34b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h"
3541ae8e74SKuba Mracek #include "lldb/Target/StackFrameRecognizer.h"
364740a734SSean Callanan #include "lldb/Target/StopInfo.h"
376d56d2ceSJim Ingham #include "lldb/Target/Target.h"
38b9c1b51eSKate Stone #include "lldb/Target/Thread.h"
39145d95c9SPavel Labath #include "lldb/Utility/Args.h"
404740a734SSean Callanan #include "lldb/Utility/LLDBAssert.h"
41bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
4238d0632eSPavel Labath #include "lldb/Utility/Timer.h"
4330fdc8d8SChris Lattner 
44796ac80bSJonas Devlieghere #include <memory>
45796ac80bSJonas Devlieghere #include <string>
46796ac80bSJonas Devlieghere 
4730fdc8d8SChris Lattner using namespace lldb;
4830fdc8d8SChris Lattner using namespace lldb_private;
4930fdc8d8SChris Lattner 
504740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose
514740a734SSean Callanan 
524740a734SSean Callanan // CommandObjectFrameInfo
534740a734SSean Callanan 
544740a734SSean Callanan // CommandObjectFrameDiagnose
554740a734SSean Callanan 
56ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_diag
57ec67e734SRaphael Isemann #include "CommandOptions.inc"
581f0f5b5bSZachary Turner 
59b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed {
604740a734SSean Callanan public:
61b9c1b51eSKate Stone   class CommandOptions : public Options {
624740a734SSean Callanan   public:
63b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
644740a734SSean Callanan 
654740a734SSean Callanan     ~CommandOptions() override = default;
664740a734SSean Callanan 
6797206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
68b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
6997206d57SZachary Turner       Status error;
704740a734SSean Callanan       const int short_option = m_getopt_table[option_idx].val;
71b9c1b51eSKate Stone       switch (short_option) {
724740a734SSean Callanan       case 'r':
734740a734SSean Callanan         reg = ConstString(option_arg);
744740a734SSean Callanan         break;
754740a734SSean Callanan 
76b9c1b51eSKate Stone       case 'a': {
77fe11483bSZachary Turner         address.emplace();
78fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *address)) {
794740a734SSean Callanan           address.reset();
80b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid address argument '%s'",
81fe11483bSZachary Turner                                          option_arg.str().c_str());
824740a734SSean Callanan         }
83b9c1b51eSKate Stone       } break;
844740a734SSean Callanan 
85b9c1b51eSKate Stone       case 'o': {
86fe11483bSZachary Turner         offset.emplace();
87fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *offset)) {
884740a734SSean Callanan           offset.reset();
89b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid offset argument '%s'",
90fe11483bSZachary Turner                                          option_arg.str().c_str());
914740a734SSean Callanan         }
92b9c1b51eSKate Stone       } break;
934740a734SSean Callanan 
944740a734SSean Callanan       default:
9536162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
964740a734SSean Callanan       }
974740a734SSean Callanan 
984740a734SSean Callanan       return error;
994740a734SSean Callanan     }
1004740a734SSean Callanan 
101b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
1024740a734SSean Callanan       address.reset();
1034740a734SSean Callanan       reg.reset();
1044740a734SSean Callanan       offset.reset();
1054740a734SSean Callanan     }
1064740a734SSean Callanan 
1071f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
10870602439SZachary Turner       return llvm::makeArrayRef(g_frame_diag_options);
1091f0f5b5bSZachary Turner     }
1104740a734SSean Callanan 
1114740a734SSean Callanan     // Options.
1124740a734SSean Callanan     llvm::Optional<lldb::addr_t> address;
1134740a734SSean Callanan     llvm::Optional<ConstString> reg;
1144740a734SSean Callanan     llvm::Optional<int64_t> offset;
1154740a734SSean Callanan   };
1164740a734SSean Callanan 
1174740a734SSean Callanan   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
1184740a734SSean Callanan       : CommandObjectParsed(interpreter, "frame diagnose",
119b9c1b51eSKate Stone                             "Try to determine what path path the current stop "
120b9c1b51eSKate Stone                             "location used to get to a register or address",
121b9c1b51eSKate Stone                             nullptr,
122b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
123b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched |
1244740a734SSean Callanan                                 eCommandProcessMustBePaused),
125b9c1b51eSKate Stone         m_options() {
1264740a734SSean Callanan     CommandArgumentEntry arg;
1274740a734SSean Callanan     CommandArgumentData index_arg;
1284740a734SSean Callanan 
1294740a734SSean Callanan     // Define the first (and only) variant of this arg.
1304740a734SSean Callanan     index_arg.arg_type = eArgTypeFrameIndex;
1314740a734SSean Callanan     index_arg.arg_repetition = eArgRepeatOptional;
1324740a734SSean Callanan 
133b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
134b9c1b51eSKate Stone     // argument entry.
1354740a734SSean Callanan     arg.push_back(index_arg);
1364740a734SSean Callanan 
1374740a734SSean Callanan     // Push the data for the first argument into the m_arguments vector.
1384740a734SSean Callanan     m_arguments.push_back(arg);
1394740a734SSean Callanan   }
1404740a734SSean Callanan 
1414740a734SSean Callanan   ~CommandObjectFrameDiagnose() override = default;
1424740a734SSean Callanan 
143b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
1444740a734SSean Callanan 
1454740a734SSean Callanan protected:
146b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1474740a734SSean Callanan     Thread *thread = m_exe_ctx.GetThreadPtr();
1484740a734SSean Callanan     StackFrameSP frame_sp = thread->GetSelectedFrame();
1494740a734SSean Callanan 
1504740a734SSean Callanan     ValueObjectSP valobj_sp;
1514740a734SSean Callanan 
152b9c1b51eSKate Stone     if (m_options.address.hasValue()) {
153b9c1b51eSKate Stone       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
154b9c1b51eSKate Stone         result.AppendError(
155b9c1b51eSKate Stone             "`frame diagnose --address` is incompatible with other arguments.");
1564740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1574740a734SSean Callanan         return false;
1584740a734SSean Callanan       }
1594740a734SSean Callanan       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
160b9c1b51eSKate Stone     } else if (m_options.reg.hasValue()) {
161b9c1b51eSKate Stone       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
162b9c1b51eSKate Stone           m_options.reg.getValue(), m_options.offset.getValueOr(0));
163b9c1b51eSKate Stone     } else {
1644740a734SSean Callanan       StopInfoSP stop_info_sp = thread->GetStopInfo();
165b9c1b51eSKate Stone       if (!stop_info_sp) {
1664740a734SSean Callanan         result.AppendError("No arguments provided, and no stop info.");
1674740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1684740a734SSean Callanan         return false;
1694740a734SSean Callanan       }
1704740a734SSean Callanan 
1714740a734SSean Callanan       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
1724740a734SSean Callanan     }
1734740a734SSean Callanan 
174b9c1b51eSKate Stone     if (!valobj_sp) {
1754740a734SSean Callanan       result.AppendError("No diagnosis available.");
1764740a734SSean Callanan       result.SetStatus(eReturnStatusFailed);
1774740a734SSean Callanan       return false;
1784740a734SSean Callanan     }
1794740a734SSean Callanan 
180*a925974bSAdrian Prantl     DumpValueObjectOptions::DeclPrintingHelper helper =
181*a925974bSAdrian Prantl         [&valobj_sp](ConstString type, ConstString var,
182*a925974bSAdrian Prantl                      const DumpValueObjectOptions &opts,
1833bc714b2SZachary Turner                      Stream &stream) -> bool {
184b9c1b51eSKate Stone       const ValueObject::GetExpressionPathFormat format = ValueObject::
185b9c1b51eSKate Stone           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
1865d1f711aSPavel Labath       const bool qualify_cxx_base_classes = false;
1874740a734SSean Callanan       valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
1884740a734SSean Callanan       stream.PutCString(" =");
1894740a734SSean Callanan       return true;
1904740a734SSean Callanan     };
1914740a734SSean Callanan 
1924740a734SSean Callanan     DumpValueObjectOptions options;
1934740a734SSean Callanan     options.SetDeclPrintingHelper(helper);
194b9c1b51eSKate Stone     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
195b9c1b51eSKate Stone                                options);
1964740a734SSean Callanan     printer.PrintValueObject();
1974740a734SSean Callanan 
1984740a734SSean Callanan     return true;
1994740a734SSean Callanan   }
2004740a734SSean Callanan 
2014740a734SSean Callanan protected:
2024740a734SSean Callanan   CommandOptions m_options;
2034740a734SSean Callanan };
2044740a734SSean Callanan 
20530fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo
20630fdc8d8SChris Lattner 
20730fdc8d8SChris Lattner // CommandObjectFrameInfo
20830fdc8d8SChris Lattner 
209b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed {
21030fdc8d8SChris Lattner public:
2117428a18cSKate Stone   CommandObjectFrameInfo(CommandInterpreter &interpreter)
212*a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame info",
213*a925974bSAdrian Prantl                             "List information about the current "
214b9c1b51eSKate Stone                             "stack frame in the current thread.",
215b9c1b51eSKate Stone                             "frame info",
216b9c1b51eSKate Stone                             eCommandRequiresFrame | eCommandTryTargetAPILock |
217*a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
218*a925974bSAdrian Prantl                                 eCommandProcessMustBePaused) {}
21930fdc8d8SChris Lattner 
220c8ecc2a9SEugene Zelenko   ~CommandObjectFrameInfo() override = default;
22130fdc8d8SChris Lattner 
2225a988416SJim Ingham protected:
223b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
224f9fc609fSGreg Clayton     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
22530fdc8d8SChris Lattner     result.SetStatus(eReturnStatusSuccessFinishResult);
22630fdc8d8SChris Lattner     return result.Succeeded();
22730fdc8d8SChris Lattner   }
22830fdc8d8SChris Lattner };
22930fdc8d8SChris Lattner 
23030fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect
23130fdc8d8SChris Lattner 
23230fdc8d8SChris Lattner // CommandObjectFrameSelect
23330fdc8d8SChris Lattner 
234ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_select
235ec67e734SRaphael Isemann #include "CommandOptions.inc"
2361f0f5b5bSZachary Turner 
237b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed {
23830fdc8d8SChris Lattner public:
239b9c1b51eSKate Stone   class CommandOptions : public Options {
240864174e1SGreg Clayton   public:
241b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
242864174e1SGreg Clayton 
243c8ecc2a9SEugene Zelenko     ~CommandOptions() override = default;
244864174e1SGreg Clayton 
24597206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
246b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
24797206d57SZachary Turner       Status error;
2483bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
249b9c1b51eSKate Stone       switch (short_option) {
250dab6f074SRaphael Isemann       case 'r': {
251dab6f074SRaphael Isemann         int32_t offset = 0;
252dab6f074SRaphael Isemann         if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
253b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
254fe11483bSZachary Turner                                          option_arg.str().c_str());
255dab6f074SRaphael Isemann         } else
256dab6f074SRaphael Isemann           relative_frame_offset = offset;
2575a039d55SRaphael Isemann         break;
258dab6f074SRaphael Isemann       }
259864174e1SGreg Clayton 
260864174e1SGreg Clayton       default:
26136162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
262864174e1SGreg Clayton       }
263864174e1SGreg Clayton 
264864174e1SGreg Clayton       return error;
265864174e1SGreg Clayton     }
266864174e1SGreg Clayton 
2675a039d55SRaphael Isemann     void OptionParsingStarting(ExecutionContext *execution_context) override {
268dab6f074SRaphael Isemann       relative_frame_offset.reset();
2695a039d55SRaphael Isemann     }
270864174e1SGreg Clayton 
2711f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
27270602439SZachary Turner       return llvm::makeArrayRef(g_frame_select_options);
2731f0f5b5bSZachary Turner     }
274864174e1SGreg Clayton 
275dab6f074SRaphael Isemann     llvm::Optional<int32_t> relative_frame_offset;
276864174e1SGreg Clayton   };
277864174e1SGreg Clayton 
2787428a18cSKate Stone   CommandObjectFrameSelect(CommandInterpreter &interpreter)
279*a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame select",
280*a925974bSAdrian Prantl                             "Select the current stack frame by "
281b9c1b51eSKate Stone                             "index from within the current thread "
282b9c1b51eSKate Stone                             "(see 'thread backtrace'.)",
283b9c1b51eSKate Stone                             nullptr,
284b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
285*a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
286*a925974bSAdrian Prantl                                 eCommandProcessMustBePaused),
287b9c1b51eSKate Stone         m_options() {
288405fe67fSCaroline Tice     CommandArgumentEntry arg;
289405fe67fSCaroline Tice     CommandArgumentData index_arg;
290405fe67fSCaroline Tice 
291405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
292405fe67fSCaroline Tice     index_arg.arg_type = eArgTypeFrameIndex;
293864174e1SGreg Clayton     index_arg.arg_repetition = eArgRepeatOptional;
294405fe67fSCaroline Tice 
295b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
296b9c1b51eSKate Stone     // argument entry.
297405fe67fSCaroline Tice     arg.push_back(index_arg);
298405fe67fSCaroline Tice 
299405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
300405fe67fSCaroline Tice     m_arguments.push_back(arg);
30130fdc8d8SChris Lattner   }
30230fdc8d8SChris Lattner 
303c8ecc2a9SEugene Zelenko   ~CommandObjectFrameSelect() override = default;
30430fdc8d8SChris Lattner 
305b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
306864174e1SGreg Clayton 
3075a988416SJim Ingham protected:
308b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
309b9c1b51eSKate Stone     // No need to check "thread" for validity as eCommandRequiresThread ensures
310b9c1b51eSKate Stone     // it is valid
311f9fc609fSGreg Clayton     Thread *thread = m_exe_ctx.GetThreadPtr();
312f9fc609fSGreg Clayton 
313864174e1SGreg Clayton     uint32_t frame_idx = UINT32_MAX;
314dab6f074SRaphael Isemann     if (m_options.relative_frame_offset.hasValue()) {
315864174e1SGreg Clayton       // The one and only argument is a signed relative frame index
316c14ee32dSGreg Clayton       frame_idx = thread->GetSelectedFrameIndex();
317864174e1SGreg Clayton       if (frame_idx == UINT32_MAX)
318864174e1SGreg Clayton         frame_idx = 0;
319864174e1SGreg Clayton 
320dab6f074SRaphael Isemann       if (*m_options.relative_frame_offset < 0) {
321dab6f074SRaphael Isemann         if (static_cast<int32_t>(frame_idx) >=
322dab6f074SRaphael Isemann             -*m_options.relative_frame_offset)
323dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
324b9c1b51eSKate Stone         else {
325b9c1b51eSKate Stone           if (frame_idx == 0) {
32605097246SAdrian Prantl             // If you are already at the bottom of the stack, then just warn
32705097246SAdrian Prantl             // and don't reset the frame.
3287428a18cSKate Stone             result.AppendError("Already at the bottom of the stack.");
329213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
330213b4546SJim Ingham             return false;
331b9c1b51eSKate Stone           } else
332864174e1SGreg Clayton             frame_idx = 0;
333864174e1SGreg Clayton         }
334dab6f074SRaphael Isemann       } else if (*m_options.relative_frame_offset > 0) {
335b9c1b51eSKate Stone         // I don't want "up 20" where "20" takes you past the top of the stack
336b9c1b51eSKate Stone         // to produce
337b9c1b51eSKate Stone         // an error, but rather to just go to the top.  So I have to count the
338b9c1b51eSKate Stone         // stack here...
339b0c72a5fSJim Ingham         const uint32_t num_frames = thread->GetStackFrameCount();
340b9c1b51eSKate Stone         if (static_cast<int32_t>(num_frames - frame_idx) >
341dab6f074SRaphael Isemann             *m_options.relative_frame_offset)
342dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
343b9c1b51eSKate Stone         else {
344b9c1b51eSKate Stone           if (frame_idx == num_frames - 1) {
345b9c1b51eSKate Stone             // If we are already at the top of the stack, just warn and don't
346b9c1b51eSKate Stone             // reset the frame.
3477428a18cSKate Stone             result.AppendError("Already at the top of the stack.");
348213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
349213b4546SJim Ingham             return false;
350b9c1b51eSKate Stone           } else
351864174e1SGreg Clayton             frame_idx = num_frames - 1;
352864174e1SGreg Clayton         }
353864174e1SGreg Clayton       }
354b9c1b51eSKate Stone     } else {
355f965cc86SZachary Turner       if (command.GetArgumentCount() > 1) {
356f965cc86SZachary Turner         result.AppendErrorWithFormat(
357f965cc86SZachary Turner             "too many arguments; expected frame-index, saw '%s'.\n",
358867e7d17SZachary Turner             command[0].c_str());
359f965cc86SZachary Turner         m_options.GenerateOptionUsage(
360f965cc86SZachary Turner             result.GetErrorStream(), this,
361f965cc86SZachary Turner             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
362f965cc86SZachary Turner         return false;
363f965cc86SZachary Turner       }
364f965cc86SZachary Turner 
365b9c1b51eSKate Stone       if (command.GetArgumentCount() == 1) {
3660d9a201eSRaphael Isemann         if (command[0].ref().getAsInteger(0, frame_idx)) {
367b9c1b51eSKate Stone           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
368f965cc86SZachary Turner                                        command[0].c_str());
369afbb0af8SJim Ingham           result.SetStatus(eReturnStatusFailed);
370afbb0af8SJim Ingham           return false;
371afbb0af8SJim Ingham         }
372b9c1b51eSKate Stone       } else if (command.GetArgumentCount() == 0) {
37382d4a2b9SJason Molenda         frame_idx = thread->GetSelectedFrameIndex();
374b9c1b51eSKate Stone         if (frame_idx == UINT32_MAX) {
37582d4a2b9SJason Molenda           frame_idx = 0;
37682d4a2b9SJason Molenda         }
377864174e1SGreg Clayton       }
378864174e1SGreg Clayton     }
37930fdc8d8SChris Lattner 
380b9c1b51eSKate Stone     bool success = thread->SetSelectedFrameByIndexNoisily(
381b9c1b51eSKate Stone         frame_idx, result.GetOutputStream());
382b9c1b51eSKate Stone     if (success) {
383f9fc609fSGreg Clayton       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
38430fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
385b9c1b51eSKate Stone     } else {
386b9c1b51eSKate Stone       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
387b9c1b51eSKate Stone                                    frame_idx);
38830fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
38993208b86SJim Ingham     }
39093208b86SJim Ingham 
39193208b86SJim Ingham     return result.Succeeded();
39230fdc8d8SChris Lattner   }
393864174e1SGreg Clayton 
394c8ecc2a9SEugene Zelenko protected:
395864174e1SGreg Clayton   CommandOptions m_options;
396864174e1SGreg Clayton };
397864174e1SGreg Clayton 
3986d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable
3996d56d2ceSJim Ingham // List images with associated information
400b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed {
4016d56d2ceSJim Ingham public:
4027428a18cSKate Stone   CommandObjectFrameVariable(CommandInterpreter &interpreter)
4037428a18cSKate Stone       : CommandObjectParsed(
404b9c1b51eSKate Stone             interpreter, "frame variable",
405b9c1b51eSKate Stone             "Show variables for the current stack frame. Defaults to all "
4067428a18cSKate Stone             "arguments and local variables in scope. Names of argument, "
4077428a18cSKate Stone             "local, file static and file global variables can be specified. "
408ed8a705cSGreg Clayton             "Children of aggregate variables can be specified such as "
409285ae0c0SJim Ingham             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
410285ae0c0SJim Ingham             "not invoke operator overloads if they exist, but directly access "
411285ae0c0SJim Ingham             "the specified element.  If you want to trigger operator overloads "
412285ae0c0SJim Ingham             "use the expression command to print the variable instead."
413285ae0c0SJim Ingham             "\nIt is worth noting that except for overloaded "
414285ae0c0SJim Ingham             "operators, when printing local variables 'expr local_var' and "
415285ae0c0SJim Ingham             "'frame var local_var' produce the same "
416285ae0c0SJim Ingham             "results.  However, 'frame variable' is more efficient, since it "
417285ae0c0SJim Ingham             "uses debug information and memory reads directly, rather than "
418285ae0c0SJim Ingham             "parsing and evaluating an expression, which may even involve "
419285ae0c0SJim Ingham             "JITing and running code in the target program.",
420*a925974bSAdrian Prantl             nullptr,
421*a925974bSAdrian Prantl             eCommandRequiresFrame | eCommandTryTargetAPILock |
422*a925974bSAdrian Prantl                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
423*a925974bSAdrian Prantl                 eCommandRequiresProcess),
424e1cfbc79STodd Fiala         m_option_group(),
425b9c1b51eSKate Stone         m_option_variable(
426b9c1b51eSKate Stone             true), // Include the frame specific options by passing "true"
427*a925974bSAdrian Prantl         m_option_format(eFormatDefault), m_varobj_options() {
428405fe67fSCaroline Tice     CommandArgumentEntry arg;
429405fe67fSCaroline Tice     CommandArgumentData var_name_arg;
430405fe67fSCaroline Tice 
431405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
432405fe67fSCaroline Tice     var_name_arg.arg_type = eArgTypeVarName;
433405fe67fSCaroline Tice     var_name_arg.arg_repetition = eArgRepeatStar;
434405fe67fSCaroline Tice 
435b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
436b9c1b51eSKate Stone     // argument entry.
437405fe67fSCaroline Tice     arg.push_back(var_name_arg);
438405fe67fSCaroline Tice 
439405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
440405fe67fSCaroline Tice     m_arguments.push_back(arg);
4412837b766SJim Ingham 
442715c2365SGreg Clayton     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
443b9c1b51eSKate Stone     m_option_group.Append(&m_option_format,
444b9c1b51eSKate Stone                           OptionGroupFormat::OPTION_GROUP_FORMAT |
445b9c1b51eSKate Stone                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
446b9c1b51eSKate Stone                           LLDB_OPT_SET_1);
4472837b766SJim Ingham     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
4482837b766SJim Ingham     m_option_group.Finalize();
4496d56d2ceSJim Ingham   }
4506d56d2ceSJim Ingham 
451c8ecc2a9SEugene Zelenko   ~CommandObjectFrameVariable() override = default;
4526d56d2ceSJim Ingham 
453b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
454f21feadcSGreg Clayton 
455ae34ed2cSRaphael Isemann   void
456ae34ed2cSRaphael Isemann   HandleArgumentCompletion(CompletionRequest &request,
4572443bbd4SRaphael Isemann                            OptionElementVector &opt_element_vector) override {
458f21feadcSGreg Clayton     // Arguments are the standard source file completer.
459b9c1b51eSKate Stone     CommandCompletions::InvokeCommonCompletionCallbacks(
460b9c1b51eSKate Stone         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
461a2e76c0bSRaphael Isemann         request, nullptr);
462f21feadcSGreg Clayton   }
4636d56d2ceSJim Ingham 
4645a988416SJim Ingham protected:
46573418dfeSEnrico Granata   llvm::StringRef GetScopeString(VariableSP var_sp) {
46673418dfeSEnrico Granata     if (!var_sp)
46773418dfeSEnrico Granata       return llvm::StringRef::withNullAsEmpty(nullptr);
46873418dfeSEnrico Granata 
46973418dfeSEnrico Granata     switch (var_sp->GetScope()) {
47073418dfeSEnrico Granata     case eValueTypeVariableGlobal:
47173418dfeSEnrico Granata       return "GLOBAL: ";
47273418dfeSEnrico Granata     case eValueTypeVariableStatic:
47373418dfeSEnrico Granata       return "STATIC: ";
47473418dfeSEnrico Granata     case eValueTypeVariableArgument:
47573418dfeSEnrico Granata       return "ARG: ";
47673418dfeSEnrico Granata     case eValueTypeVariableLocal:
47773418dfeSEnrico Granata       return "LOCAL: ";
47873418dfeSEnrico Granata     case eValueTypeVariableThreadLocal:
47973418dfeSEnrico Granata       return "THREAD: ";
48073418dfeSEnrico Granata     default:
48173418dfeSEnrico Granata       break;
48273418dfeSEnrico Granata     }
48373418dfeSEnrico Granata 
48473418dfeSEnrico Granata     return llvm::StringRef::withNullAsEmpty(nullptr);
48573418dfeSEnrico Granata   }
48673418dfeSEnrico Granata 
487b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
48805097246SAdrian Prantl     // No need to check "frame" for validity as eCommandRequiresFrame ensures
48905097246SAdrian Prantl     // it is valid
490b57e4a1bSJason Molenda     StackFrame *frame = m_exe_ctx.GetFramePtr();
4911e49e5e7SJohnny Chen 
492a134cc1bSGreg Clayton     Stream &s = result.GetOutputStream();
4936d56d2ceSJim Ingham 
494b9c1b51eSKate Stone     // Be careful about the stack frame, if any summary formatter runs code, it
49505097246SAdrian Prantl     // might clear the StackFrameList for the thread.  So hold onto a shared
49605097246SAdrian Prantl     // pointer to the frame so it stays alive.
497650543f9SJim Ingham 
498b9c1b51eSKate Stone     VariableList *variable_list =
499b9c1b51eSKate Stone         frame->GetVariableList(m_option_variable.show_globals);
500a134cc1bSGreg Clayton 
5016d56d2ceSJim Ingham     VariableSP var_sp;
5026d56d2ceSJim Ingham     ValueObjectSP valobj_sp;
50378a685aaSJim Ingham 
504061858ceSEnrico Granata     TypeSummaryImplSP summary_format_sp;
50517b11749SEnrico Granata     if (!m_option_variable.summary.IsCurrentValueEmpty())
506b9c1b51eSKate Stone       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
507b9c1b51eSKate Stone           ConstString(m_option_variable.summary.GetCurrentValue()),
508b9c1b51eSKate Stone           summary_format_sp);
50917b11749SEnrico Granata     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
510796ac80bSJonas Devlieghere       summary_format_sp = std::make_shared<StringSummaryFormat>(
511b9c1b51eSKate Stone           TypeSummaryImpl::Flags(),
512796ac80bSJonas Devlieghere           m_option_variable.summary_string.GetCurrentValue());
513f9fa6ee5SEnrico Granata 
514b9c1b51eSKate Stone     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
515b9c1b51eSKate Stone         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
516b9c1b51eSKate Stone         summary_format_sp));
517379447a7SEnrico Granata 
518b9c1b51eSKate Stone     const SymbolContext &sym_ctx =
519b9c1b51eSKate Stone         frame->GetSymbolContext(eSymbolContextFunction);
5206754e04fSEnrico Granata     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
5216754e04fSEnrico Granata       m_option_variable.show_globals = true;
5226754e04fSEnrico Granata 
523b9c1b51eSKate Stone     if (variable_list) {
5241deb7962SGreg Clayton       const Format format = m_option_format.GetFormat();
5250c489f58SEnrico Granata       options.SetFormat(format);
5261deb7962SGreg Clayton 
52711eb9c64SZachary Turner       if (!command.empty()) {
52846747022SGreg Clayton         VariableList regex_var_list;
52946747022SGreg Clayton 
53005097246SAdrian Prantl         // If we have any args to the variable command, we will make variable
53105097246SAdrian Prantl         // objects from them...
532f965cc86SZachary Turner         for (auto &entry : command) {
533b9c1b51eSKate Stone           if (m_option_variable.use_regex) {
534c7bece56SGreg Clayton             const size_t regex_start_index = regex_var_list.GetSize();
5350d9a201eSRaphael Isemann             llvm::StringRef name_str = entry.ref();
53695eae423SZachary Turner             RegularExpression regex(name_str);
537f9d90bc5SJan Kratochvil             if (regex.IsValid()) {
53846747022SGreg Clayton               size_t num_matches = 0;
539b9c1b51eSKate Stone               const size_t num_new_regex_vars =
540b9c1b51eSKate Stone                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
54178a685aaSJim Ingham                                                          num_matches);
542b9c1b51eSKate Stone               if (num_new_regex_vars > 0) {
543b9c1b51eSKate Stone                 for (size_t regex_idx = regex_start_index,
544b9c1b51eSKate Stone                             end_index = regex_var_list.GetSize();
545b9c1b51eSKate Stone                      regex_idx < end_index; ++regex_idx) {
54646747022SGreg Clayton                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
547b9c1b51eSKate Stone                   if (var_sp) {
548b9c1b51eSKate Stone                     valobj_sp = frame->GetValueObjectForFrameVariable(
549b9c1b51eSKate Stone                         var_sp, m_varobj_options.use_dynamic);
550b9c1b51eSKate Stone                     if (valobj_sp) {
55173418dfeSEnrico Granata                       std::string scope_string;
55273418dfeSEnrico Granata                       if (m_option_variable.show_scope)
55373418dfeSEnrico Granata                         scope_string = GetScopeString(var_sp).str();
55473418dfeSEnrico Granata 
55573418dfeSEnrico Granata                       if (!scope_string.empty())
556771ef6d4SMalcolm Parsons                         s.PutCString(scope_string);
55773418dfeSEnrico Granata 
558b9c1b51eSKate Stone                       if (m_option_variable.show_decl &&
559b9c1b51eSKate Stone                           var_sp->GetDeclaration().GetFile()) {
56045ba8543SGreg Clayton                         bool show_fullpaths = false;
56145ba8543SGreg Clayton                         bool show_module = true;
562b9c1b51eSKate Stone                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
563b9c1b51eSKate Stone                                                     show_module))
56446747022SGreg Clayton                           s.PutCString(": ");
56546747022SGreg Clayton                       }
5664d93b8cdSEnrico Granata                       valobj_sp->Dump(result.GetOutputStream(), options);
56746747022SGreg Clayton                     }
56846747022SGreg Clayton                   }
56946747022SGreg Clayton                 }
570b9c1b51eSKate Stone               } else if (num_matches == 0) {
571b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: no variables matched "
572b9c1b51eSKate Stone                                                "the regular expression '%s'.\n",
573f965cc86SZachary Turner                                                entry.c_str());
57446747022SGreg Clayton               }
575b9c1b51eSKate Stone             } else {
5763af3f1e8SJonas Devlieghere               if (llvm::Error err = regex.GetError())
5773af3f1e8SJonas Devlieghere                 result.GetErrorStream().Printf(
5783af3f1e8SJonas Devlieghere                     "error: %s\n", llvm::toString(std::move(err)).c_str());
57946747022SGreg Clayton               else
580b9c1b51eSKate Stone                 result.GetErrorStream().Printf(
581b9c1b51eSKate Stone                     "error: unknown regex error when compiling '%s'\n",
582f965cc86SZachary Turner                     entry.c_str());
58346747022SGreg Clayton             }
584b9c1b51eSKate Stone           } else // No regex, either exact variable names or variable
585b9c1b51eSKate Stone                  // expressions.
58646747022SGreg Clayton           {
58797206d57SZachary Turner             Status error;
588b9c1b51eSKate Stone             uint32_t expr_path_options =
589b9c1b51eSKate Stone                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
59046252398SEnrico Granata                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
59146252398SEnrico Granata                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
5922837b766SJim Ingham             lldb::VariableSP var_sp;
593b9c1b51eSKate Stone             valobj_sp = frame->GetValueForVariableExpressionPath(
5940d9a201eSRaphael Isemann                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
595b9c1b51eSKate Stone                 var_sp, error);
596b9c1b51eSKate Stone             if (valobj_sp) {
59773418dfeSEnrico Granata               std::string scope_string;
59873418dfeSEnrico Granata               if (m_option_variable.show_scope)
59973418dfeSEnrico Granata                 scope_string = GetScopeString(var_sp).str();
60073418dfeSEnrico Granata 
60173418dfeSEnrico Granata               if (!scope_string.empty())
602771ef6d4SMalcolm Parsons                 s.PutCString(scope_string);
603b9c1b51eSKate Stone               if (m_option_variable.show_decl && var_sp &&
604b9c1b51eSKate Stone                   var_sp->GetDeclaration().GetFile()) {
605a134cc1bSGreg Clayton                 var_sp->GetDeclaration().DumpStopContext(&s, false);
606a134cc1bSGreg Clayton                 s.PutCString(": ");
607a134cc1bSGreg Clayton               }
6080c489f58SEnrico Granata 
6090c489f58SEnrico Granata               options.SetFormat(format);
610b9c1b51eSKate Stone               options.SetVariableFormatDisplayLanguage(
611b9c1b51eSKate Stone                   valobj_sp->GetPreferredDisplayLanguage());
612887062aeSJohnny Chen 
613887062aeSJohnny Chen               Stream &output_stream = result.GetOutputStream();
614f965cc86SZachary Turner               options.SetRootValueObjectName(
615f965cc86SZachary Turner                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
6164d93b8cdSEnrico Granata               valobj_sp->Dump(output_stream, options);
617b9c1b51eSKate Stone             } else {
618c8ecc2a9SEugene Zelenko               const char *error_cstr = error.AsCString(nullptr);
61954979cddSGreg Clayton               if (error_cstr)
62054979cddSGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
62154979cddSGreg Clayton               else
622b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: unable to find any "
623b9c1b51eSKate Stone                                                "variable expression path that "
624b9c1b51eSKate Stone                                                "matches '%s'.\n",
625f965cc86SZachary Turner                                                entry.c_str());
6266d56d2ceSJim Ingham             }
6276d56d2ceSJim Ingham           }
6286d56d2ceSJim Ingham         }
629b9c1b51eSKate Stone       } else // No command arg specified.  Use variable_list, instead.
6306d56d2ceSJim Ingham       {
631c7bece56SGreg Clayton         const size_t num_variables = variable_list->GetSize();
632b9c1b51eSKate Stone         if (num_variables > 0) {
633b9c1b51eSKate Stone           for (size_t i = 0; i < num_variables; i++) {
6341a65ae11SGreg Clayton             var_sp = variable_list->GetVariableAtIndex(i);
635f955efc0SSylvestre Ledru             switch (var_sp->GetScope()) {
636eb236735SJim Ingham             case eValueTypeVariableGlobal:
637eb236735SJim Ingham               if (!m_option_variable.show_globals)
638eb236735SJim Ingham                 continue;
639eb236735SJim Ingham               break;
640eb236735SJim Ingham             case eValueTypeVariableStatic:
641eb236735SJim Ingham               if (!m_option_variable.show_globals)
642eb236735SJim Ingham                 continue;
643eb236735SJim Ingham               break;
644eb236735SJim Ingham             case eValueTypeVariableArgument:
645eb236735SJim Ingham               if (!m_option_variable.show_args)
646eb236735SJim Ingham                 continue;
647eb236735SJim Ingham               break;
648eb236735SJim Ingham             case eValueTypeVariableLocal:
649eb236735SJim Ingham               if (!m_option_variable.show_locals)
650eb236735SJim Ingham                 continue;
651eb236735SJim Ingham               break;
652eb236735SJim Ingham             default:
653eb236735SJim Ingham               continue;
654eb236735SJim Ingham               break;
655eb236735SJim Ingham             }
656560558ebSEnrico Granata             std::string scope_string;
657eb236735SJim Ingham             if (m_option_variable.show_scope)
65873418dfeSEnrico Granata               scope_string = GetScopeString(var_sp).str();
6596d56d2ceSJim Ingham 
66005097246SAdrian Prantl             // Use the variable object code to make sure we are using the same
66105097246SAdrian Prantl             // APIs as the public API will be using...
662b9c1b51eSKate Stone             valobj_sp = frame->GetValueObjectForFrameVariable(
663b9c1b51eSKate Stone                 var_sp, m_varobj_options.use_dynamic);
664b9c1b51eSKate Stone             if (valobj_sp) {
66505097246SAdrian Prantl               // When dumping all variables, don't print any variables that are
66605097246SAdrian Prantl               // not in scope to avoid extra unneeded output
667b9c1b51eSKate Stone               if (valobj_sp->IsInScope()) {
668b9c1b51eSKate Stone                 if (!valobj_sp->GetTargetSP()
669b9c1b51eSKate Stone                          ->GetDisplayRuntimeSupportValues() &&
670c8ecc2a9SEugene Zelenko                     valobj_sp->IsRuntimeSupportValue())
671560558ebSEnrico Granata                   continue;
672560558ebSEnrico Granata 
673560558ebSEnrico Granata                 if (!scope_string.empty())
674771ef6d4SMalcolm Parsons                   s.PutCString(scope_string);
675560558ebSEnrico Granata 
676b9c1b51eSKate Stone                 if (m_option_variable.show_decl &&
677b9c1b51eSKate Stone                     var_sp->GetDeclaration().GetFile()) {
678a134cc1bSGreg Clayton                   var_sp->GetDeclaration().DumpStopContext(&s, false);
679a134cc1bSGreg Clayton                   s.PutCString(": ");
680a134cc1bSGreg Clayton                 }
6810c489f58SEnrico Granata 
6820c489f58SEnrico Granata                 options.SetFormat(format);
683b9c1b51eSKate Stone                 options.SetVariableFormatDisplayLanguage(
684b9c1b51eSKate Stone                     valobj_sp->GetPreferredDisplayLanguage());
685f965cc86SZachary Turner                 options.SetRootValueObjectName(
686f965cc86SZachary Turner                     var_sp ? var_sp->GetName().AsCString() : nullptr);
6874d93b8cdSEnrico Granata                 valobj_sp->Dump(result.GetOutputStream(), options);
688a134cc1bSGreg Clayton               }
689a134cc1bSGreg Clayton             }
6906d56d2ceSJim Ingham           }
6916d56d2ceSJim Ingham         }
6926d56d2ceSJim Ingham       }
6936d56d2ceSJim Ingham       result.SetStatus(eReturnStatusSuccessFinishResult);
6946d56d2ceSJim Ingham     }
69561a80ba6SEnrico Granata 
69641ae8e74SKuba Mracek     if (m_option_variable.show_recognized_args) {
69741ae8e74SKuba Mracek       auto recognized_frame = frame->GetRecognizedFrame();
69841ae8e74SKuba Mracek       if (recognized_frame) {
69941ae8e74SKuba Mracek         ValueObjectListSP recognized_arg_list =
70041ae8e74SKuba Mracek             recognized_frame->GetRecognizedArguments();
70141ae8e74SKuba Mracek         if (recognized_arg_list) {
70241ae8e74SKuba Mracek           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
70341ae8e74SKuba Mracek             options.SetFormat(m_option_format.GetFormat());
70441ae8e74SKuba Mracek             options.SetVariableFormatDisplayLanguage(
70541ae8e74SKuba Mracek                 rec_value_sp->GetPreferredDisplayLanguage());
70641ae8e74SKuba Mracek             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
70741ae8e74SKuba Mracek             rec_value_sp->Dump(result.GetOutputStream(), options);
70841ae8e74SKuba Mracek           }
70941ae8e74SKuba Mracek         }
71041ae8e74SKuba Mracek       }
71141ae8e74SKuba Mracek     }
71241ae8e74SKuba Mracek 
713b9c1b51eSKate Stone     if (m_interpreter.TruncationWarningNecessary()) {
71461a80ba6SEnrico Granata       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
71561a80ba6SEnrico Granata                                       m_cmd_name.c_str());
71661a80ba6SEnrico Granata       m_interpreter.TruncationWarningGiven();
71761a80ba6SEnrico Granata     }
71861a80ba6SEnrico Granata 
71924fff242SDavide Italiano     // Increment statistics.
72024fff242SDavide Italiano     bool res = result.Succeeded();
721cb2380c9SRaphael Isemann     Target &target = GetSelectedOrDummyTarget();
72224fff242SDavide Italiano     if (res)
723cb2380c9SRaphael Isemann       target.IncrementStats(StatisticKind::FrameVarSuccess);
72424fff242SDavide Italiano     else
725cb2380c9SRaphael Isemann       target.IncrementStats(StatisticKind::FrameVarFailure);
72624fff242SDavide Italiano     return res;
7276d56d2ceSJim Ingham   }
7286d56d2ceSJim Ingham 
729c8ecc2a9SEugene Zelenko protected:
7302837b766SJim Ingham   OptionGroupOptions m_option_group;
731715c2365SGreg Clayton   OptionGroupVariable m_option_variable;
7321deb7962SGreg Clayton   OptionGroupFormat m_option_format;
7332837b766SJim Ingham   OptionGroupValueObjectDisplay m_varobj_options;
7346d56d2ceSJim Ingham };
7356d56d2ceSJim Ingham 
73641ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer
73741ae8e74SKuba Mracek 
738ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_recognizer_add
739ec67e734SRaphael Isemann #include "CommandOptions.inc"
74041ae8e74SKuba Mracek 
74141ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
74241ae8e74SKuba Mracek private:
74341ae8e74SKuba Mracek   class CommandOptions : public Options {
74441ae8e74SKuba Mracek   public:
74541ae8e74SKuba Mracek     CommandOptions() : Options() {}
74641ae8e74SKuba Mracek     ~CommandOptions() override = default;
74741ae8e74SKuba Mracek 
74841ae8e74SKuba Mracek     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
74941ae8e74SKuba Mracek                           ExecutionContext *execution_context) override {
75041ae8e74SKuba Mracek       Status error;
75141ae8e74SKuba Mracek       const int short_option = m_getopt_table[option_idx].val;
75241ae8e74SKuba Mracek 
75341ae8e74SKuba Mracek       switch (short_option) {
75441ae8e74SKuba Mracek       case 'l':
75541ae8e74SKuba Mracek         m_class_name = std::string(option_arg);
75641ae8e74SKuba Mracek         break;
75741ae8e74SKuba Mracek       case 's':
75841ae8e74SKuba Mracek         m_module = std::string(option_arg);
75941ae8e74SKuba Mracek         break;
76041ae8e74SKuba Mracek       case 'n':
76141ae8e74SKuba Mracek         m_function = std::string(option_arg);
76241ae8e74SKuba Mracek         break;
76341ae8e74SKuba Mracek       case 'x':
76441ae8e74SKuba Mracek         m_regex = true;
76541ae8e74SKuba Mracek         break;
76641ae8e74SKuba Mracek       default:
76736162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
76841ae8e74SKuba Mracek       }
76941ae8e74SKuba Mracek 
77041ae8e74SKuba Mracek       return error;
77141ae8e74SKuba Mracek     }
77241ae8e74SKuba Mracek 
77341ae8e74SKuba Mracek     void OptionParsingStarting(ExecutionContext *execution_context) override {
77441ae8e74SKuba Mracek       m_module = "";
77541ae8e74SKuba Mracek       m_function = "";
77641ae8e74SKuba Mracek       m_class_name = "";
77741ae8e74SKuba Mracek       m_regex = false;
77841ae8e74SKuba Mracek     }
77941ae8e74SKuba Mracek 
78041ae8e74SKuba Mracek     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
78141ae8e74SKuba Mracek       return llvm::makeArrayRef(g_frame_recognizer_add_options);
78241ae8e74SKuba Mracek     }
78341ae8e74SKuba Mracek 
78441ae8e74SKuba Mracek     // Instance variables to hold the values for command options.
78541ae8e74SKuba Mracek     std::string m_class_name;
78641ae8e74SKuba Mracek     std::string m_module;
78741ae8e74SKuba Mracek     std::string m_function;
78841ae8e74SKuba Mracek     bool m_regex;
78941ae8e74SKuba Mracek   };
79041ae8e74SKuba Mracek 
79141ae8e74SKuba Mracek   CommandOptions m_options;
79241ae8e74SKuba Mracek 
79341ae8e74SKuba Mracek   Options *GetOptions() override { return &m_options; }
79441ae8e74SKuba Mracek 
79541ae8e74SKuba Mracek protected:
79641ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override;
79741ae8e74SKuba Mracek 
79841ae8e74SKuba Mracek public:
79941ae8e74SKuba Mracek   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
80041ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer add",
80141ae8e74SKuba Mracek                             "Add a new frame recognizer.", nullptr),
80241ae8e74SKuba Mracek         m_options() {
80341ae8e74SKuba Mracek     SetHelpLong(R"(
80441ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on
80541ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source
80641ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments
80741ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments.
80841ae8e74SKuba Mracek 
80941ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class
81041ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a
81141ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type
81241ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize.
81341ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that
81441ae8e74SKuba Mracek represent the recognized arguments.
81541ae8e74SKuba Mracek 
81641ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc
81741ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows:
81841ae8e74SKuba Mracek 
81941ae8e74SKuba Mracek   class LibcFdRecognizer(object):
82041ae8e74SKuba Mracek     def get_recognized_arguments(self, frame):
82141ae8e74SKuba Mracek       if frame.name in ["read", "write", "close"]:
82241ae8e74SKuba Mracek         fd = frame.EvaluateExpression("$arg1").unsigned
82341ae8e74SKuba Mracek         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
82441ae8e74SKuba Mracek         return [value]
82541ae8e74SKuba Mracek       return []
82641ae8e74SKuba Mracek 
82741ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script
82841ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'.
82941ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is
83041ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
83141ae8e74SKuba Mracek in other modules:
83241ae8e74SKuba Mracek 
83341ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py
83441ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
83541ae8e74SKuba Mracek 
83641ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we
83741ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable':
83841ae8e74SKuba Mracek 
83941ae8e74SKuba Mracek (lldb) b read
84041ae8e74SKuba Mracek (lldb) r
84141ae8e74SKuba Mracek Process 1234 stopped
84241ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
84341ae8e74SKuba Mracek     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
84441ae8e74SKuba Mracek (lldb) frame variable
84541ae8e74SKuba Mracek (int) fd = 3
84641ae8e74SKuba Mracek 
84741ae8e74SKuba Mracek     )");
84841ae8e74SKuba Mracek   }
84941ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerAdd() override = default;
85041ae8e74SKuba Mracek };
85141ae8e74SKuba Mracek 
85241ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
85341ae8e74SKuba Mracek                                                 CommandReturnObject &result) {
854f80d2655SKuba Mracek #ifndef LLDB_DISABLE_PYTHON
85541ae8e74SKuba Mracek   if (m_options.m_class_name.empty()) {
85641ae8e74SKuba Mracek     result.AppendErrorWithFormat(
85741ae8e74SKuba Mracek         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
85841ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
85941ae8e74SKuba Mracek     return false;
86041ae8e74SKuba Mracek   }
86141ae8e74SKuba Mracek 
86241ae8e74SKuba Mracek   if (m_options.m_module.empty()) {
86341ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
86441ae8e74SKuba Mracek                                  m_cmd_name.c_str());
86541ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
86641ae8e74SKuba Mracek     return false;
86741ae8e74SKuba Mracek   }
86841ae8e74SKuba Mracek 
86941ae8e74SKuba Mracek   if (m_options.m_function.empty()) {
87041ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a function name (-n argument).\n",
87141ae8e74SKuba Mracek                                  m_cmd_name.c_str());
87241ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
87341ae8e74SKuba Mracek     return false;
87441ae8e74SKuba Mracek   }
87541ae8e74SKuba Mracek 
8762b29b432SJonas Devlieghere   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
87741ae8e74SKuba Mracek 
87841ae8e74SKuba Mracek   if (interpreter &&
87941ae8e74SKuba Mracek       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
880*a925974bSAdrian Prantl     result.AppendWarning("The provided class does not exist - please define it "
88141ae8e74SKuba Mracek                          "before attempting to use this frame recognizer");
88241ae8e74SKuba Mracek   }
88341ae8e74SKuba Mracek 
88441ae8e74SKuba Mracek   StackFrameRecognizerSP recognizer_sp =
88541ae8e74SKuba Mracek       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
88641ae8e74SKuba Mracek           interpreter, m_options.m_class_name.c_str()));
88741ae8e74SKuba Mracek   if (m_options.m_regex) {
88841ae8e74SKuba Mracek     auto module =
88941ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_module));
89041ae8e74SKuba Mracek     auto func =
89141ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_function));
89241ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
89341ae8e74SKuba Mracek   } else {
89441ae8e74SKuba Mracek     auto module = ConstString(m_options.m_module);
89541ae8e74SKuba Mracek     auto func = ConstString(m_options.m_function);
89641ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
89741ae8e74SKuba Mracek   }
898f80d2655SKuba Mracek #endif
89941ae8e74SKuba Mracek 
90041ae8e74SKuba Mracek   result.SetStatus(eReturnStatusSuccessFinishNoResult);
90141ae8e74SKuba Mracek   return result.Succeeded();
90241ae8e74SKuba Mracek }
90341ae8e74SKuba Mracek 
90441ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
90541ae8e74SKuba Mracek public:
90641ae8e74SKuba Mracek   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
90741ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer clear",
90841ae8e74SKuba Mracek                             "Delete all frame recognizers.", nullptr) {}
90941ae8e74SKuba Mracek 
91041ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerClear() override = default;
91141ae8e74SKuba Mracek 
91241ae8e74SKuba Mracek protected:
91341ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
91441ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveAllRecognizers();
91541ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
91641ae8e74SKuba Mracek     return result.Succeeded();
91741ae8e74SKuba Mracek   }
91841ae8e74SKuba Mracek };
91941ae8e74SKuba Mracek 
92041ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
92141ae8e74SKuba Mracek public:
92241ae8e74SKuba Mracek   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
92341ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer delete",
92441ae8e74SKuba Mracek                             "Delete an existing frame recognizer.", nullptr) {}
92541ae8e74SKuba Mracek 
92641ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerDelete() override = default;
92741ae8e74SKuba Mracek 
92841ae8e74SKuba Mracek protected:
92941ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
93041ae8e74SKuba Mracek     if (command.GetArgumentCount() == 0) {
93141ae8e74SKuba Mracek       if (!m_interpreter.Confirm(
93241ae8e74SKuba Mracek               "About to delete all frame recognizers, do you want to do that?",
93341ae8e74SKuba Mracek               true)) {
93441ae8e74SKuba Mracek         result.AppendMessage("Operation cancelled...");
93541ae8e74SKuba Mracek         result.SetStatus(eReturnStatusFailed);
93641ae8e74SKuba Mracek         return false;
93741ae8e74SKuba Mracek       }
93841ae8e74SKuba Mracek 
93941ae8e74SKuba Mracek       StackFrameRecognizerManager::RemoveAllRecognizers();
94041ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
94141ae8e74SKuba Mracek       return result.Succeeded();
94241ae8e74SKuba Mracek     }
94341ae8e74SKuba Mracek 
94441ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
94541ae8e74SKuba Mracek       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
94641ae8e74SKuba Mracek                                    m_cmd_name.c_str());
94741ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
94841ae8e74SKuba Mracek       return false;
94941ae8e74SKuba Mracek     }
95041ae8e74SKuba Mracek 
95141ae8e74SKuba Mracek     uint32_t recognizer_id =
95241ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
95341ae8e74SKuba Mracek 
95441ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
95541ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
95641ae8e74SKuba Mracek     return result.Succeeded();
95741ae8e74SKuba Mracek   }
95841ae8e74SKuba Mracek };
95941ae8e74SKuba Mracek 
96041ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed {
96141ae8e74SKuba Mracek public:
96241ae8e74SKuba Mracek   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
96341ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer list",
96441ae8e74SKuba Mracek                             "Show a list of active frame recognizers.",
96541ae8e74SKuba Mracek                             nullptr) {}
96641ae8e74SKuba Mracek 
96741ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerList() override = default;
96841ae8e74SKuba Mracek 
96941ae8e74SKuba Mracek protected:
97041ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
97141ae8e74SKuba Mracek     bool any_printed = false;
97241ae8e74SKuba Mracek     StackFrameRecognizerManager::ForEach(
97341ae8e74SKuba Mracek         [&result, &any_printed](uint32_t recognizer_id, std::string name,
97441ae8e74SKuba Mracek                                 std::string function, std::string symbol,
97541ae8e74SKuba Mracek                                 bool regexp) {
976*a925974bSAdrian Prantl           if (name == "")
977*a925974bSAdrian Prantl             name = "(internal)";
97841ae8e74SKuba Mracek           result.GetOutputStream().Printf(
97941ae8e74SKuba Mracek               "%d: %s, module %s, function %s%s\n", recognizer_id, name.c_str(),
98041ae8e74SKuba Mracek               function.c_str(), symbol.c_str(), regexp ? " (regexp)" : "");
98141ae8e74SKuba Mracek           any_printed = true;
98241ae8e74SKuba Mracek         });
98341ae8e74SKuba Mracek 
98441ae8e74SKuba Mracek     if (any_printed)
98541ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
98641ae8e74SKuba Mracek     else {
98741ae8e74SKuba Mracek       result.GetOutputStream().PutCString("no matching results found.\n");
98841ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishNoResult);
98941ae8e74SKuba Mracek     }
99041ae8e74SKuba Mracek     return result.Succeeded();
99141ae8e74SKuba Mracek   }
99241ae8e74SKuba Mracek };
99341ae8e74SKuba Mracek 
99441ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
99541ae8e74SKuba Mracek public:
99641ae8e74SKuba Mracek   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
99741ae8e74SKuba Mracek       : CommandObjectParsed(
99841ae8e74SKuba Mracek             interpreter, "frame recognizer info",
99941ae8e74SKuba Mracek             "Show which frame recognizer is applied a stack frame (if any).",
100041ae8e74SKuba Mracek             nullptr) {
100141ae8e74SKuba Mracek     CommandArgumentEntry arg;
100241ae8e74SKuba Mracek     CommandArgumentData index_arg;
100341ae8e74SKuba Mracek 
100441ae8e74SKuba Mracek     // Define the first (and only) variant of this arg.
100541ae8e74SKuba Mracek     index_arg.arg_type = eArgTypeFrameIndex;
100641ae8e74SKuba Mracek     index_arg.arg_repetition = eArgRepeatPlain;
100741ae8e74SKuba Mracek 
100841ae8e74SKuba Mracek     // There is only one variant this argument could be; put it into the
100941ae8e74SKuba Mracek     // argument entry.
101041ae8e74SKuba Mracek     arg.push_back(index_arg);
101141ae8e74SKuba Mracek 
101241ae8e74SKuba Mracek     // Push the data for the first argument into the m_arguments vector.
101341ae8e74SKuba Mracek     m_arguments.push_back(arg);
101441ae8e74SKuba Mracek   }
101541ae8e74SKuba Mracek 
101641ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerInfo() override = default;
101741ae8e74SKuba Mracek 
101841ae8e74SKuba Mracek protected:
101941ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
102041ae8e74SKuba Mracek     Process *process = m_exe_ctx.GetProcessPtr();
102141ae8e74SKuba Mracek     if (process == nullptr) {
102241ae8e74SKuba Mracek       result.AppendError("no process");
102341ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
102441ae8e74SKuba Mracek       return false;
102541ae8e74SKuba Mracek     }
102641ae8e74SKuba Mracek     Thread *thread = m_exe_ctx.GetThreadPtr();
102741ae8e74SKuba Mracek     if (thread == nullptr) {
102841ae8e74SKuba Mracek       result.AppendError("no thread");
102941ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
103041ae8e74SKuba Mracek       return false;
103141ae8e74SKuba Mracek     }
103241ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
103341ae8e74SKuba Mracek       result.AppendErrorWithFormat(
103441ae8e74SKuba Mracek           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
103541ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
103641ae8e74SKuba Mracek       return false;
103741ae8e74SKuba Mracek     }
103841ae8e74SKuba Mracek 
103941ae8e74SKuba Mracek     uint32_t frame_index =
104041ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
104141ae8e74SKuba Mracek     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
104241ae8e74SKuba Mracek     if (!frame_sp) {
104341ae8e74SKuba Mracek       result.AppendErrorWithFormat("no frame with index %u", frame_index);
104441ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
104541ae8e74SKuba Mracek       return false;
104641ae8e74SKuba Mracek     }
104741ae8e74SKuba Mracek 
104841ae8e74SKuba Mracek     auto recognizer =
104941ae8e74SKuba Mracek         StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
105041ae8e74SKuba Mracek 
105141ae8e74SKuba Mracek     Stream &output_stream = result.GetOutputStream();
105241ae8e74SKuba Mracek     output_stream.Printf("frame %d ", frame_index);
105341ae8e74SKuba Mracek     if (recognizer) {
105441ae8e74SKuba Mracek       output_stream << "is recognized by ";
105541ae8e74SKuba Mracek       output_stream << recognizer->GetName();
105641ae8e74SKuba Mracek     } else {
105741ae8e74SKuba Mracek       output_stream << "not recognized by any recognizer";
105841ae8e74SKuba Mracek     }
105941ae8e74SKuba Mracek     output_stream.EOL();
106041ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
106141ae8e74SKuba Mracek     return result.Succeeded();
106241ae8e74SKuba Mracek   }
106341ae8e74SKuba Mracek };
106441ae8e74SKuba Mracek 
106541ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword {
106641ae8e74SKuba Mracek public:
106741ae8e74SKuba Mracek   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
106841ae8e74SKuba Mracek       : CommandObjectMultiword(
106941ae8e74SKuba Mracek             interpreter, "frame recognizer",
107041ae8e74SKuba Mracek             "Commands for editing and viewing frame recognizers.",
107141ae8e74SKuba Mracek             "frame recognizer [<sub-command-options>] ") {
1072*a925974bSAdrian Prantl     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1073*a925974bSAdrian Prantl                               interpreter)));
107441ae8e74SKuba Mracek     LoadSubCommand(
107541ae8e74SKuba Mracek         "clear",
107641ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
107741ae8e74SKuba Mracek     LoadSubCommand(
107841ae8e74SKuba Mracek         "delete",
107941ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1080*a925974bSAdrian Prantl     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1081*a925974bSAdrian Prantl                                interpreter)));
1082*a925974bSAdrian Prantl     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1083*a925974bSAdrian Prantl                                interpreter)));
108441ae8e74SKuba Mracek   }
108541ae8e74SKuba Mracek 
108641ae8e74SKuba Mracek   ~CommandObjectFrameRecognizer() override = default;
108741ae8e74SKuba Mracek };
108841ae8e74SKuba Mracek 
108930fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
109030fdc8d8SChris Lattner 
109130fdc8d8SChris Lattner // CommandObjectMultiwordFrame
109230fdc8d8SChris Lattner 
1093b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1094b9c1b51eSKate Stone     CommandInterpreter &interpreter)
1095*a925974bSAdrian Prantl     : CommandObjectMultiword(interpreter, "frame",
1096*a925974bSAdrian Prantl                              "Commands for selecting and "
1097b9c1b51eSKate Stone                              "examing the current "
1098b9c1b51eSKate Stone                              "thread's stack frames.",
1099b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
1100b9c1b51eSKate Stone   LoadSubCommand("diagnose",
1101b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1102b9c1b51eSKate Stone   LoadSubCommand("info",
1103b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1104b9c1b51eSKate Stone   LoadSubCommand("select",
1105b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1106b9c1b51eSKate Stone   LoadSubCommand("variable",
1107b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
110841ae8e74SKuba Mracek #ifndef LLDB_DISABLE_PYTHON
1109*a925974bSAdrian Prantl   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1110*a925974bSAdrian Prantl                                    interpreter)));
111141ae8e74SKuba Mracek #endif
111230fdc8d8SChris Lattner }
111330fdc8d8SChris Lattner 
1114c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1115