180814287SRaphael Isemann //===-- CommandObjectFrame.cpp --------------------------------------------===//
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/ValueObject.h"
115548cb50SEnrico Granata #include "lldb/DataFormatters/DataVisualization.h"
124d93b8cdSEnrico Granata #include "lldb/DataFormatters/ValueObjectPrinter.h"
1359998b7bSJonas Devlieghere #include "lldb/Host/Config.h"
143eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h"
1541ae8e74SKuba Mracek #include "lldb/Host/StringConvert.h"
1630fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h"
1730fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h"
181deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h"
192837b766SJim Ingham #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
20715c2365SGreg Clayton #include "lldb/Interpreter/OptionGroupVariable.h"
21b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h"
226754e04fSEnrico Granata #include "lldb/Symbol/Function.h"
236d56d2ceSJim Ingham #include "lldb/Symbol/SymbolContext.h"
246d56d2ceSJim Ingham #include "lldb/Symbol/Variable.h"
256d56d2ceSJim Ingham #include "lldb/Symbol/VariableList.h"
26b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h"
2741ae8e74SKuba Mracek #include "lldb/Target/StackFrameRecognizer.h"
284740a734SSean Callanan #include "lldb/Target/StopInfo.h"
296d56d2ceSJim Ingham #include "lldb/Target/Target.h"
30b9c1b51eSKate Stone #include "lldb/Target/Thread.h"
31145d95c9SPavel Labath #include "lldb/Utility/Args.h"
3230fdc8d8SChris Lattner 
33796ac80bSJonas Devlieghere #include <memory>
34796ac80bSJonas Devlieghere #include <string>
35796ac80bSJonas Devlieghere 
3630fdc8d8SChris Lattner using namespace lldb;
3730fdc8d8SChris Lattner using namespace lldb_private;
3830fdc8d8SChris Lattner 
394740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose
404740a734SSean Callanan 
414740a734SSean Callanan // CommandObjectFrameInfo
424740a734SSean Callanan 
434740a734SSean Callanan // CommandObjectFrameDiagnose
444740a734SSean Callanan 
45ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_diag
46ec67e734SRaphael Isemann #include "CommandOptions.inc"
471f0f5b5bSZachary Turner 
48b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed {
494740a734SSean Callanan public:
50b9c1b51eSKate Stone   class CommandOptions : public Options {
514740a734SSean Callanan   public:
52b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
534740a734SSean Callanan 
544740a734SSean Callanan     ~CommandOptions() override = default;
554740a734SSean Callanan 
5697206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
57b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
5897206d57SZachary Turner       Status error;
594740a734SSean Callanan       const int short_option = m_getopt_table[option_idx].val;
60b9c1b51eSKate Stone       switch (short_option) {
614740a734SSean Callanan       case 'r':
624740a734SSean Callanan         reg = ConstString(option_arg);
634740a734SSean Callanan         break;
644740a734SSean Callanan 
65b9c1b51eSKate Stone       case 'a': {
66fe11483bSZachary Turner         address.emplace();
67fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *address)) {
684740a734SSean Callanan           address.reset();
69b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid address argument '%s'",
70fe11483bSZachary Turner                                          option_arg.str().c_str());
714740a734SSean Callanan         }
72b9c1b51eSKate Stone       } break;
734740a734SSean Callanan 
74b9c1b51eSKate Stone       case 'o': {
75fe11483bSZachary Turner         offset.emplace();
76fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *offset)) {
774740a734SSean Callanan           offset.reset();
78b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid offset argument '%s'",
79fe11483bSZachary Turner                                          option_arg.str().c_str());
804740a734SSean Callanan         }
81b9c1b51eSKate Stone       } break;
824740a734SSean Callanan 
834740a734SSean Callanan       default:
8436162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
854740a734SSean Callanan       }
864740a734SSean Callanan 
874740a734SSean Callanan       return error;
884740a734SSean Callanan     }
894740a734SSean Callanan 
90b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
914740a734SSean Callanan       address.reset();
924740a734SSean Callanan       reg.reset();
934740a734SSean Callanan       offset.reset();
944740a734SSean Callanan     }
954740a734SSean Callanan 
961f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
9770602439SZachary Turner       return llvm::makeArrayRef(g_frame_diag_options);
981f0f5b5bSZachary Turner     }
994740a734SSean Callanan 
1004740a734SSean Callanan     // Options.
1014740a734SSean Callanan     llvm::Optional<lldb::addr_t> address;
1024740a734SSean Callanan     llvm::Optional<ConstString> reg;
1034740a734SSean Callanan     llvm::Optional<int64_t> offset;
1044740a734SSean Callanan   };
1054740a734SSean Callanan 
1064740a734SSean Callanan   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
1074740a734SSean Callanan       : CommandObjectParsed(interpreter, "frame diagnose",
108b9c1b51eSKate Stone                             "Try to determine what path path the current stop "
109b9c1b51eSKate Stone                             "location used to get to a register or address",
110b9c1b51eSKate Stone                             nullptr,
111b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
112b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched |
1134740a734SSean Callanan                                 eCommandProcessMustBePaused),
114b9c1b51eSKate Stone         m_options() {
1154740a734SSean Callanan     CommandArgumentEntry arg;
1164740a734SSean Callanan     CommandArgumentData index_arg;
1174740a734SSean Callanan 
1184740a734SSean Callanan     // Define the first (and only) variant of this arg.
1194740a734SSean Callanan     index_arg.arg_type = eArgTypeFrameIndex;
1204740a734SSean Callanan     index_arg.arg_repetition = eArgRepeatOptional;
1214740a734SSean Callanan 
122b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
123b9c1b51eSKate Stone     // argument entry.
1244740a734SSean Callanan     arg.push_back(index_arg);
1254740a734SSean Callanan 
1264740a734SSean Callanan     // Push the data for the first argument into the m_arguments vector.
1274740a734SSean Callanan     m_arguments.push_back(arg);
1284740a734SSean Callanan   }
1294740a734SSean Callanan 
1304740a734SSean Callanan   ~CommandObjectFrameDiagnose() override = default;
1314740a734SSean Callanan 
132b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
1334740a734SSean Callanan 
1344740a734SSean Callanan protected:
135b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1364740a734SSean Callanan     Thread *thread = m_exe_ctx.GetThreadPtr();
1374740a734SSean Callanan     StackFrameSP frame_sp = thread->GetSelectedFrame();
1384740a734SSean Callanan 
1394740a734SSean Callanan     ValueObjectSP valobj_sp;
1404740a734SSean Callanan 
141b9c1b51eSKate Stone     if (m_options.address.hasValue()) {
142b9c1b51eSKate Stone       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
143b9c1b51eSKate Stone         result.AppendError(
144b9c1b51eSKate Stone             "`frame diagnose --address` is incompatible with other arguments.");
1454740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1464740a734SSean Callanan         return false;
1474740a734SSean Callanan       }
1484740a734SSean Callanan       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
149b9c1b51eSKate Stone     } else if (m_options.reg.hasValue()) {
150b9c1b51eSKate Stone       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
151b9c1b51eSKate Stone           m_options.reg.getValue(), m_options.offset.getValueOr(0));
152b9c1b51eSKate Stone     } else {
1534740a734SSean Callanan       StopInfoSP stop_info_sp = thread->GetStopInfo();
154b9c1b51eSKate Stone       if (!stop_info_sp) {
1554740a734SSean Callanan         result.AppendError("No arguments provided, and no stop info.");
1564740a734SSean Callanan         result.SetStatus(eReturnStatusFailed);
1574740a734SSean Callanan         return false;
1584740a734SSean Callanan       }
1594740a734SSean Callanan 
1604740a734SSean Callanan       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
1614740a734SSean Callanan     }
1624740a734SSean Callanan 
163b9c1b51eSKate Stone     if (!valobj_sp) {
1644740a734SSean Callanan       result.AppendError("No diagnosis available.");
1654740a734SSean Callanan       result.SetStatus(eReturnStatusFailed);
1664740a734SSean Callanan       return false;
1674740a734SSean Callanan     }
1684740a734SSean Callanan 
169a925974bSAdrian Prantl     DumpValueObjectOptions::DeclPrintingHelper helper =
170a925974bSAdrian Prantl         [&valobj_sp](ConstString type, ConstString var,
171a925974bSAdrian Prantl                      const DumpValueObjectOptions &opts,
1723bc714b2SZachary Turner                      Stream &stream) -> bool {
173b9c1b51eSKate Stone       const ValueObject::GetExpressionPathFormat format = ValueObject::
174b9c1b51eSKate Stone           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
1753014efe0SAlex Langford       valobj_sp->GetExpressionPath(stream, format);
1764740a734SSean Callanan       stream.PutCString(" =");
1774740a734SSean Callanan       return true;
1784740a734SSean Callanan     };
1794740a734SSean Callanan 
1804740a734SSean Callanan     DumpValueObjectOptions options;
1814740a734SSean Callanan     options.SetDeclPrintingHelper(helper);
182b9c1b51eSKate Stone     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
183b9c1b51eSKate Stone                                options);
1844740a734SSean Callanan     printer.PrintValueObject();
1854740a734SSean Callanan 
1864740a734SSean Callanan     return true;
1874740a734SSean Callanan   }
1884740a734SSean Callanan 
1894740a734SSean Callanan   CommandOptions m_options;
1904740a734SSean Callanan };
1914740a734SSean Callanan 
19230fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo
19330fdc8d8SChris Lattner 
19430fdc8d8SChris Lattner // CommandObjectFrameInfo
19530fdc8d8SChris Lattner 
196b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed {
19730fdc8d8SChris Lattner public:
1987428a18cSKate Stone   CommandObjectFrameInfo(CommandInterpreter &interpreter)
199a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame info",
200a925974bSAdrian Prantl                             "List information about the current "
201b9c1b51eSKate Stone                             "stack frame in the current thread.",
202b9c1b51eSKate Stone                             "frame info",
203b9c1b51eSKate Stone                             eCommandRequiresFrame | eCommandTryTargetAPILock |
204a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
205a925974bSAdrian Prantl                                 eCommandProcessMustBePaused) {}
20630fdc8d8SChris Lattner 
207c8ecc2a9SEugene Zelenko   ~CommandObjectFrameInfo() override = default;
20830fdc8d8SChris Lattner 
2095a988416SJim Ingham protected:
210b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
211f9fc609fSGreg Clayton     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
21230fdc8d8SChris Lattner     result.SetStatus(eReturnStatusSuccessFinishResult);
21330fdc8d8SChris Lattner     return result.Succeeded();
21430fdc8d8SChris Lattner   }
21530fdc8d8SChris Lattner };
21630fdc8d8SChris Lattner 
21730fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect
21830fdc8d8SChris Lattner 
21930fdc8d8SChris Lattner // CommandObjectFrameSelect
22030fdc8d8SChris Lattner 
221ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_select
222ec67e734SRaphael Isemann #include "CommandOptions.inc"
2231f0f5b5bSZachary Turner 
224b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed {
22530fdc8d8SChris Lattner public:
226b9c1b51eSKate Stone   class CommandOptions : public Options {
227864174e1SGreg Clayton   public:
228b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
229864174e1SGreg Clayton 
230c8ecc2a9SEugene Zelenko     ~CommandOptions() override = default;
231864174e1SGreg Clayton 
23297206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
233b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
23497206d57SZachary Turner       Status error;
2353bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
236b9c1b51eSKate Stone       switch (short_option) {
237dab6f074SRaphael Isemann       case 'r': {
238dab6f074SRaphael Isemann         int32_t offset = 0;
239dab6f074SRaphael Isemann         if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
240b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
241fe11483bSZachary Turner                                          option_arg.str().c_str());
242dab6f074SRaphael Isemann         } else
243dab6f074SRaphael Isemann           relative_frame_offset = offset;
2445a039d55SRaphael Isemann         break;
245dab6f074SRaphael Isemann       }
246864174e1SGreg Clayton 
247864174e1SGreg Clayton       default:
24836162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
249864174e1SGreg Clayton       }
250864174e1SGreg Clayton 
251864174e1SGreg Clayton       return error;
252864174e1SGreg Clayton     }
253864174e1SGreg Clayton 
2545a039d55SRaphael Isemann     void OptionParsingStarting(ExecutionContext *execution_context) override {
255dab6f074SRaphael Isemann       relative_frame_offset.reset();
2565a039d55SRaphael Isemann     }
257864174e1SGreg Clayton 
2581f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
25970602439SZachary Turner       return llvm::makeArrayRef(g_frame_select_options);
2601f0f5b5bSZachary Turner     }
261864174e1SGreg Clayton 
262dab6f074SRaphael Isemann     llvm::Optional<int32_t> relative_frame_offset;
263864174e1SGreg Clayton   };
264864174e1SGreg Clayton 
2657428a18cSKate Stone   CommandObjectFrameSelect(CommandInterpreter &interpreter)
266a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame select",
267a925974bSAdrian Prantl                             "Select the current stack frame by "
268b9c1b51eSKate Stone                             "index from within the current thread "
269b9c1b51eSKate Stone                             "(see 'thread backtrace'.)",
270b9c1b51eSKate Stone                             nullptr,
271b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
272a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
273a925974bSAdrian Prantl                                 eCommandProcessMustBePaused),
274b9c1b51eSKate Stone         m_options() {
275405fe67fSCaroline Tice     CommandArgumentEntry arg;
276405fe67fSCaroline Tice     CommandArgumentData index_arg;
277405fe67fSCaroline Tice 
278405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
279405fe67fSCaroline Tice     index_arg.arg_type = eArgTypeFrameIndex;
280864174e1SGreg Clayton     index_arg.arg_repetition = eArgRepeatOptional;
281405fe67fSCaroline Tice 
282b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
283b9c1b51eSKate Stone     // argument entry.
284405fe67fSCaroline Tice     arg.push_back(index_arg);
285405fe67fSCaroline Tice 
286405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
287405fe67fSCaroline Tice     m_arguments.push_back(arg);
28830fdc8d8SChris Lattner   }
28930fdc8d8SChris Lattner 
290c8ecc2a9SEugene Zelenko   ~CommandObjectFrameSelect() override = default;
29130fdc8d8SChris Lattner 
292*80eb4228SGongyu Deng   void
293*80eb4228SGongyu Deng   HandleArgumentCompletion(CompletionRequest &request,
294*80eb4228SGongyu Deng                            OptionElementVector &opt_element_vector) override {
295*80eb4228SGongyu Deng     if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
296*80eb4228SGongyu Deng       return;
297*80eb4228SGongyu Deng 
298*80eb4228SGongyu Deng     lldb::ThreadSP thread_sp = m_exe_ctx.GetThreadSP();
299*80eb4228SGongyu Deng     const uint32_t frame_num = thread_sp->GetStackFrameCount();
300*80eb4228SGongyu Deng     for (uint32_t i = 0; i < frame_num; ++i) {
301*80eb4228SGongyu Deng       lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i);
302*80eb4228SGongyu Deng       StreamString strm;
303*80eb4228SGongyu Deng       frame_sp->Dump(&strm, false, true);
304*80eb4228SGongyu Deng       request.TryCompleteCurrentArg(std::to_string(i), strm.GetString());
305*80eb4228SGongyu Deng     }
306*80eb4228SGongyu Deng   }
307*80eb4228SGongyu Deng 
308b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
309864174e1SGreg Clayton 
3105a988416SJim Ingham protected:
311b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
312b9c1b51eSKate Stone     // No need to check "thread" for validity as eCommandRequiresThread ensures
313b9c1b51eSKate Stone     // it is valid
314f9fc609fSGreg Clayton     Thread *thread = m_exe_ctx.GetThreadPtr();
315f9fc609fSGreg Clayton 
316864174e1SGreg Clayton     uint32_t frame_idx = UINT32_MAX;
317dab6f074SRaphael Isemann     if (m_options.relative_frame_offset.hasValue()) {
318864174e1SGreg Clayton       // The one and only argument is a signed relative frame index
319c14ee32dSGreg Clayton       frame_idx = thread->GetSelectedFrameIndex();
320864174e1SGreg Clayton       if (frame_idx == UINT32_MAX)
321864174e1SGreg Clayton         frame_idx = 0;
322864174e1SGreg Clayton 
323dab6f074SRaphael Isemann       if (*m_options.relative_frame_offset < 0) {
324dab6f074SRaphael Isemann         if (static_cast<int32_t>(frame_idx) >=
325dab6f074SRaphael Isemann             -*m_options.relative_frame_offset)
326dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
327b9c1b51eSKate Stone         else {
328b9c1b51eSKate Stone           if (frame_idx == 0) {
32905097246SAdrian Prantl             // If you are already at the bottom of the stack, then just warn
33005097246SAdrian Prantl             // and don't reset the frame.
3317428a18cSKate Stone             result.AppendError("Already at the bottom of the stack.");
332213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
333213b4546SJim Ingham             return false;
334b9c1b51eSKate Stone           } else
335864174e1SGreg Clayton             frame_idx = 0;
336864174e1SGreg Clayton         }
337dab6f074SRaphael Isemann       } else if (*m_options.relative_frame_offset > 0) {
338b9c1b51eSKate Stone         // I don't want "up 20" where "20" takes you past the top of the stack
339b9c1b51eSKate Stone         // to produce
340b9c1b51eSKate Stone         // an error, but rather to just go to the top.  So I have to count the
341b9c1b51eSKate Stone         // stack here...
342b0c72a5fSJim Ingham         const uint32_t num_frames = thread->GetStackFrameCount();
343b9c1b51eSKate Stone         if (static_cast<int32_t>(num_frames - frame_idx) >
344dab6f074SRaphael Isemann             *m_options.relative_frame_offset)
345dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
346b9c1b51eSKate Stone         else {
347b9c1b51eSKate Stone           if (frame_idx == num_frames - 1) {
348b9c1b51eSKate Stone             // If we are already at the top of the stack, just warn and don't
349b9c1b51eSKate Stone             // reset the frame.
3507428a18cSKate Stone             result.AppendError("Already at the top of the stack.");
351213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
352213b4546SJim Ingham             return false;
353b9c1b51eSKate Stone           } else
354864174e1SGreg Clayton             frame_idx = num_frames - 1;
355864174e1SGreg Clayton         }
356864174e1SGreg Clayton       }
357b9c1b51eSKate Stone     } else {
358f965cc86SZachary Turner       if (command.GetArgumentCount() > 1) {
359f965cc86SZachary Turner         result.AppendErrorWithFormat(
360f965cc86SZachary Turner             "too many arguments; expected frame-index, saw '%s'.\n",
361867e7d17SZachary Turner             command[0].c_str());
362f965cc86SZachary Turner         m_options.GenerateOptionUsage(
363f965cc86SZachary Turner             result.GetErrorStream(), this,
364f965cc86SZachary Turner             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
365f965cc86SZachary Turner         return false;
366f965cc86SZachary Turner       }
367f965cc86SZachary Turner 
368b9c1b51eSKate Stone       if (command.GetArgumentCount() == 1) {
3690d9a201eSRaphael Isemann         if (command[0].ref().getAsInteger(0, frame_idx)) {
370b9c1b51eSKate Stone           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
371f965cc86SZachary Turner                                        command[0].c_str());
372afbb0af8SJim Ingham           result.SetStatus(eReturnStatusFailed);
373afbb0af8SJim Ingham           return false;
374afbb0af8SJim Ingham         }
375b9c1b51eSKate Stone       } else if (command.GetArgumentCount() == 0) {
37682d4a2b9SJason Molenda         frame_idx = thread->GetSelectedFrameIndex();
377b9c1b51eSKate Stone         if (frame_idx == UINT32_MAX) {
37882d4a2b9SJason Molenda           frame_idx = 0;
37982d4a2b9SJason Molenda         }
380864174e1SGreg Clayton       }
381864174e1SGreg Clayton     }
38230fdc8d8SChris Lattner 
383b9c1b51eSKate Stone     bool success = thread->SetSelectedFrameByIndexNoisily(
384b9c1b51eSKate Stone         frame_idx, result.GetOutputStream());
385b9c1b51eSKate Stone     if (success) {
386f9fc609fSGreg Clayton       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
38730fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
388b9c1b51eSKate Stone     } else {
389b9c1b51eSKate Stone       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
390b9c1b51eSKate Stone                                    frame_idx);
39130fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
39293208b86SJim Ingham     }
39393208b86SJim Ingham 
39493208b86SJim Ingham     return result.Succeeded();
39530fdc8d8SChris Lattner   }
396864174e1SGreg Clayton 
397864174e1SGreg Clayton   CommandOptions m_options;
398864174e1SGreg Clayton };
399864174e1SGreg Clayton 
4006d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable
4016d56d2ceSJim Ingham // List images with associated information
402b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed {
4036d56d2ceSJim Ingham public:
4047428a18cSKate Stone   CommandObjectFrameVariable(CommandInterpreter &interpreter)
4057428a18cSKate Stone       : CommandObjectParsed(
406b9c1b51eSKate Stone             interpreter, "frame variable",
407b9c1b51eSKate Stone             "Show variables for the current stack frame. Defaults to all "
4087428a18cSKate Stone             "arguments and local variables in scope. Names of argument, "
4097428a18cSKate Stone             "local, file static and file global variables can be specified. "
410ed8a705cSGreg Clayton             "Children of aggregate variables can be specified such as "
411285ae0c0SJim Ingham             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
412285ae0c0SJim Ingham             "not invoke operator overloads if they exist, but directly access "
413285ae0c0SJim Ingham             "the specified element.  If you want to trigger operator overloads "
414285ae0c0SJim Ingham             "use the expression command to print the variable instead."
415285ae0c0SJim Ingham             "\nIt is worth noting that except for overloaded "
416285ae0c0SJim Ingham             "operators, when printing local variables 'expr local_var' and "
417285ae0c0SJim Ingham             "'frame var local_var' produce the same "
418285ae0c0SJim Ingham             "results.  However, 'frame variable' is more efficient, since it "
419285ae0c0SJim Ingham             "uses debug information and memory reads directly, rather than "
420285ae0c0SJim Ingham             "parsing and evaluating an expression, which may even involve "
421285ae0c0SJim Ingham             "JITing and running code in the target program.",
422a925974bSAdrian Prantl             nullptr,
423a925974bSAdrian Prantl             eCommandRequiresFrame | eCommandTryTargetAPILock |
424a925974bSAdrian Prantl                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
425a925974bSAdrian Prantl                 eCommandRequiresProcess),
426e1cfbc79STodd Fiala         m_option_group(),
427b9c1b51eSKate Stone         m_option_variable(
428b9c1b51eSKate Stone             true), // Include the frame specific options by passing "true"
429a925974bSAdrian Prantl         m_option_format(eFormatDefault), m_varobj_options() {
430405fe67fSCaroline Tice     CommandArgumentEntry arg;
431405fe67fSCaroline Tice     CommandArgumentData var_name_arg;
432405fe67fSCaroline Tice 
433405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
434405fe67fSCaroline Tice     var_name_arg.arg_type = eArgTypeVarName;
435405fe67fSCaroline Tice     var_name_arg.arg_repetition = eArgRepeatStar;
436405fe67fSCaroline Tice 
437b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
438b9c1b51eSKate Stone     // argument entry.
439405fe67fSCaroline Tice     arg.push_back(var_name_arg);
440405fe67fSCaroline Tice 
441405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
442405fe67fSCaroline Tice     m_arguments.push_back(arg);
4432837b766SJim Ingham 
444715c2365SGreg Clayton     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
445b9c1b51eSKate Stone     m_option_group.Append(&m_option_format,
446b9c1b51eSKate Stone                           OptionGroupFormat::OPTION_GROUP_FORMAT |
447b9c1b51eSKate Stone                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
448b9c1b51eSKate Stone                           LLDB_OPT_SET_1);
4492837b766SJim Ingham     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
4502837b766SJim Ingham     m_option_group.Finalize();
4516d56d2ceSJim Ingham   }
4526d56d2ceSJim Ingham 
453c8ecc2a9SEugene Zelenko   ~CommandObjectFrameVariable() override = default;
4546d56d2ceSJim Ingham 
455b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
456f21feadcSGreg Clayton 
457ae34ed2cSRaphael Isemann   void
458ae34ed2cSRaphael Isemann   HandleArgumentCompletion(CompletionRequest &request,
4592443bbd4SRaphael Isemann                            OptionElementVector &opt_element_vector) override {
460f21feadcSGreg Clayton     // Arguments are the standard source file completer.
461b9c1b51eSKate Stone     CommandCompletions::InvokeCommonCompletionCallbacks(
462b9c1b51eSKate Stone         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
463a2e76c0bSRaphael Isemann         request, nullptr);
464f21feadcSGreg Clayton   }
4656d56d2ceSJim Ingham 
4665a988416SJim Ingham protected:
46773418dfeSEnrico Granata   llvm::StringRef GetScopeString(VariableSP var_sp) {
46873418dfeSEnrico Granata     if (!var_sp)
46973418dfeSEnrico Granata       return llvm::StringRef::withNullAsEmpty(nullptr);
47073418dfeSEnrico Granata 
47173418dfeSEnrico Granata     switch (var_sp->GetScope()) {
47273418dfeSEnrico Granata     case eValueTypeVariableGlobal:
47373418dfeSEnrico Granata       return "GLOBAL: ";
47473418dfeSEnrico Granata     case eValueTypeVariableStatic:
47573418dfeSEnrico Granata       return "STATIC: ";
47673418dfeSEnrico Granata     case eValueTypeVariableArgument:
47773418dfeSEnrico Granata       return "ARG: ";
47873418dfeSEnrico Granata     case eValueTypeVariableLocal:
47973418dfeSEnrico Granata       return "LOCAL: ";
48073418dfeSEnrico Granata     case eValueTypeVariableThreadLocal:
48173418dfeSEnrico Granata       return "THREAD: ";
48273418dfeSEnrico Granata     default:
48373418dfeSEnrico Granata       break;
48473418dfeSEnrico Granata     }
48573418dfeSEnrico Granata 
48673418dfeSEnrico Granata     return llvm::StringRef::withNullAsEmpty(nullptr);
48773418dfeSEnrico Granata   }
48873418dfeSEnrico Granata 
489b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
49005097246SAdrian Prantl     // No need to check "frame" for validity as eCommandRequiresFrame ensures
49105097246SAdrian Prantl     // it is valid
492b57e4a1bSJason Molenda     StackFrame *frame = m_exe_ctx.GetFramePtr();
4931e49e5e7SJohnny Chen 
494a134cc1bSGreg Clayton     Stream &s = result.GetOutputStream();
4956d56d2ceSJim Ingham 
496b9c1b51eSKate Stone     // Be careful about the stack frame, if any summary formatter runs code, it
49705097246SAdrian Prantl     // might clear the StackFrameList for the thread.  So hold onto a shared
49805097246SAdrian Prantl     // pointer to the frame so it stays alive.
499650543f9SJim Ingham 
500b9c1b51eSKate Stone     VariableList *variable_list =
501b9c1b51eSKate Stone         frame->GetVariableList(m_option_variable.show_globals);
502a134cc1bSGreg Clayton 
5036d56d2ceSJim Ingham     VariableSP var_sp;
5046d56d2ceSJim Ingham     ValueObjectSP valobj_sp;
50578a685aaSJim Ingham 
506061858ceSEnrico Granata     TypeSummaryImplSP summary_format_sp;
50717b11749SEnrico Granata     if (!m_option_variable.summary.IsCurrentValueEmpty())
508b9c1b51eSKate Stone       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
509b9c1b51eSKate Stone           ConstString(m_option_variable.summary.GetCurrentValue()),
510b9c1b51eSKate Stone           summary_format_sp);
51117b11749SEnrico Granata     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
512796ac80bSJonas Devlieghere       summary_format_sp = std::make_shared<StringSummaryFormat>(
513b9c1b51eSKate Stone           TypeSummaryImpl::Flags(),
514796ac80bSJonas Devlieghere           m_option_variable.summary_string.GetCurrentValue());
515f9fa6ee5SEnrico Granata 
516b9c1b51eSKate Stone     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
517b9c1b51eSKate Stone         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
518b9c1b51eSKate Stone         summary_format_sp));
519379447a7SEnrico Granata 
520b9c1b51eSKate Stone     const SymbolContext &sym_ctx =
521b9c1b51eSKate Stone         frame->GetSymbolContext(eSymbolContextFunction);
5226754e04fSEnrico Granata     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
5236754e04fSEnrico Granata       m_option_variable.show_globals = true;
5246754e04fSEnrico Granata 
525b9c1b51eSKate Stone     if (variable_list) {
5261deb7962SGreg Clayton       const Format format = m_option_format.GetFormat();
5270c489f58SEnrico Granata       options.SetFormat(format);
5281deb7962SGreg Clayton 
52911eb9c64SZachary Turner       if (!command.empty()) {
53046747022SGreg Clayton         VariableList regex_var_list;
53146747022SGreg Clayton 
53205097246SAdrian Prantl         // If we have any args to the variable command, we will make variable
53305097246SAdrian Prantl         // objects from them...
534f965cc86SZachary Turner         for (auto &entry : command) {
535b9c1b51eSKate Stone           if (m_option_variable.use_regex) {
536c7bece56SGreg Clayton             const size_t regex_start_index = regex_var_list.GetSize();
5370d9a201eSRaphael Isemann             llvm::StringRef name_str = entry.ref();
53895eae423SZachary Turner             RegularExpression regex(name_str);
539f9d90bc5SJan Kratochvil             if (regex.IsValid()) {
54046747022SGreg Clayton               size_t num_matches = 0;
541b9c1b51eSKate Stone               const size_t num_new_regex_vars =
542b9c1b51eSKate Stone                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
54378a685aaSJim Ingham                                                          num_matches);
544b9c1b51eSKate Stone               if (num_new_regex_vars > 0) {
545b9c1b51eSKate Stone                 for (size_t regex_idx = regex_start_index,
546b9c1b51eSKate Stone                             end_index = regex_var_list.GetSize();
547b9c1b51eSKate Stone                      regex_idx < end_index; ++regex_idx) {
54846747022SGreg Clayton                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
549b9c1b51eSKate Stone                   if (var_sp) {
550b9c1b51eSKate Stone                     valobj_sp = frame->GetValueObjectForFrameVariable(
551b9c1b51eSKate Stone                         var_sp, m_varobj_options.use_dynamic);
552b9c1b51eSKate Stone                     if (valobj_sp) {
55373418dfeSEnrico Granata                       std::string scope_string;
55473418dfeSEnrico Granata                       if (m_option_variable.show_scope)
55573418dfeSEnrico Granata                         scope_string = GetScopeString(var_sp).str();
55673418dfeSEnrico Granata 
55773418dfeSEnrico Granata                       if (!scope_string.empty())
558771ef6d4SMalcolm Parsons                         s.PutCString(scope_string);
55973418dfeSEnrico Granata 
560b9c1b51eSKate Stone                       if (m_option_variable.show_decl &&
561b9c1b51eSKate Stone                           var_sp->GetDeclaration().GetFile()) {
56245ba8543SGreg Clayton                         bool show_fullpaths = false;
56345ba8543SGreg Clayton                         bool show_module = true;
564b9c1b51eSKate Stone                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
565b9c1b51eSKate Stone                                                     show_module))
56646747022SGreg Clayton                           s.PutCString(": ");
56746747022SGreg Clayton                       }
5684d93b8cdSEnrico Granata                       valobj_sp->Dump(result.GetOutputStream(), options);
56946747022SGreg Clayton                     }
57046747022SGreg Clayton                   }
57146747022SGreg Clayton                 }
572b9c1b51eSKate Stone               } else if (num_matches == 0) {
573b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: no variables matched "
574b9c1b51eSKate Stone                                                "the regular expression '%s'.\n",
575f965cc86SZachary Turner                                                entry.c_str());
57646747022SGreg Clayton               }
577b9c1b51eSKate Stone             } else {
5783af3f1e8SJonas Devlieghere               if (llvm::Error err = regex.GetError())
5793af3f1e8SJonas Devlieghere                 result.GetErrorStream().Printf(
5803af3f1e8SJonas Devlieghere                     "error: %s\n", llvm::toString(std::move(err)).c_str());
58146747022SGreg Clayton               else
582b9c1b51eSKate Stone                 result.GetErrorStream().Printf(
583b9c1b51eSKate Stone                     "error: unknown regex error when compiling '%s'\n",
584f965cc86SZachary Turner                     entry.c_str());
58546747022SGreg Clayton             }
586b9c1b51eSKate Stone           } else // No regex, either exact variable names or variable
587b9c1b51eSKate Stone                  // expressions.
58846747022SGreg Clayton           {
58997206d57SZachary Turner             Status error;
590b9c1b51eSKate Stone             uint32_t expr_path_options =
591b9c1b51eSKate Stone                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
59246252398SEnrico Granata                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
59346252398SEnrico Granata                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
5942837b766SJim Ingham             lldb::VariableSP var_sp;
595b9c1b51eSKate Stone             valobj_sp = frame->GetValueForVariableExpressionPath(
5960d9a201eSRaphael Isemann                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
597b9c1b51eSKate Stone                 var_sp, error);
598b9c1b51eSKate Stone             if (valobj_sp) {
59973418dfeSEnrico Granata               std::string scope_string;
60073418dfeSEnrico Granata               if (m_option_variable.show_scope)
60173418dfeSEnrico Granata                 scope_string = GetScopeString(var_sp).str();
60273418dfeSEnrico Granata 
60373418dfeSEnrico Granata               if (!scope_string.empty())
604771ef6d4SMalcolm Parsons                 s.PutCString(scope_string);
605b9c1b51eSKate Stone               if (m_option_variable.show_decl && var_sp &&
606b9c1b51eSKate Stone                   var_sp->GetDeclaration().GetFile()) {
607a134cc1bSGreg Clayton                 var_sp->GetDeclaration().DumpStopContext(&s, false);
608a134cc1bSGreg Clayton                 s.PutCString(": ");
609a134cc1bSGreg Clayton               }
6100c489f58SEnrico Granata 
6110c489f58SEnrico Granata               options.SetFormat(format);
612b9c1b51eSKate Stone               options.SetVariableFormatDisplayLanguage(
613b9c1b51eSKate Stone                   valobj_sp->GetPreferredDisplayLanguage());
614887062aeSJohnny Chen 
615887062aeSJohnny Chen               Stream &output_stream = result.GetOutputStream();
616f965cc86SZachary Turner               options.SetRootValueObjectName(
617f965cc86SZachary Turner                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
6184d93b8cdSEnrico Granata               valobj_sp->Dump(output_stream, options);
619b9c1b51eSKate Stone             } else {
620c8ecc2a9SEugene Zelenko               const char *error_cstr = error.AsCString(nullptr);
62154979cddSGreg Clayton               if (error_cstr)
62254979cddSGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
62354979cddSGreg Clayton               else
624b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: unable to find any "
625b9c1b51eSKate Stone                                                "variable expression path that "
626b9c1b51eSKate Stone                                                "matches '%s'.\n",
627f965cc86SZachary Turner                                                entry.c_str());
6286d56d2ceSJim Ingham             }
6296d56d2ceSJim Ingham           }
6306d56d2ceSJim Ingham         }
631b9c1b51eSKate Stone       } else // No command arg specified.  Use variable_list, instead.
6326d56d2ceSJim Ingham       {
633c7bece56SGreg Clayton         const size_t num_variables = variable_list->GetSize();
634b9c1b51eSKate Stone         if (num_variables > 0) {
635b9c1b51eSKate Stone           for (size_t i = 0; i < num_variables; i++) {
6361a65ae11SGreg Clayton             var_sp = variable_list->GetVariableAtIndex(i);
637f955efc0SSylvestre Ledru             switch (var_sp->GetScope()) {
638eb236735SJim Ingham             case eValueTypeVariableGlobal:
639eb236735SJim Ingham               if (!m_option_variable.show_globals)
640eb236735SJim Ingham                 continue;
641eb236735SJim Ingham               break;
642eb236735SJim Ingham             case eValueTypeVariableStatic:
643eb236735SJim Ingham               if (!m_option_variable.show_globals)
644eb236735SJim Ingham                 continue;
645eb236735SJim Ingham               break;
646eb236735SJim Ingham             case eValueTypeVariableArgument:
647eb236735SJim Ingham               if (!m_option_variable.show_args)
648eb236735SJim Ingham                 continue;
649eb236735SJim Ingham               break;
650eb236735SJim Ingham             case eValueTypeVariableLocal:
651eb236735SJim Ingham               if (!m_option_variable.show_locals)
652eb236735SJim Ingham                 continue;
653eb236735SJim Ingham               break;
654eb236735SJim Ingham             default:
655eb236735SJim Ingham               continue;
656eb236735SJim Ingham               break;
657eb236735SJim Ingham             }
658560558ebSEnrico Granata             std::string scope_string;
659eb236735SJim Ingham             if (m_option_variable.show_scope)
66073418dfeSEnrico Granata               scope_string = GetScopeString(var_sp).str();
6616d56d2ceSJim Ingham 
66205097246SAdrian Prantl             // Use the variable object code to make sure we are using the same
66305097246SAdrian Prantl             // APIs as the public API will be using...
664b9c1b51eSKate Stone             valobj_sp = frame->GetValueObjectForFrameVariable(
665b9c1b51eSKate Stone                 var_sp, m_varobj_options.use_dynamic);
666b9c1b51eSKate Stone             if (valobj_sp) {
66705097246SAdrian Prantl               // When dumping all variables, don't print any variables that are
66805097246SAdrian Prantl               // not in scope to avoid extra unneeded output
669b9c1b51eSKate Stone               if (valobj_sp->IsInScope()) {
670b9c1b51eSKate Stone                 if (!valobj_sp->GetTargetSP()
671b9c1b51eSKate Stone                          ->GetDisplayRuntimeSupportValues() &&
672c8ecc2a9SEugene Zelenko                     valobj_sp->IsRuntimeSupportValue())
673560558ebSEnrico Granata                   continue;
674560558ebSEnrico Granata 
675560558ebSEnrico Granata                 if (!scope_string.empty())
676771ef6d4SMalcolm Parsons                   s.PutCString(scope_string);
677560558ebSEnrico Granata 
678b9c1b51eSKate Stone                 if (m_option_variable.show_decl &&
679b9c1b51eSKate Stone                     var_sp->GetDeclaration().GetFile()) {
680a134cc1bSGreg Clayton                   var_sp->GetDeclaration().DumpStopContext(&s, false);
681a134cc1bSGreg Clayton                   s.PutCString(": ");
682a134cc1bSGreg Clayton                 }
6830c489f58SEnrico Granata 
6840c489f58SEnrico Granata                 options.SetFormat(format);
685b9c1b51eSKate Stone                 options.SetVariableFormatDisplayLanguage(
686b9c1b51eSKate Stone                     valobj_sp->GetPreferredDisplayLanguage());
687f965cc86SZachary Turner                 options.SetRootValueObjectName(
688f965cc86SZachary Turner                     var_sp ? var_sp->GetName().AsCString() : nullptr);
6894d93b8cdSEnrico Granata                 valobj_sp->Dump(result.GetOutputStream(), options);
690a134cc1bSGreg Clayton               }
691a134cc1bSGreg Clayton             }
6926d56d2ceSJim Ingham           }
6936d56d2ceSJim Ingham         }
6946d56d2ceSJim Ingham       }
6956d56d2ceSJim Ingham       result.SetStatus(eReturnStatusSuccessFinishResult);
6966d56d2ceSJim Ingham     }
69761a80ba6SEnrico Granata 
69841ae8e74SKuba Mracek     if (m_option_variable.show_recognized_args) {
69941ae8e74SKuba Mracek       auto recognized_frame = frame->GetRecognizedFrame();
70041ae8e74SKuba Mracek       if (recognized_frame) {
70141ae8e74SKuba Mracek         ValueObjectListSP recognized_arg_list =
70241ae8e74SKuba Mracek             recognized_frame->GetRecognizedArguments();
70341ae8e74SKuba Mracek         if (recognized_arg_list) {
70441ae8e74SKuba Mracek           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
70541ae8e74SKuba Mracek             options.SetFormat(m_option_format.GetFormat());
70641ae8e74SKuba Mracek             options.SetVariableFormatDisplayLanguage(
70741ae8e74SKuba Mracek                 rec_value_sp->GetPreferredDisplayLanguage());
70841ae8e74SKuba Mracek             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
70941ae8e74SKuba Mracek             rec_value_sp->Dump(result.GetOutputStream(), options);
71041ae8e74SKuba Mracek           }
71141ae8e74SKuba Mracek         }
71241ae8e74SKuba Mracek       }
71341ae8e74SKuba Mracek     }
71441ae8e74SKuba Mracek 
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();
723cb2380c9SRaphael Isemann     Target &target = GetSelectedOrDummyTarget();
72424fff242SDavide Italiano     if (res)
725cb2380c9SRaphael Isemann       target.IncrementStats(StatisticKind::FrameVarSuccess);
72624fff242SDavide Italiano     else
727cb2380c9SRaphael Isemann       target.IncrementStats(StatisticKind::FrameVarFailure);
72824fff242SDavide Italiano     return res;
7296d56d2ceSJim Ingham   }
7306d56d2ceSJim Ingham 
7312837b766SJim Ingham   OptionGroupOptions m_option_group;
732715c2365SGreg Clayton   OptionGroupVariable m_option_variable;
7331deb7962SGreg Clayton   OptionGroupFormat m_option_format;
7342837b766SJim Ingham   OptionGroupValueObjectDisplay m_varobj_options;
7356d56d2ceSJim Ingham };
7366d56d2ceSJim Ingham 
73741ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer
73841ae8e74SKuba Mracek 
739ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_recognizer_add
740ec67e734SRaphael Isemann #include "CommandOptions.inc"
74141ae8e74SKuba Mracek 
74241ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
74341ae8e74SKuba Mracek private:
74441ae8e74SKuba Mracek   class CommandOptions : public Options {
74541ae8e74SKuba Mracek   public:
74641ae8e74SKuba Mracek     CommandOptions() : Options() {}
74741ae8e74SKuba Mracek     ~CommandOptions() override = default;
74841ae8e74SKuba Mracek 
74941ae8e74SKuba Mracek     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
75041ae8e74SKuba Mracek                           ExecutionContext *execution_context) override {
75141ae8e74SKuba Mracek       Status error;
75241ae8e74SKuba Mracek       const int short_option = m_getopt_table[option_idx].val;
75341ae8e74SKuba Mracek 
75441ae8e74SKuba Mracek       switch (short_option) {
75541ae8e74SKuba Mracek       case 'l':
75641ae8e74SKuba Mracek         m_class_name = std::string(option_arg);
75741ae8e74SKuba Mracek         break;
75841ae8e74SKuba Mracek       case 's':
75941ae8e74SKuba Mracek         m_module = std::string(option_arg);
76041ae8e74SKuba Mracek         break;
76141ae8e74SKuba Mracek       case 'n':
762db31e2e1SMed Ismail Bennani         m_symbols.push_back(std::string(option_arg));
76341ae8e74SKuba Mracek         break;
76441ae8e74SKuba Mracek       case 'x':
76541ae8e74SKuba Mracek         m_regex = true;
76641ae8e74SKuba Mracek         break;
76741ae8e74SKuba Mracek       default:
76836162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
76941ae8e74SKuba Mracek       }
77041ae8e74SKuba Mracek 
77141ae8e74SKuba Mracek       return error;
77241ae8e74SKuba Mracek     }
77341ae8e74SKuba Mracek 
77441ae8e74SKuba Mracek     void OptionParsingStarting(ExecutionContext *execution_context) override {
77541ae8e74SKuba Mracek       m_module = "";
776db31e2e1SMed Ismail Bennani       m_symbols.clear();
77741ae8e74SKuba Mracek       m_class_name = "";
77841ae8e74SKuba Mracek       m_regex = false;
77941ae8e74SKuba Mracek     }
78041ae8e74SKuba Mracek 
78141ae8e74SKuba Mracek     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
78241ae8e74SKuba Mracek       return llvm::makeArrayRef(g_frame_recognizer_add_options);
78341ae8e74SKuba Mracek     }
78441ae8e74SKuba Mracek 
78541ae8e74SKuba Mracek     // Instance variables to hold the values for command options.
78641ae8e74SKuba Mracek     std::string m_class_name;
78741ae8e74SKuba Mracek     std::string m_module;
788db31e2e1SMed Ismail Bennani     std::vector<std::string> m_symbols;
78941ae8e74SKuba Mracek     bool m_regex;
79041ae8e74SKuba Mracek   };
79141ae8e74SKuba Mracek 
79241ae8e74SKuba Mracek   CommandOptions m_options;
79341ae8e74SKuba Mracek 
79441ae8e74SKuba Mracek   Options *GetOptions() override { return &m_options; }
79541ae8e74SKuba Mracek 
79641ae8e74SKuba Mracek protected:
79741ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override;
79841ae8e74SKuba Mracek 
79941ae8e74SKuba Mracek public:
80041ae8e74SKuba Mracek   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
80141ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer add",
80241ae8e74SKuba Mracek                             "Add a new frame recognizer.", nullptr),
80341ae8e74SKuba Mracek         m_options() {
80441ae8e74SKuba Mracek     SetHelpLong(R"(
80541ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on
80641ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source
80741ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments
80841ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments.
80941ae8e74SKuba Mracek 
81041ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class
81141ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a
81241ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type
81341ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize.
81441ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that
81541ae8e74SKuba Mracek represent the recognized arguments.
81641ae8e74SKuba Mracek 
81741ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc
81841ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows:
81941ae8e74SKuba Mracek 
82041ae8e74SKuba Mracek   class LibcFdRecognizer(object):
82141ae8e74SKuba Mracek     def get_recognized_arguments(self, frame):
82241ae8e74SKuba Mracek       if frame.name in ["read", "write", "close"]:
82341ae8e74SKuba Mracek         fd = frame.EvaluateExpression("$arg1").unsigned
82441ae8e74SKuba Mracek         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
82541ae8e74SKuba Mracek         return [value]
82641ae8e74SKuba Mracek       return []
82741ae8e74SKuba Mracek 
82841ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script
82941ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'.
83041ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is
83141ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
83241ae8e74SKuba Mracek in other modules:
83341ae8e74SKuba Mracek 
83441ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py
83541ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
83641ae8e74SKuba Mracek 
83741ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we
83841ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable':
83941ae8e74SKuba Mracek 
84041ae8e74SKuba Mracek (lldb) b read
84141ae8e74SKuba Mracek (lldb) r
84241ae8e74SKuba Mracek Process 1234 stopped
84341ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
84441ae8e74SKuba Mracek     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
84541ae8e74SKuba Mracek (lldb) frame variable
84641ae8e74SKuba Mracek (int) fd = 3
84741ae8e74SKuba Mracek 
84841ae8e74SKuba Mracek     )");
84941ae8e74SKuba Mracek   }
85041ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerAdd() override = default;
85141ae8e74SKuba Mracek };
85241ae8e74SKuba Mracek 
85341ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
85441ae8e74SKuba Mracek                                                 CommandReturnObject &result) {
8554e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
85641ae8e74SKuba Mracek   if (m_options.m_class_name.empty()) {
85741ae8e74SKuba Mracek     result.AppendErrorWithFormat(
85841ae8e74SKuba Mracek         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
85941ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
86041ae8e74SKuba Mracek     return false;
86141ae8e74SKuba Mracek   }
86241ae8e74SKuba Mracek 
86341ae8e74SKuba Mracek   if (m_options.m_module.empty()) {
86441ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
86541ae8e74SKuba Mracek                                  m_cmd_name.c_str());
86641ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
86741ae8e74SKuba Mracek     return false;
86841ae8e74SKuba Mracek   }
86941ae8e74SKuba Mracek 
870db31e2e1SMed Ismail Bennani   if (m_options.m_symbols.empty()) {
871db31e2e1SMed Ismail Bennani     result.AppendErrorWithFormat(
872db31e2e1SMed Ismail Bennani         "%s needs at least one symbol name (-n argument).\n",
873db31e2e1SMed Ismail Bennani         m_cmd_name.c_str());
874db31e2e1SMed Ismail Bennani     result.SetStatus(eReturnStatusFailed);
875db31e2e1SMed Ismail Bennani     return false;
876db31e2e1SMed Ismail Bennani   }
877db31e2e1SMed Ismail Bennani 
878db31e2e1SMed Ismail Bennani   if (m_options.m_regex && m_options.m_symbols.size() > 1) {
879db31e2e1SMed Ismail Bennani     result.AppendErrorWithFormat(
880db31e2e1SMed Ismail Bennani         "%s needs only one symbol regular expression (-n argument).\n",
88141ae8e74SKuba Mracek         m_cmd_name.c_str());
88241ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
88341ae8e74SKuba Mracek     return false;
88441ae8e74SKuba Mracek   }
88541ae8e74SKuba Mracek 
8862b29b432SJonas Devlieghere   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
88741ae8e74SKuba Mracek 
88841ae8e74SKuba Mracek   if (interpreter &&
88941ae8e74SKuba Mracek       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
890a925974bSAdrian Prantl     result.AppendWarning("The provided class does not exist - please define it "
89141ae8e74SKuba Mracek                          "before attempting to use this frame recognizer");
89241ae8e74SKuba Mracek   }
89341ae8e74SKuba Mracek 
89441ae8e74SKuba Mracek   StackFrameRecognizerSP recognizer_sp =
89541ae8e74SKuba Mracek       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
89641ae8e74SKuba Mracek           interpreter, m_options.m_class_name.c_str()));
89741ae8e74SKuba Mracek   if (m_options.m_regex) {
89841ae8e74SKuba Mracek     auto module =
89941ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_module));
90041ae8e74SKuba Mracek     auto func =
901db31e2e1SMed Ismail Bennani         RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
90241ae8e74SKuba Mracek     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func);
90341ae8e74SKuba Mracek   } else {
90441ae8e74SKuba Mracek     auto module = ConstString(m_options.m_module);
905db31e2e1SMed Ismail Bennani     std::vector<ConstString> symbols(m_options.m_symbols.begin(),
906db31e2e1SMed Ismail Bennani                                      m_options.m_symbols.end());
907db31e2e1SMed Ismail Bennani     StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, symbols);
90841ae8e74SKuba Mracek   }
909f80d2655SKuba Mracek #endif
91041ae8e74SKuba Mracek 
91141ae8e74SKuba Mracek   result.SetStatus(eReturnStatusSuccessFinishNoResult);
91241ae8e74SKuba Mracek   return result.Succeeded();
91341ae8e74SKuba Mracek }
91441ae8e74SKuba Mracek 
91541ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
91641ae8e74SKuba Mracek public:
91741ae8e74SKuba Mracek   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
91841ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer clear",
91941ae8e74SKuba Mracek                             "Delete all frame recognizers.", nullptr) {}
92041ae8e74SKuba Mracek 
92141ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerClear() override = default;
92241ae8e74SKuba Mracek 
92341ae8e74SKuba Mracek protected:
92441ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
92541ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveAllRecognizers();
92641ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
92741ae8e74SKuba Mracek     return result.Succeeded();
92841ae8e74SKuba Mracek   }
92941ae8e74SKuba Mracek };
93041ae8e74SKuba Mracek 
93141ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
93241ae8e74SKuba Mracek public:
93341ae8e74SKuba Mracek   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
93441ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer delete",
93541ae8e74SKuba Mracek                             "Delete an existing frame recognizer.", nullptr) {}
93641ae8e74SKuba Mracek 
93741ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerDelete() override = default;
93841ae8e74SKuba Mracek 
93941ae8e74SKuba Mracek protected:
94041ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
94141ae8e74SKuba Mracek     if (command.GetArgumentCount() == 0) {
94241ae8e74SKuba Mracek       if (!m_interpreter.Confirm(
94341ae8e74SKuba Mracek               "About to delete all frame recognizers, do you want to do that?",
94441ae8e74SKuba Mracek               true)) {
94541ae8e74SKuba Mracek         result.AppendMessage("Operation cancelled...");
94641ae8e74SKuba Mracek         result.SetStatus(eReturnStatusFailed);
94741ae8e74SKuba Mracek         return false;
94841ae8e74SKuba Mracek       }
94941ae8e74SKuba Mracek 
95041ae8e74SKuba Mracek       StackFrameRecognizerManager::RemoveAllRecognizers();
95141ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
95241ae8e74SKuba Mracek       return result.Succeeded();
95341ae8e74SKuba Mracek     }
95441ae8e74SKuba Mracek 
95541ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
95641ae8e74SKuba Mracek       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
95741ae8e74SKuba Mracek                                    m_cmd_name.c_str());
95841ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
95941ae8e74SKuba Mracek       return false;
96041ae8e74SKuba Mracek     }
96141ae8e74SKuba Mracek 
96241ae8e74SKuba Mracek     uint32_t recognizer_id =
96341ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
96441ae8e74SKuba Mracek 
96541ae8e74SKuba Mracek     StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id);
96641ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
96741ae8e74SKuba Mracek     return result.Succeeded();
96841ae8e74SKuba Mracek   }
96941ae8e74SKuba Mracek };
97041ae8e74SKuba Mracek 
97141ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed {
97241ae8e74SKuba Mracek public:
97341ae8e74SKuba Mracek   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
97441ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer list",
97541ae8e74SKuba Mracek                             "Show a list of active frame recognizers.",
97641ae8e74SKuba Mracek                             nullptr) {}
97741ae8e74SKuba Mracek 
97841ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerList() override = default;
97941ae8e74SKuba Mracek 
98041ae8e74SKuba Mracek protected:
98141ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
98241ae8e74SKuba Mracek     bool any_printed = false;
98341ae8e74SKuba Mracek     StackFrameRecognizerManager::ForEach(
984db31e2e1SMed Ismail Bennani         [&result, &any_printed](
985db31e2e1SMed Ismail Bennani             uint32_t recognizer_id, std::string name, std::string module,
986db31e2e1SMed Ismail Bennani             llvm::ArrayRef<ConstString> symbols, bool regexp) {
987cb0c4ee3SMed Ismail Bennani           Stream &stream = result.GetOutputStream();
988cb0c4ee3SMed Ismail Bennani 
989cb0c4ee3SMed Ismail Bennani           if (name.empty())
990a925974bSAdrian Prantl             name = "(internal)";
991cb0c4ee3SMed Ismail Bennani 
992cb0c4ee3SMed Ismail Bennani           stream << std::to_string(recognizer_id) << ": " << name;
993cb0c4ee3SMed Ismail Bennani           if (!module.empty())
994cb0c4ee3SMed Ismail Bennani             stream << ", module " << module;
995db31e2e1SMed Ismail Bennani           if (!symbols.empty())
996db31e2e1SMed Ismail Bennani             for (auto &symbol : symbols)
997db31e2e1SMed Ismail Bennani               stream << ", symbol " << symbol;
998cb0c4ee3SMed Ismail Bennani           if (regexp)
999cb0c4ee3SMed Ismail Bennani             stream << " (regexp)";
1000cb0c4ee3SMed Ismail Bennani 
1001cb0c4ee3SMed Ismail Bennani           stream.EOL();
1002cb0c4ee3SMed Ismail Bennani           stream.Flush();
1003cb0c4ee3SMed Ismail Bennani 
100441ae8e74SKuba Mracek           any_printed = true;
100541ae8e74SKuba Mracek         });
100641ae8e74SKuba Mracek 
100741ae8e74SKuba Mracek     if (any_printed)
100841ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
100941ae8e74SKuba Mracek     else {
101041ae8e74SKuba Mracek       result.GetOutputStream().PutCString("no matching results found.\n");
101141ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishNoResult);
101241ae8e74SKuba Mracek     }
101341ae8e74SKuba Mracek     return result.Succeeded();
101441ae8e74SKuba Mracek   }
101541ae8e74SKuba Mracek };
101641ae8e74SKuba Mracek 
101741ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
101841ae8e74SKuba Mracek public:
101941ae8e74SKuba Mracek   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
102041ae8e74SKuba Mracek       : CommandObjectParsed(
102141ae8e74SKuba Mracek             interpreter, "frame recognizer info",
102241ae8e74SKuba Mracek             "Show which frame recognizer is applied a stack frame (if any).",
102341ae8e74SKuba Mracek             nullptr) {
102441ae8e74SKuba Mracek     CommandArgumentEntry arg;
102541ae8e74SKuba Mracek     CommandArgumentData index_arg;
102641ae8e74SKuba Mracek 
102741ae8e74SKuba Mracek     // Define the first (and only) variant of this arg.
102841ae8e74SKuba Mracek     index_arg.arg_type = eArgTypeFrameIndex;
102941ae8e74SKuba Mracek     index_arg.arg_repetition = eArgRepeatPlain;
103041ae8e74SKuba Mracek 
103141ae8e74SKuba Mracek     // There is only one variant this argument could be; put it into the
103241ae8e74SKuba Mracek     // argument entry.
103341ae8e74SKuba Mracek     arg.push_back(index_arg);
103441ae8e74SKuba Mracek 
103541ae8e74SKuba Mracek     // Push the data for the first argument into the m_arguments vector.
103641ae8e74SKuba Mracek     m_arguments.push_back(arg);
103741ae8e74SKuba Mracek   }
103841ae8e74SKuba Mracek 
103941ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerInfo() override = default;
104041ae8e74SKuba Mracek 
104141ae8e74SKuba Mracek protected:
104241ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
104341ae8e74SKuba Mracek     Process *process = m_exe_ctx.GetProcessPtr();
104441ae8e74SKuba Mracek     if (process == nullptr) {
104541ae8e74SKuba Mracek       result.AppendError("no process");
104641ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
104741ae8e74SKuba Mracek       return false;
104841ae8e74SKuba Mracek     }
104941ae8e74SKuba Mracek     Thread *thread = m_exe_ctx.GetThreadPtr();
105041ae8e74SKuba Mracek     if (thread == nullptr) {
105141ae8e74SKuba Mracek       result.AppendError("no thread");
105241ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
105341ae8e74SKuba Mracek       return false;
105441ae8e74SKuba Mracek     }
105541ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
105641ae8e74SKuba Mracek       result.AppendErrorWithFormat(
105741ae8e74SKuba Mracek           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
105841ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
105941ae8e74SKuba Mracek       return false;
106041ae8e74SKuba Mracek     }
106141ae8e74SKuba Mracek 
106241ae8e74SKuba Mracek     uint32_t frame_index =
106341ae8e74SKuba Mracek         StringConvert::ToUInt32(command.GetArgumentAtIndex(0), 0, 0);
106441ae8e74SKuba Mracek     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
106541ae8e74SKuba Mracek     if (!frame_sp) {
106641ae8e74SKuba Mracek       result.AppendErrorWithFormat("no frame with index %u", frame_index);
106741ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
106841ae8e74SKuba Mracek       return false;
106941ae8e74SKuba Mracek     }
107041ae8e74SKuba Mracek 
107141ae8e74SKuba Mracek     auto recognizer =
107241ae8e74SKuba Mracek         StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp);
107341ae8e74SKuba Mracek 
107441ae8e74SKuba Mracek     Stream &output_stream = result.GetOutputStream();
107541ae8e74SKuba Mracek     output_stream.Printf("frame %d ", frame_index);
107641ae8e74SKuba Mracek     if (recognizer) {
107741ae8e74SKuba Mracek       output_stream << "is recognized by ";
107841ae8e74SKuba Mracek       output_stream << recognizer->GetName();
107941ae8e74SKuba Mracek     } else {
108041ae8e74SKuba Mracek       output_stream << "not recognized by any recognizer";
108141ae8e74SKuba Mracek     }
108241ae8e74SKuba Mracek     output_stream.EOL();
108341ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
108441ae8e74SKuba Mracek     return result.Succeeded();
108541ae8e74SKuba Mracek   }
108641ae8e74SKuba Mracek };
108741ae8e74SKuba Mracek 
108841ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword {
108941ae8e74SKuba Mracek public:
109041ae8e74SKuba Mracek   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
109141ae8e74SKuba Mracek       : CommandObjectMultiword(
109241ae8e74SKuba Mracek             interpreter, "frame recognizer",
109341ae8e74SKuba Mracek             "Commands for editing and viewing frame recognizers.",
109441ae8e74SKuba Mracek             "frame recognizer [<sub-command-options>] ") {
1095a925974bSAdrian Prantl     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1096a925974bSAdrian Prantl                               interpreter)));
109741ae8e74SKuba Mracek     LoadSubCommand(
109841ae8e74SKuba Mracek         "clear",
109941ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
110041ae8e74SKuba Mracek     LoadSubCommand(
110141ae8e74SKuba Mracek         "delete",
110241ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1103a925974bSAdrian Prantl     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1104a925974bSAdrian Prantl                                interpreter)));
1105a925974bSAdrian Prantl     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1106a925974bSAdrian Prantl                                interpreter)));
110741ae8e74SKuba Mracek   }
110841ae8e74SKuba Mracek 
110941ae8e74SKuba Mracek   ~CommandObjectFrameRecognizer() override = default;
111041ae8e74SKuba Mracek };
111141ae8e74SKuba Mracek 
111230fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
111330fdc8d8SChris Lattner 
111430fdc8d8SChris Lattner // CommandObjectMultiwordFrame
111530fdc8d8SChris Lattner 
1116b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1117b9c1b51eSKate Stone     CommandInterpreter &interpreter)
1118a925974bSAdrian Prantl     : CommandObjectMultiword(interpreter, "frame",
1119a925974bSAdrian Prantl                              "Commands for selecting and "
1120b9c1b51eSKate Stone                              "examing the current "
1121b9c1b51eSKate Stone                              "thread's stack frames.",
1122b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
1123b9c1b51eSKate Stone   LoadSubCommand("diagnose",
1124b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1125b9c1b51eSKate Stone   LoadSubCommand("info",
1126b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1127b9c1b51eSKate Stone   LoadSubCommand("select",
1128b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1129b9c1b51eSKate Stone   LoadSubCommand("variable",
1130b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
11314e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
1132a925974bSAdrian Prantl   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1133a925974bSAdrian Prantl                                    interpreter)));
113441ae8e74SKuba Mracek #endif
113530fdc8d8SChris Lattner }
113630fdc8d8SChris Lattner 
1137c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1138