130fdc8d8SChris Lattner //===-- CommandObjectFrame.cpp ----------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner // C Includes
1130fdc8d8SChris Lattner // C++ Includes
12de6bd243SJohnny Chen #include <string>
13c8ecc2a9SEugene Zelenko 
1430fdc8d8SChris Lattner // Other libraries and framework includes
1530fdc8d8SChris Lattner // Project includes
16c8ecc2a9SEugene Zelenko #include "CommandObjectFrame.h"
1730fdc8d8SChris Lattner #include "lldb/Core/Debugger.h"
186d56d2ceSJim Ingham #include "lldb/Core/Module.h"
196d56d2ceSJim Ingham #include "lldb/Core/StreamFile.h"
206d56d2ceSJim Ingham #include "lldb/Core/Value.h"
216d56d2ceSJim Ingham #include "lldb/Core/ValueObject.h"
226d56d2ceSJim Ingham #include "lldb/Core/ValueObjectVariable.h"
235548cb50SEnrico Granata #include "lldb/DataFormatters/DataVisualization.h"
244d93b8cdSEnrico Granata #include "lldb/DataFormatters/ValueObjectPrinter.h"
257fb56d0aSGreg Clayton #include "lldb/Host/Host.h"
263eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h"
2730fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h"
2830fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h"
291deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h"
302837b766SJim Ingham #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
31715c2365SGreg Clayton #include "lldb/Interpreter/OptionGroupVariable.h"
32b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h"
336d56d2ceSJim Ingham #include "lldb/Symbol/ClangASTContext.h"
34b9c1b51eSKate Stone #include "lldb/Symbol/CompilerType.h"
356754e04fSEnrico Granata #include "lldb/Symbol/Function.h"
366d56d2ceSJim Ingham #include "lldb/Symbol/ObjectFile.h"
376d56d2ceSJim Ingham #include "lldb/Symbol/SymbolContext.h"
386d56d2ceSJim Ingham #include "lldb/Symbol/Type.h"
396d56d2ceSJim Ingham #include "lldb/Symbol/Variable.h"
406d56d2ceSJim Ingham #include "lldb/Symbol/VariableList.h"
4130fdc8d8SChris Lattner #include "lldb/Target/Process.h"
42b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h"
434740a734SSean Callanan #include "lldb/Target/StopInfo.h"
446d56d2ceSJim Ingham #include "lldb/Target/Target.h"
45b9c1b51eSKate Stone #include "lldb/Target/Thread.h"
46145d95c9SPavel Labath #include "lldb/Utility/Args.h"
474740a734SSean Callanan #include "lldb/Utility/LLDBAssert.h"
48bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
4938d0632eSPavel Labath #include "lldb/Utility/Timer.h"
5030fdc8d8SChris Lattner 
5130fdc8d8SChris Lattner using namespace lldb;
5230fdc8d8SChris Lattner using namespace lldb_private;
5330fdc8d8SChris Lattner 
544740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose
554740a734SSean Callanan 
564740a734SSean Callanan //-------------------------------------------------------------------------
574740a734SSean Callanan // CommandObjectFrameInfo
584740a734SSean Callanan //-------------------------------------------------------------------------
594740a734SSean Callanan 
604740a734SSean Callanan //-------------------------------------------------------------------------
614740a734SSean Callanan // CommandObjectFrameDiagnose
624740a734SSean Callanan //-------------------------------------------------------------------------
634740a734SSean Callanan 
641f0f5b5bSZachary Turner static OptionDefinition g_frame_diag_options[] = {
651f0f5b5bSZachary Turner     // clang-format off
661f0f5b5bSZachary Turner   { LLDB_OPT_SET_1, false, "register", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeRegisterName,    "A register to diagnose." },
671f0f5b5bSZachary Turner   { LLDB_OPT_SET_1, false, "address",  'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddress,         "An address to diagnose." },
681f0f5b5bSZachary Turner   { LLDB_OPT_SET_1, false, "offset",   'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset,          "An optional offset.  Requires --register." }
691f0f5b5bSZachary Turner     // clang-format on
701f0f5b5bSZachary Turner };
711f0f5b5bSZachary Turner 
72b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed {
734740a734SSean Callanan public:
74b9c1b51eSKate Stone   class CommandOptions : public Options {
754740a734SSean Callanan   public:
76b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
774740a734SSean Callanan 
784740a734SSean Callanan     ~CommandOptions() override = default;
794740a734SSean Callanan 
8097206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
81b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
8297206d57SZachary Turner       Status error;
834740a734SSean Callanan       const int short_option = m_getopt_table[option_idx].val;
84b9c1b51eSKate Stone       switch (short_option) {
854740a734SSean Callanan       case 'r':
864740a734SSean Callanan         reg = ConstString(option_arg);
874740a734SSean Callanan         break;
884740a734SSean Callanan 
89b9c1b51eSKate Stone       case 'a': {
90fe11483bSZachary Turner         address.emplace();
91fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *address)) {
924740a734SSean Callanan           address.reset();
93b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid address argument '%s'",
94fe11483bSZachary Turner                                          option_arg.str().c_str());
954740a734SSean Callanan         }
96b9c1b51eSKate Stone       } break;
974740a734SSean Callanan 
98b9c1b51eSKate Stone       case 'o': {
99fe11483bSZachary Turner         offset.emplace();
100fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *offset)) {
1014740a734SSean Callanan           offset.reset();
102b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid offset argument '%s'",
103fe11483bSZachary Turner                                          option_arg.str().c_str());
1044740a734SSean Callanan         }
105b9c1b51eSKate Stone       } break;
1064740a734SSean Callanan 
1074740a734SSean Callanan       default:
108b9c1b51eSKate Stone         error.SetErrorStringWithFormat("invalid short option character '%c'",
109b9c1b51eSKate Stone                                        short_option);
1104740a734SSean Callanan         break;
1114740a734SSean Callanan       }
1124740a734SSean Callanan 
1134740a734SSean Callanan       return error;
1144740a734SSean Callanan     }
1154740a734SSean Callanan 
116b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
1174740a734SSean Callanan       address.reset();
1184740a734SSean Callanan       reg.reset();
1194740a734SSean Callanan       offset.reset();
1204740a734SSean Callanan     }
1214740a734SSean Callanan 
1221f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
12370602439SZachary Turner       return llvm::makeArrayRef(g_frame_diag_options);
1241f0f5b5bSZachary Turner     }
1254740a734SSean Callanan 
1264740a734SSean Callanan     // Options.
1274740a734SSean Callanan     llvm::Optional<lldb::addr_t> address;
1284740a734SSean Callanan     llvm::Optional<ConstString> reg;
1294740a734SSean Callanan     llvm::Optional<int64_t> offset;
1304740a734SSean Callanan   };
1314740a734SSean Callanan 
1324740a734SSean Callanan   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
1334740a734SSean Callanan       : CommandObjectParsed(interpreter, "frame diagnose",
134b9c1b51eSKate Stone                             "Try to determine what path path the current stop "
135b9c1b51eSKate Stone                             "location used to get to a register or address",
136b9c1b51eSKate Stone                             nullptr,
137b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
138b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched |
1394740a734SSean Callanan                                 eCommandProcessMustBePaused),
140b9c1b51eSKate Stone         m_options() {
1414740a734SSean Callanan     CommandArgumentEntry arg;
1424740a734SSean Callanan     CommandArgumentData index_arg;
1434740a734SSean Callanan 
1444740a734SSean Callanan     // Define the first (and only) variant of this arg.
1454740a734SSean Callanan     index_arg.arg_type = eArgTypeFrameIndex;
1464740a734SSean Callanan     index_arg.arg_repetition = eArgRepeatOptional;
1474740a734SSean Callanan 
148b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
149b9c1b51eSKate Stone     // argument entry.
1504740a734SSean Callanan     arg.push_back(index_arg);
1514740a734SSean Callanan 
1524740a734SSean Callanan     // Push the data for the first argument into the m_arguments vector.
1534740a734SSean Callanan     m_arguments.push_back(arg);
1544740a734SSean Callanan   }
1554740a734SSean Callanan 
1564740a734SSean Callanan   ~CommandObjectFrameDiagnose() override = default;
1574740a734SSean Callanan 
158b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
1594740a734SSean Callanan 
1604740a734SSean Callanan protected:
161b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1624740a734SSean Callanan     Thread *thread = m_exe_ctx.GetThreadPtr();
1634740a734SSean Callanan     StackFrameSP frame_sp = thread->GetSelectedFrame();
1644740a734SSean Callanan 
1654740a734SSean Callanan     ValueObjectSP valobj_sp;
1664740a734SSean Callanan 
167b9c1b51eSKate Stone     if (m_options.address.hasValue()) {
168b9c1b51eSKate Stone       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
169b9c1b51eSKate Stone         result.AppendError(
170b9c1b51eSKate Stone             "`frame diagnose --address` is incompatible with other arguments.");
1714740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1724740a734SSean Callanan         return false;
1734740a734SSean Callanan       }
1744740a734SSean Callanan       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
175b9c1b51eSKate Stone     } else if (m_options.reg.hasValue()) {
176b9c1b51eSKate Stone       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
177b9c1b51eSKate Stone           m_options.reg.getValue(), m_options.offset.getValueOr(0));
178b9c1b51eSKate Stone     } else {
1794740a734SSean Callanan       StopInfoSP stop_info_sp = thread->GetStopInfo();
180b9c1b51eSKate Stone       if (!stop_info_sp) {
1814740a734SSean Callanan         result.AppendError("No arguments provided, and no stop info.");
1824740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1834740a734SSean Callanan         return false;
1844740a734SSean Callanan       }
1854740a734SSean Callanan 
1864740a734SSean Callanan       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
1874740a734SSean Callanan     }
1884740a734SSean Callanan 
189b9c1b51eSKate Stone     if (!valobj_sp) {
1904740a734SSean Callanan       result.AppendError("No diagnosis available.");
1914740a734SSean Callanan       result.SetStatus(eReturnStatusFailed);
1924740a734SSean Callanan       return false;
1934740a734SSean Callanan     }
1944740a734SSean Callanan 
1954740a734SSean Callanan 
1963bc714b2SZachary Turner     DumpValueObjectOptions::DeclPrintingHelper helper = [&valobj_sp](
1973bc714b2SZachary Turner         ConstString type, ConstString var, const DumpValueObjectOptions &opts,
1983bc714b2SZachary Turner         Stream &stream) -> bool {
199b9c1b51eSKate Stone       const ValueObject::GetExpressionPathFormat format = ValueObject::
200b9c1b51eSKate Stone           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
2015d1f711aSPavel Labath       const bool qualify_cxx_base_classes = false;
2024740a734SSean Callanan       valobj_sp->GetExpressionPath(stream, qualify_cxx_base_classes, format);
2034740a734SSean Callanan       stream.PutCString(" =");
2044740a734SSean Callanan       return true;
2054740a734SSean Callanan     };
2064740a734SSean Callanan 
2074740a734SSean Callanan     DumpValueObjectOptions options;
2084740a734SSean Callanan     options.SetDeclPrintingHelper(helper);
209b9c1b51eSKate Stone     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
210b9c1b51eSKate Stone                                options);
2114740a734SSean Callanan     printer.PrintValueObject();
2124740a734SSean Callanan 
2134740a734SSean Callanan     return true;
2144740a734SSean Callanan   }
2154740a734SSean Callanan 
2164740a734SSean Callanan protected:
2174740a734SSean Callanan   CommandOptions m_options;
2184740a734SSean Callanan };
2194740a734SSean Callanan 
22030fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo
22130fdc8d8SChris Lattner 
22230fdc8d8SChris Lattner //-------------------------------------------------------------------------
22330fdc8d8SChris Lattner // CommandObjectFrameInfo
22430fdc8d8SChris Lattner //-------------------------------------------------------------------------
22530fdc8d8SChris Lattner 
226b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed {
22730fdc8d8SChris Lattner public:
2287428a18cSKate Stone   CommandObjectFrameInfo(CommandInterpreter &interpreter)
229b9c1b51eSKate Stone       : CommandObjectParsed(
230b9c1b51eSKate Stone             interpreter, "frame info", "List information about the current "
231b9c1b51eSKate Stone                                        "stack frame in the current thread.",
232b9c1b51eSKate Stone             "frame info",
233b9c1b51eSKate Stone             eCommandRequiresFrame | eCommandTryTargetAPILock |
234b9c1b51eSKate Stone                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
23530fdc8d8SChris Lattner 
236c8ecc2a9SEugene Zelenko   ~CommandObjectFrameInfo() override = default;
23730fdc8d8SChris Lattner 
2385a988416SJim Ingham protected:
239b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
240f9fc609fSGreg Clayton     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
24130fdc8d8SChris Lattner     result.SetStatus(eReturnStatusSuccessFinishResult);
24230fdc8d8SChris Lattner     return result.Succeeded();
24330fdc8d8SChris Lattner   }
24430fdc8d8SChris Lattner };
24530fdc8d8SChris Lattner 
24630fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect
24730fdc8d8SChris Lattner 
24830fdc8d8SChris Lattner //-------------------------------------------------------------------------
24930fdc8d8SChris Lattner // CommandObjectFrameSelect
25030fdc8d8SChris Lattner //-------------------------------------------------------------------------
25130fdc8d8SChris Lattner 
2521f0f5b5bSZachary Turner static OptionDefinition g_frame_select_options[] = {
2531f0f5b5bSZachary Turner     // clang-format off
2541f0f5b5bSZachary Turner   { LLDB_OPT_SET_1, false, "relative", 'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "A relative frame index offset from the current frame index." },
2551f0f5b5bSZachary Turner     // clang-format on
2561f0f5b5bSZachary Turner };
2571f0f5b5bSZachary Turner 
258b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed {
25930fdc8d8SChris Lattner public:
260b9c1b51eSKate Stone   class CommandOptions : public Options {
261864174e1SGreg Clayton   public:
262b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
263864174e1SGreg Clayton 
264c8ecc2a9SEugene Zelenko     ~CommandOptions() override = default;
265864174e1SGreg Clayton 
26697206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
267b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
26897206d57SZachary Turner       Status error;
2693bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
270b9c1b51eSKate Stone       switch (short_option) {
271864174e1SGreg Clayton       case 'r':
272fe11483bSZachary Turner         if (option_arg.getAsInteger(0, relative_frame_offset)) {
273fe11483bSZachary Turner           relative_frame_offset = INT32_MIN;
274b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
275fe11483bSZachary Turner                                          option_arg.str().c_str());
276fe11483bSZachary Turner         }
277864174e1SGreg Clayton         break;
278864174e1SGreg Clayton 
279864174e1SGreg Clayton       default:
280b9c1b51eSKate Stone         error.SetErrorStringWithFormat("invalid short option character '%c'",
281b9c1b51eSKate Stone                                        short_option);
282864174e1SGreg Clayton         break;
283864174e1SGreg Clayton       }
284864174e1SGreg Clayton 
285864174e1SGreg Clayton       return error;
286864174e1SGreg Clayton     }
287864174e1SGreg Clayton 
288b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
289864174e1SGreg Clayton       relative_frame_offset = INT32_MIN;
290864174e1SGreg Clayton     }
291864174e1SGreg Clayton 
2921f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
29370602439SZachary Turner       return llvm::makeArrayRef(g_frame_select_options);
2941f0f5b5bSZachary Turner     }
295864174e1SGreg Clayton 
296864174e1SGreg Clayton     int32_t relative_frame_offset;
297864174e1SGreg Clayton   };
298864174e1SGreg Clayton 
2997428a18cSKate Stone   CommandObjectFrameSelect(CommandInterpreter &interpreter)
3007428a18cSKate Stone       : CommandObjectParsed(
301b9c1b51eSKate Stone             interpreter, "frame select", "Select the current stack frame by "
302b9c1b51eSKate Stone                                          "index from within the current thread "
303b9c1b51eSKate Stone                                          "(see 'thread backtrace'.)",
304b9c1b51eSKate Stone             nullptr,
305b9c1b51eSKate Stone             eCommandRequiresThread | eCommandTryTargetAPILock |
306b9c1b51eSKate Stone                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
307b9c1b51eSKate Stone         m_options() {
308405fe67fSCaroline Tice     CommandArgumentEntry arg;
309405fe67fSCaroline Tice     CommandArgumentData index_arg;
310405fe67fSCaroline Tice 
311405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
312405fe67fSCaroline Tice     index_arg.arg_type = eArgTypeFrameIndex;
313864174e1SGreg Clayton     index_arg.arg_repetition = eArgRepeatOptional;
314405fe67fSCaroline Tice 
315b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
316b9c1b51eSKate Stone     // argument entry.
317405fe67fSCaroline Tice     arg.push_back(index_arg);
318405fe67fSCaroline Tice 
319405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
320405fe67fSCaroline Tice     m_arguments.push_back(arg);
32130fdc8d8SChris Lattner   }
32230fdc8d8SChris Lattner 
323c8ecc2a9SEugene Zelenko   ~CommandObjectFrameSelect() override = default;
32430fdc8d8SChris Lattner 
325b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
326864174e1SGreg Clayton 
3275a988416SJim Ingham protected:
328b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
329b9c1b51eSKate Stone     // No need to check "thread" for validity as eCommandRequiresThread ensures
330b9c1b51eSKate Stone     // it is valid
331f9fc609fSGreg Clayton     Thread *thread = m_exe_ctx.GetThreadPtr();
332f9fc609fSGreg Clayton 
333864174e1SGreg Clayton     uint32_t frame_idx = UINT32_MAX;
334b9c1b51eSKate Stone     if (m_options.relative_frame_offset != INT32_MIN) {
335864174e1SGreg Clayton       // The one and only argument is a signed relative frame index
336c14ee32dSGreg Clayton       frame_idx = thread->GetSelectedFrameIndex();
337864174e1SGreg Clayton       if (frame_idx == UINT32_MAX)
338864174e1SGreg Clayton         frame_idx = 0;
339864174e1SGreg Clayton 
340b9c1b51eSKate Stone       if (m_options.relative_frame_offset < 0) {
3413985c8c6SSaleem Abdulrasool         if (static_cast<int32_t>(frame_idx) >= -m_options.relative_frame_offset)
342864174e1SGreg Clayton           frame_idx += m_options.relative_frame_offset;
343b9c1b51eSKate Stone         else {
344b9c1b51eSKate Stone           if (frame_idx == 0) {
34505097246SAdrian Prantl             // If you are already at the bottom of the stack, then just warn
34605097246SAdrian Prantl             // and don't reset the frame.
3477428a18cSKate Stone             result.AppendError("Already at the bottom of the stack.");
348213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
349213b4546SJim Ingham             return false;
350b9c1b51eSKate Stone           } else
351864174e1SGreg Clayton             frame_idx = 0;
352864174e1SGreg Clayton         }
353b9c1b51eSKate Stone       } else if (m_options.relative_frame_offset > 0) {
354b9c1b51eSKate Stone         // I don't want "up 20" where "20" takes you past the top of the stack
355b9c1b51eSKate Stone         // to produce
356b9c1b51eSKate Stone         // an error, but rather to just go to the top.  So I have to count the
357b9c1b51eSKate Stone         // stack here...
358b0c72a5fSJim Ingham         const uint32_t num_frames = thread->GetStackFrameCount();
359b9c1b51eSKate Stone         if (static_cast<int32_t>(num_frames - frame_idx) >
360b9c1b51eSKate Stone             m_options.relative_frame_offset)
361864174e1SGreg Clayton           frame_idx += m_options.relative_frame_offset;
362b9c1b51eSKate Stone         else {
363b9c1b51eSKate Stone           if (frame_idx == num_frames - 1) {
364b9c1b51eSKate Stone             // If we are already at the top of the stack, just warn and don't
365b9c1b51eSKate Stone             // reset the frame.
3667428a18cSKate Stone             result.AppendError("Already at the top of the stack.");
367213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
368213b4546SJim Ingham             return false;
369b9c1b51eSKate Stone           } else
370864174e1SGreg Clayton             frame_idx = num_frames - 1;
371864174e1SGreg Clayton         }
372864174e1SGreg Clayton       }
373b9c1b51eSKate Stone     } else {
374f965cc86SZachary Turner       if (command.GetArgumentCount() > 1) {
375f965cc86SZachary Turner         result.AppendErrorWithFormat(
376f965cc86SZachary Turner             "too many arguments; expected frame-index, saw '%s'.\n",
377867e7d17SZachary Turner             command[0].c_str());
378f965cc86SZachary Turner         m_options.GenerateOptionUsage(
379f965cc86SZachary Turner             result.GetErrorStream(), this,
380f965cc86SZachary Turner             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
381f965cc86SZachary Turner         return false;
382f965cc86SZachary Turner       }
383f965cc86SZachary Turner 
384b9c1b51eSKate Stone       if (command.GetArgumentCount() == 1) {
385f965cc86SZachary Turner         if (command[0].ref.getAsInteger(0, frame_idx)) {
386b9c1b51eSKate Stone           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
387f965cc86SZachary Turner                                        command[0].c_str());
388afbb0af8SJim Ingham           result.SetStatus(eReturnStatusFailed);
389afbb0af8SJim Ingham           return false;
390afbb0af8SJim Ingham         }
391b9c1b51eSKate Stone       } else if (command.GetArgumentCount() == 0) {
39282d4a2b9SJason Molenda         frame_idx = thread->GetSelectedFrameIndex();
393b9c1b51eSKate Stone         if (frame_idx == UINT32_MAX) {
39482d4a2b9SJason Molenda           frame_idx = 0;
39582d4a2b9SJason Molenda         }
396864174e1SGreg Clayton       }
397864174e1SGreg Clayton     }
39830fdc8d8SChris Lattner 
399b9c1b51eSKate Stone     bool success = thread->SetSelectedFrameByIndexNoisily(
400b9c1b51eSKate Stone         frame_idx, result.GetOutputStream());
401b9c1b51eSKate Stone     if (success) {
402f9fc609fSGreg Clayton       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
40330fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
404b9c1b51eSKate Stone     } else {
405b9c1b51eSKate Stone       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
406b9c1b51eSKate Stone                                    frame_idx);
40730fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
40893208b86SJim Ingham     }
40993208b86SJim Ingham 
41093208b86SJim Ingham     return result.Succeeded();
41130fdc8d8SChris Lattner   }
412864174e1SGreg Clayton 
413c8ecc2a9SEugene Zelenko protected:
414864174e1SGreg Clayton   CommandOptions m_options;
415864174e1SGreg Clayton };
416864174e1SGreg Clayton 
4176d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable
4186d56d2ceSJim Ingham //----------------------------------------------------------------------
4196d56d2ceSJim Ingham // List images with associated information
4206d56d2ceSJim Ingham //----------------------------------------------------------------------
421b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed {
4226d56d2ceSJim Ingham public:
4237428a18cSKate Stone   CommandObjectFrameVariable(CommandInterpreter &interpreter)
4247428a18cSKate Stone       : CommandObjectParsed(
425b9c1b51eSKate Stone             interpreter, "frame variable",
426b9c1b51eSKate Stone             "Show variables for the current stack frame. Defaults to all "
4277428a18cSKate Stone             "arguments and local variables in scope. Names of argument, "
4287428a18cSKate Stone             "local, file static and file global variables can be specified. "
429ed8a705cSGreg Clayton             "Children of aggregate variables can be specified such as "
430973cf9e8SJohnny Chen             "'var->child.x'.",
431b9c1b51eSKate Stone             nullptr, eCommandRequiresFrame | eCommandTryTargetAPILock |
432b9c1b51eSKate Stone                          eCommandProcessMustBeLaunched |
4337428a18cSKate Stone                          eCommandProcessMustBePaused | eCommandRequiresProcess),
434e1cfbc79STodd Fiala         m_option_group(),
435b9c1b51eSKate Stone         m_option_variable(
436b9c1b51eSKate Stone             true), // Include the frame specific options by passing "true"
4371deb7962SGreg Clayton         m_option_format(eFormatDefault),
438b9c1b51eSKate Stone         m_varobj_options() {
439405fe67fSCaroline Tice     CommandArgumentEntry arg;
440405fe67fSCaroline Tice     CommandArgumentData var_name_arg;
441405fe67fSCaroline Tice 
442405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
443405fe67fSCaroline Tice     var_name_arg.arg_type = eArgTypeVarName;
444405fe67fSCaroline Tice     var_name_arg.arg_repetition = eArgRepeatStar;
445405fe67fSCaroline Tice 
446b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
447b9c1b51eSKate Stone     // argument entry.
448405fe67fSCaroline Tice     arg.push_back(var_name_arg);
449405fe67fSCaroline Tice 
450405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
451405fe67fSCaroline Tice     m_arguments.push_back(arg);
4522837b766SJim Ingham 
453715c2365SGreg Clayton     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
454b9c1b51eSKate Stone     m_option_group.Append(&m_option_format,
455b9c1b51eSKate Stone                           OptionGroupFormat::OPTION_GROUP_FORMAT |
456b9c1b51eSKate Stone                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
457b9c1b51eSKate Stone                           LLDB_OPT_SET_1);
4582837b766SJim Ingham     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
4592837b766SJim Ingham     m_option_group.Finalize();
4606d56d2ceSJim Ingham   }
4616d56d2ceSJim Ingham 
462c8ecc2a9SEugene Zelenko   ~CommandObjectFrameVariable() override = default;
4636d56d2ceSJim Ingham 
464b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
465f21feadcSGreg Clayton 
466*2443bbd4SRaphael Isemann   int HandleArgumentCompletion(
467*2443bbd4SRaphael Isemann       CompletionRequest &request,
468*2443bbd4SRaphael Isemann       OptionElementVector &opt_element_vector) override {
469f21feadcSGreg Clayton     // Arguments are the standard source file completer.
470*2443bbd4SRaphael Isemann     auto completion_str = request.GetParsedLine()[request.GetCursorIndex()].ref;
471*2443bbd4SRaphael Isemann     completion_str = completion_str.take_front(request.GetCursorCharPosition());
472f21feadcSGreg Clayton 
473*2443bbd4SRaphael Isemann     bool word_complete = request.GetWordComplete();
474b9c1b51eSKate Stone     CommandCompletions::InvokeCommonCompletionCallbacks(
475b9c1b51eSKate Stone         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
476*2443bbd4SRaphael Isemann         completion_str, request.GetMatchStartPoint(),
477*2443bbd4SRaphael Isemann         request.GetMaxReturnElements(), nullptr, word_complete,
478*2443bbd4SRaphael Isemann         request.GetMatches());
479*2443bbd4SRaphael Isemann     request.SetWordComplete(word_complete);
480*2443bbd4SRaphael Isemann     return request.GetMatches().GetSize();
481f21feadcSGreg Clayton   }
4826d56d2ceSJim Ingham 
4835a988416SJim Ingham protected:
48473418dfeSEnrico Granata   llvm::StringRef GetScopeString(VariableSP var_sp) {
48573418dfeSEnrico Granata     if (!var_sp)
48673418dfeSEnrico Granata       return llvm::StringRef::withNullAsEmpty(nullptr);
48773418dfeSEnrico Granata 
48873418dfeSEnrico Granata     switch (var_sp->GetScope()) {
48973418dfeSEnrico Granata     case eValueTypeVariableGlobal:
49073418dfeSEnrico Granata       return "GLOBAL: ";
49173418dfeSEnrico Granata     case eValueTypeVariableStatic:
49273418dfeSEnrico Granata       return "STATIC: ";
49373418dfeSEnrico Granata     case eValueTypeVariableArgument:
49473418dfeSEnrico Granata       return "ARG: ";
49573418dfeSEnrico Granata     case eValueTypeVariableLocal:
49673418dfeSEnrico Granata       return "LOCAL: ";
49773418dfeSEnrico Granata     case eValueTypeVariableThreadLocal:
49873418dfeSEnrico Granata       return "THREAD: ";
49973418dfeSEnrico Granata     default:
50073418dfeSEnrico Granata       break;
50173418dfeSEnrico Granata     }
50273418dfeSEnrico Granata 
50373418dfeSEnrico Granata     return llvm::StringRef::withNullAsEmpty(nullptr);
50473418dfeSEnrico Granata   }
50573418dfeSEnrico Granata 
506b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
50705097246SAdrian Prantl     // No need to check "frame" for validity as eCommandRequiresFrame ensures
50805097246SAdrian Prantl     // it is valid
509b57e4a1bSJason Molenda     StackFrame *frame = m_exe_ctx.GetFramePtr();
5101e49e5e7SJohnny Chen 
511a134cc1bSGreg Clayton     Stream &s = result.GetOutputStream();
5126d56d2ceSJim Ingham 
513b9c1b51eSKate Stone     // Be careful about the stack frame, if any summary formatter runs code, it
51405097246SAdrian Prantl     // might clear the StackFrameList for the thread.  So hold onto a shared
51505097246SAdrian Prantl     // pointer to the frame so it stays alive.
516650543f9SJim Ingham 
517b9c1b51eSKate Stone     VariableList *variable_list =
518b9c1b51eSKate Stone         frame->GetVariableList(m_option_variable.show_globals);
519a134cc1bSGreg Clayton 
5206d56d2ceSJim Ingham     VariableSP var_sp;
5216d56d2ceSJim Ingham     ValueObjectSP valobj_sp;
52278a685aaSJim Ingham 
523061858ceSEnrico Granata     TypeSummaryImplSP summary_format_sp;
52417b11749SEnrico Granata     if (!m_option_variable.summary.IsCurrentValueEmpty())
525b9c1b51eSKate Stone       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
526b9c1b51eSKate Stone           ConstString(m_option_variable.summary.GetCurrentValue()),
527b9c1b51eSKate Stone           summary_format_sp);
52817b11749SEnrico Granata     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
529b9c1b51eSKate Stone       summary_format_sp.reset(new StringSummaryFormat(
530b9c1b51eSKate Stone           TypeSummaryImpl::Flags(),
531b9c1b51eSKate Stone           m_option_variable.summary_string.GetCurrentValue()));
532f9fa6ee5SEnrico Granata 
533b9c1b51eSKate Stone     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
534b9c1b51eSKate Stone         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
535b9c1b51eSKate Stone         summary_format_sp));
536379447a7SEnrico Granata 
537b9c1b51eSKate Stone     const SymbolContext &sym_ctx =
538b9c1b51eSKate Stone         frame->GetSymbolContext(eSymbolContextFunction);
5396754e04fSEnrico Granata     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
5406754e04fSEnrico Granata       m_option_variable.show_globals = true;
5416754e04fSEnrico Granata 
542b9c1b51eSKate Stone     if (variable_list) {
5431deb7962SGreg Clayton       const Format format = m_option_format.GetFormat();
5440c489f58SEnrico Granata       options.SetFormat(format);
5451deb7962SGreg Clayton 
54611eb9c64SZachary Turner       if (!command.empty()) {
54746747022SGreg Clayton         VariableList regex_var_list;
54846747022SGreg Clayton 
54905097246SAdrian Prantl         // If we have any args to the variable command, we will make variable
55005097246SAdrian Prantl         // objects from them...
551f965cc86SZachary Turner         for (auto &entry : command) {
552b9c1b51eSKate Stone           if (m_option_variable.use_regex) {
553c7bece56SGreg Clayton             const size_t regex_start_index = regex_var_list.GetSize();
554f965cc86SZachary Turner             llvm::StringRef name_str = entry.ref;
55595eae423SZachary Turner             RegularExpression regex(name_str);
55695eae423SZachary Turner             if (regex.Compile(name_str)) {
55746747022SGreg Clayton               size_t num_matches = 0;
558b9c1b51eSKate Stone               const size_t num_new_regex_vars =
559b9c1b51eSKate Stone                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
56078a685aaSJim Ingham                                                          num_matches);
561b9c1b51eSKate Stone               if (num_new_regex_vars > 0) {
562b9c1b51eSKate Stone                 for (size_t regex_idx = regex_start_index,
563b9c1b51eSKate Stone                             end_index = regex_var_list.GetSize();
564b9c1b51eSKate Stone                      regex_idx < end_index; ++regex_idx) {
56546747022SGreg Clayton                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
566b9c1b51eSKate Stone                   if (var_sp) {
567b9c1b51eSKate Stone                     valobj_sp = frame->GetValueObjectForFrameVariable(
568b9c1b51eSKate Stone                         var_sp, m_varobj_options.use_dynamic);
569b9c1b51eSKate Stone                     if (valobj_sp) {
57073418dfeSEnrico Granata                       std::string scope_string;
57173418dfeSEnrico Granata                       if (m_option_variable.show_scope)
57273418dfeSEnrico Granata                         scope_string = GetScopeString(var_sp).str();
57373418dfeSEnrico Granata 
57473418dfeSEnrico Granata                       if (!scope_string.empty())
575771ef6d4SMalcolm Parsons                         s.PutCString(scope_string);
57673418dfeSEnrico Granata 
577b9c1b51eSKate Stone                       if (m_option_variable.show_decl &&
578b9c1b51eSKate Stone                           var_sp->GetDeclaration().GetFile()) {
57945ba8543SGreg Clayton                         bool show_fullpaths = false;
58045ba8543SGreg Clayton                         bool show_module = true;
581b9c1b51eSKate Stone                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
582b9c1b51eSKate Stone                                                     show_module))
58346747022SGreg Clayton                           s.PutCString(": ");
58446747022SGreg Clayton                       }
5854d93b8cdSEnrico Granata                       valobj_sp->Dump(result.GetOutputStream(), options);
58646747022SGreg Clayton                     }
58746747022SGreg Clayton                   }
58846747022SGreg Clayton                 }
589b9c1b51eSKate Stone               } else if (num_matches == 0) {
590b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: no variables matched "
591b9c1b51eSKate Stone                                                "the regular expression '%s'.\n",
592f965cc86SZachary Turner                                                entry.c_str());
59346747022SGreg Clayton               }
594b9c1b51eSKate Stone             } else {
59546747022SGreg Clayton               char regex_error[1024];
59646747022SGreg Clayton               if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
59746747022SGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", regex_error);
59846747022SGreg Clayton               else
599b9c1b51eSKate Stone                 result.GetErrorStream().Printf(
600b9c1b51eSKate Stone                     "error: unknown regex error when compiling '%s'\n",
601f965cc86SZachary Turner                     entry.c_str());
60246747022SGreg Clayton             }
603b9c1b51eSKate Stone           } else // No regex, either exact variable names or variable
604b9c1b51eSKate Stone                  // expressions.
60546747022SGreg Clayton           {
60697206d57SZachary Turner             Status error;
607b9c1b51eSKate Stone             uint32_t expr_path_options =
608b9c1b51eSKate Stone                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
60946252398SEnrico Granata                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
61046252398SEnrico Granata                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
6112837b766SJim Ingham             lldb::VariableSP var_sp;
612b9c1b51eSKate Stone             valobj_sp = frame->GetValueForVariableExpressionPath(
613f965cc86SZachary Turner                 entry.ref, m_varobj_options.use_dynamic, expr_path_options,
614b9c1b51eSKate Stone                 var_sp, error);
615b9c1b51eSKate Stone             if (valobj_sp) {
61673418dfeSEnrico Granata               std::string scope_string;
61773418dfeSEnrico Granata               if (m_option_variable.show_scope)
61873418dfeSEnrico Granata                 scope_string = GetScopeString(var_sp).str();
61973418dfeSEnrico Granata 
62073418dfeSEnrico Granata               if (!scope_string.empty())
621771ef6d4SMalcolm Parsons                 s.PutCString(scope_string);
622b9c1b51eSKate Stone               if (m_option_variable.show_decl && var_sp &&
623b9c1b51eSKate Stone                   var_sp->GetDeclaration().GetFile()) {
624a134cc1bSGreg Clayton                 var_sp->GetDeclaration().DumpStopContext(&s, false);
625a134cc1bSGreg Clayton                 s.PutCString(": ");
626a134cc1bSGreg Clayton               }
6270c489f58SEnrico Granata 
6280c489f58SEnrico Granata               options.SetFormat(format);
629b9c1b51eSKate Stone               options.SetVariableFormatDisplayLanguage(
630b9c1b51eSKate Stone                   valobj_sp->GetPreferredDisplayLanguage());
631887062aeSJohnny Chen 
632887062aeSJohnny Chen               Stream &output_stream = result.GetOutputStream();
633f965cc86SZachary Turner               options.SetRootValueObjectName(
634f965cc86SZachary Turner                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
6354d93b8cdSEnrico Granata               valobj_sp->Dump(output_stream, options);
636b9c1b51eSKate Stone             } else {
637c8ecc2a9SEugene Zelenko               const char *error_cstr = error.AsCString(nullptr);
63854979cddSGreg Clayton               if (error_cstr)
63954979cddSGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
64054979cddSGreg Clayton               else
641b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: unable to find any "
642b9c1b51eSKate Stone                                                "variable expression path that "
643b9c1b51eSKate Stone                                                "matches '%s'.\n",
644f965cc86SZachary Turner                                                entry.c_str());
6456d56d2ceSJim Ingham             }
6466d56d2ceSJim Ingham           }
6476d56d2ceSJim Ingham         }
648b9c1b51eSKate Stone       } else // No command arg specified.  Use variable_list, instead.
6496d56d2ceSJim Ingham       {
650c7bece56SGreg Clayton         const size_t num_variables = variable_list->GetSize();
651b9c1b51eSKate Stone         if (num_variables > 0) {
652b9c1b51eSKate Stone           for (size_t i = 0; i < num_variables; i++) {
6531a65ae11SGreg Clayton             var_sp = variable_list->GetVariableAtIndex(i);
654f955efc0SSylvestre Ledru             switch (var_sp->GetScope()) {
655eb236735SJim Ingham             case eValueTypeVariableGlobal:
656eb236735SJim Ingham               if (!m_option_variable.show_globals)
657eb236735SJim Ingham                 continue;
658eb236735SJim Ingham               break;
659eb236735SJim Ingham             case eValueTypeVariableStatic:
660eb236735SJim Ingham               if (!m_option_variable.show_globals)
661eb236735SJim Ingham                 continue;
662eb236735SJim Ingham               break;
663eb236735SJim Ingham             case eValueTypeVariableArgument:
664eb236735SJim Ingham               if (!m_option_variable.show_args)
665eb236735SJim Ingham                 continue;
666eb236735SJim Ingham               break;
667eb236735SJim Ingham             case eValueTypeVariableLocal:
668eb236735SJim Ingham               if (!m_option_variable.show_locals)
669eb236735SJim Ingham                 continue;
670eb236735SJim Ingham               break;
671eb236735SJim Ingham             default:
672eb236735SJim Ingham               continue;
673eb236735SJim Ingham               break;
674eb236735SJim Ingham             }
675560558ebSEnrico Granata             std::string scope_string;
676eb236735SJim Ingham             if (m_option_variable.show_scope)
67773418dfeSEnrico Granata               scope_string = GetScopeString(var_sp).str();
6786d56d2ceSJim Ingham 
67905097246SAdrian Prantl             // Use the variable object code to make sure we are using the same
68005097246SAdrian Prantl             // APIs as the public API will be using...
681b9c1b51eSKate Stone             valobj_sp = frame->GetValueObjectForFrameVariable(
682b9c1b51eSKate Stone                 var_sp, m_varobj_options.use_dynamic);
683b9c1b51eSKate Stone             if (valobj_sp) {
68405097246SAdrian Prantl               // When dumping all variables, don't print any variables that are
68505097246SAdrian Prantl               // not in scope to avoid extra unneeded output
686b9c1b51eSKate Stone               if (valobj_sp->IsInScope()) {
687b9c1b51eSKate Stone                 if (!valobj_sp->GetTargetSP()
688b9c1b51eSKate Stone                          ->GetDisplayRuntimeSupportValues() &&
689c8ecc2a9SEugene Zelenko                     valobj_sp->IsRuntimeSupportValue())
690560558ebSEnrico Granata                   continue;
691560558ebSEnrico Granata 
692560558ebSEnrico Granata                 if (!scope_string.empty())
693771ef6d4SMalcolm Parsons                   s.PutCString(scope_string);
694560558ebSEnrico Granata 
695b9c1b51eSKate Stone                 if (m_option_variable.show_decl &&
696b9c1b51eSKate Stone                     var_sp->GetDeclaration().GetFile()) {
697a134cc1bSGreg Clayton                   var_sp->GetDeclaration().DumpStopContext(&s, false);
698a134cc1bSGreg Clayton                   s.PutCString(": ");
699a134cc1bSGreg Clayton                 }
7000c489f58SEnrico Granata 
7010c489f58SEnrico Granata                 options.SetFormat(format);
702b9c1b51eSKate Stone                 options.SetVariableFormatDisplayLanguage(
703b9c1b51eSKate Stone                     valobj_sp->GetPreferredDisplayLanguage());
704f965cc86SZachary Turner                 options.SetRootValueObjectName(
705f965cc86SZachary Turner                     var_sp ? var_sp->GetName().AsCString() : nullptr);
7064d93b8cdSEnrico Granata                 valobj_sp->Dump(result.GetOutputStream(), options);
707a134cc1bSGreg Clayton               }
708a134cc1bSGreg Clayton             }
7096d56d2ceSJim Ingham           }
7106d56d2ceSJim Ingham         }
7116d56d2ceSJim Ingham       }
7126d56d2ceSJim Ingham       result.SetStatus(eReturnStatusSuccessFinishResult);
7136d56d2ceSJim Ingham     }
71461a80ba6SEnrico Granata 
715b9c1b51eSKate Stone     if (m_interpreter.TruncationWarningNecessary()) {
71661a80ba6SEnrico Granata       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
71761a80ba6SEnrico Granata                                       m_cmd_name.c_str());
71861a80ba6SEnrico Granata       m_interpreter.TruncationWarningGiven();
71961a80ba6SEnrico Granata     }
72061a80ba6SEnrico Granata 
72124fff242SDavide Italiano     // Increment statistics.
72224fff242SDavide Italiano     bool res = result.Succeeded();
7230df817aaSDavide Italiano     Target *target = GetSelectedOrDummyTarget();
72424fff242SDavide Italiano     if (res)
72524fff242SDavide Italiano       target->IncrementStats(StatisticKind::FrameVarSuccess);
72624fff242SDavide Italiano     else
72724fff242SDavide Italiano       target->IncrementStats(StatisticKind::FrameVarFailure);
72824fff242SDavide Italiano     return res;
7296d56d2ceSJim Ingham   }
7306d56d2ceSJim Ingham 
731c8ecc2a9SEugene Zelenko protected:
7322837b766SJim Ingham   OptionGroupOptions m_option_group;
733715c2365SGreg Clayton   OptionGroupVariable m_option_variable;
7341deb7962SGreg Clayton   OptionGroupFormat m_option_format;
7352837b766SJim Ingham   OptionGroupValueObjectDisplay m_varobj_options;
7366d56d2ceSJim Ingham };
7376d56d2ceSJim Ingham 
73830fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
73930fdc8d8SChris Lattner 
74030fdc8d8SChris Lattner //-------------------------------------------------------------------------
74130fdc8d8SChris Lattner // CommandObjectMultiwordFrame
74230fdc8d8SChris Lattner //-------------------------------------------------------------------------
74330fdc8d8SChris Lattner 
744b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
745b9c1b51eSKate Stone     CommandInterpreter &interpreter)
746b9c1b51eSKate Stone     : CommandObjectMultiword(interpreter, "frame", "Commands for selecting and "
747b9c1b51eSKate Stone                                                    "examing the current "
748b9c1b51eSKate Stone                                                    "thread's stack frames.",
749b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
750b9c1b51eSKate Stone   LoadSubCommand("diagnose",
751b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
752b9c1b51eSKate Stone   LoadSubCommand("info",
753b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
754b9c1b51eSKate Stone   LoadSubCommand("select",
755b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
756b9c1b51eSKate Stone   LoadSubCommand("variable",
757b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
75830fdc8d8SChris Lattner }
75930fdc8d8SChris Lattner 
760c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
761