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"
1530fdc8d8SChris Lattner #include "lldb/Interpreter/CommandInterpreter.h"
1630fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h"
1754c496daSRoman Podoliaka #include "lldb/Interpreter/OptionArgParser.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",
108*722a2fb7SDave Lee                             "Try to determine what 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         return false;
1464740a734SSean Callanan       }
1474740a734SSean Callanan       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
148b9c1b51eSKate Stone     } else if (m_options.reg.hasValue()) {
149b9c1b51eSKate Stone       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
150b9c1b51eSKate Stone           m_options.reg.getValue(), m_options.offset.getValueOr(0));
151b9c1b51eSKate Stone     } else {
1524740a734SSean Callanan       StopInfoSP stop_info_sp = thread->GetStopInfo();
153b9c1b51eSKate Stone       if (!stop_info_sp) {
1544740a734SSean Callanan         result.AppendError("No arguments provided, and no stop info.");
1554740a734SSean Callanan         return false;
1564740a734SSean Callanan       }
1574740a734SSean Callanan 
1584740a734SSean Callanan       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
1594740a734SSean Callanan     }
1604740a734SSean Callanan 
161b9c1b51eSKate Stone     if (!valobj_sp) {
1624740a734SSean Callanan       result.AppendError("No diagnosis available.");
1634740a734SSean Callanan       return false;
1644740a734SSean Callanan     }
1654740a734SSean Callanan 
166a925974bSAdrian Prantl     DumpValueObjectOptions::DeclPrintingHelper helper =
167a925974bSAdrian Prantl         [&valobj_sp](ConstString type, ConstString var,
168a925974bSAdrian Prantl                      const DumpValueObjectOptions &opts,
1693bc714b2SZachary Turner                      Stream &stream) -> bool {
170b9c1b51eSKate Stone       const ValueObject::GetExpressionPathFormat format = ValueObject::
171b9c1b51eSKate Stone           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
1723014efe0SAlex Langford       valobj_sp->GetExpressionPath(stream, format);
1734740a734SSean Callanan       stream.PutCString(" =");
1744740a734SSean Callanan       return true;
1754740a734SSean Callanan     };
1764740a734SSean Callanan 
1774740a734SSean Callanan     DumpValueObjectOptions options;
1784740a734SSean Callanan     options.SetDeclPrintingHelper(helper);
179b9c1b51eSKate Stone     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
180b9c1b51eSKate Stone                                options);
1814740a734SSean Callanan     printer.PrintValueObject();
1824740a734SSean Callanan 
1834740a734SSean Callanan     return true;
1844740a734SSean Callanan   }
1854740a734SSean Callanan 
1864740a734SSean Callanan   CommandOptions m_options;
1874740a734SSean Callanan };
1884740a734SSean Callanan 
18930fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo
19030fdc8d8SChris Lattner 
19130fdc8d8SChris Lattner // CommandObjectFrameInfo
19230fdc8d8SChris Lattner 
193b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed {
19430fdc8d8SChris Lattner public:
1957428a18cSKate Stone   CommandObjectFrameInfo(CommandInterpreter &interpreter)
196a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame info",
197a925974bSAdrian Prantl                             "List information about the current "
198b9c1b51eSKate Stone                             "stack frame in the current thread.",
199b9c1b51eSKate Stone                             "frame info",
200b9c1b51eSKate Stone                             eCommandRequiresFrame | eCommandTryTargetAPILock |
201a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
202a925974bSAdrian Prantl                                 eCommandProcessMustBePaused) {}
20330fdc8d8SChris Lattner 
204c8ecc2a9SEugene Zelenko   ~CommandObjectFrameInfo() override = default;
20530fdc8d8SChris Lattner 
2065a988416SJim Ingham protected:
207b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
208f9fc609fSGreg Clayton     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
20930fdc8d8SChris Lattner     result.SetStatus(eReturnStatusSuccessFinishResult);
21030fdc8d8SChris Lattner     return result.Succeeded();
21130fdc8d8SChris Lattner   }
21230fdc8d8SChris Lattner };
21330fdc8d8SChris Lattner 
21430fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect
21530fdc8d8SChris Lattner 
21630fdc8d8SChris Lattner // CommandObjectFrameSelect
21730fdc8d8SChris Lattner 
218ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_select
219ec67e734SRaphael Isemann #include "CommandOptions.inc"
2201f0f5b5bSZachary Turner 
221b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed {
22230fdc8d8SChris Lattner public:
223b9c1b51eSKate Stone   class CommandOptions : public Options {
224864174e1SGreg Clayton   public:
225b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
226864174e1SGreg Clayton 
227c8ecc2a9SEugene Zelenko     ~CommandOptions() override = default;
228864174e1SGreg Clayton 
22997206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
230b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
23197206d57SZachary Turner       Status error;
2323bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
233b9c1b51eSKate Stone       switch (short_option) {
234dab6f074SRaphael Isemann       case 'r': {
235dab6f074SRaphael Isemann         int32_t offset = 0;
236dab6f074SRaphael Isemann         if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
237b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
238fe11483bSZachary Turner                                          option_arg.str().c_str());
239dab6f074SRaphael Isemann         } else
240dab6f074SRaphael Isemann           relative_frame_offset = offset;
2415a039d55SRaphael Isemann         break;
242dab6f074SRaphael Isemann       }
243864174e1SGreg Clayton 
244864174e1SGreg Clayton       default:
24536162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
246864174e1SGreg Clayton       }
247864174e1SGreg Clayton 
248864174e1SGreg Clayton       return error;
249864174e1SGreg Clayton     }
250864174e1SGreg Clayton 
2515a039d55SRaphael Isemann     void OptionParsingStarting(ExecutionContext *execution_context) override {
252dab6f074SRaphael Isemann       relative_frame_offset.reset();
2535a039d55SRaphael Isemann     }
254864174e1SGreg Clayton 
2551f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
25670602439SZachary Turner       return llvm::makeArrayRef(g_frame_select_options);
2571f0f5b5bSZachary Turner     }
258864174e1SGreg Clayton 
259dab6f074SRaphael Isemann     llvm::Optional<int32_t> relative_frame_offset;
260864174e1SGreg Clayton   };
261864174e1SGreg Clayton 
2627428a18cSKate Stone   CommandObjectFrameSelect(CommandInterpreter &interpreter)
263a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame select",
264a925974bSAdrian Prantl                             "Select the current stack frame by "
265b9c1b51eSKate Stone                             "index from within the current thread "
266b9c1b51eSKate Stone                             "(see 'thread backtrace'.)",
267b9c1b51eSKate Stone                             nullptr,
268b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
269a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
270a925974bSAdrian Prantl                                 eCommandProcessMustBePaused),
271b9c1b51eSKate Stone         m_options() {
272405fe67fSCaroline Tice     CommandArgumentEntry arg;
273405fe67fSCaroline Tice     CommandArgumentData index_arg;
274405fe67fSCaroline Tice 
275405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
276405fe67fSCaroline Tice     index_arg.arg_type = eArgTypeFrameIndex;
277864174e1SGreg Clayton     index_arg.arg_repetition = eArgRepeatOptional;
278405fe67fSCaroline Tice 
279b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
280b9c1b51eSKate Stone     // argument entry.
281405fe67fSCaroline Tice     arg.push_back(index_arg);
282405fe67fSCaroline Tice 
283405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
284405fe67fSCaroline Tice     m_arguments.push_back(arg);
28530fdc8d8SChris Lattner   }
28630fdc8d8SChris Lattner 
287c8ecc2a9SEugene Zelenko   ~CommandObjectFrameSelect() override = default;
28830fdc8d8SChris Lattner 
28980eb4228SGongyu Deng   void
29080eb4228SGongyu Deng   HandleArgumentCompletion(CompletionRequest &request,
29180eb4228SGongyu Deng                            OptionElementVector &opt_element_vector) override {
29266fa73faSGongyu Deng     if (request.GetCursorIndex() != 0)
29380eb4228SGongyu Deng       return;
29480eb4228SGongyu Deng 
29566fa73faSGongyu Deng     CommandCompletions::InvokeCommonCompletionCallbacks(
29666fa73faSGongyu Deng         GetCommandInterpreter(), CommandCompletions::eFrameIndexCompletion,
29766fa73faSGongyu Deng         request, nullptr);
29880eb4228SGongyu Deng   }
29980eb4228SGongyu Deng 
300b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
301864174e1SGreg Clayton 
3025a988416SJim Ingham protected:
303b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
304b9c1b51eSKate Stone     // No need to check "thread" for validity as eCommandRequiresThread ensures
305b9c1b51eSKate Stone     // it is valid
306f9fc609fSGreg Clayton     Thread *thread = m_exe_ctx.GetThreadPtr();
307f9fc609fSGreg Clayton 
308864174e1SGreg Clayton     uint32_t frame_idx = UINT32_MAX;
309dab6f074SRaphael Isemann     if (m_options.relative_frame_offset.hasValue()) {
310864174e1SGreg Clayton       // The one and only argument is a signed relative frame index
311c14ee32dSGreg Clayton       frame_idx = thread->GetSelectedFrameIndex();
312864174e1SGreg Clayton       if (frame_idx == UINT32_MAX)
313864174e1SGreg Clayton         frame_idx = 0;
314864174e1SGreg Clayton 
315dab6f074SRaphael Isemann       if (*m_options.relative_frame_offset < 0) {
316dab6f074SRaphael Isemann         if (static_cast<int32_t>(frame_idx) >=
317dab6f074SRaphael Isemann             -*m_options.relative_frame_offset)
318dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
319b9c1b51eSKate Stone         else {
320b9c1b51eSKate Stone           if (frame_idx == 0) {
32105097246SAdrian Prantl             // If you are already at the bottom of the stack, then just warn
32205097246SAdrian Prantl             // and don't reset the frame.
3237428a18cSKate Stone             result.AppendError("Already at the bottom of the stack.");
324213b4546SJim Ingham             return false;
325b9c1b51eSKate Stone           } else
326864174e1SGreg Clayton             frame_idx = 0;
327864174e1SGreg Clayton         }
328dab6f074SRaphael Isemann       } else if (*m_options.relative_frame_offset > 0) {
329b9c1b51eSKate Stone         // I don't want "up 20" where "20" takes you past the top of the stack
330b9c1b51eSKate Stone         // to produce
331b9c1b51eSKate Stone         // an error, but rather to just go to the top.  So I have to count the
332b9c1b51eSKate Stone         // stack here...
333b0c72a5fSJim Ingham         const uint32_t num_frames = thread->GetStackFrameCount();
334b9c1b51eSKate Stone         if (static_cast<int32_t>(num_frames - frame_idx) >
335dab6f074SRaphael Isemann             *m_options.relative_frame_offset)
336dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
337b9c1b51eSKate Stone         else {
338b9c1b51eSKate Stone           if (frame_idx == num_frames - 1) {
339b9c1b51eSKate Stone             // If we are already at the top of the stack, just warn and don't
340b9c1b51eSKate Stone             // reset the frame.
3417428a18cSKate Stone             result.AppendError("Already at the top of the stack.");
342213b4546SJim Ingham             return false;
343b9c1b51eSKate Stone           } else
344864174e1SGreg Clayton             frame_idx = num_frames - 1;
345864174e1SGreg Clayton         }
346864174e1SGreg Clayton       }
347b9c1b51eSKate Stone     } else {
348f965cc86SZachary Turner       if (command.GetArgumentCount() > 1) {
349f965cc86SZachary Turner         result.AppendErrorWithFormat(
350f965cc86SZachary Turner             "too many arguments; expected frame-index, saw '%s'.\n",
351867e7d17SZachary Turner             command[0].c_str());
352f965cc86SZachary Turner         m_options.GenerateOptionUsage(
353f965cc86SZachary Turner             result.GetErrorStream(), this,
354f965cc86SZachary Turner             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
355f965cc86SZachary Turner         return false;
356f965cc86SZachary Turner       }
357f965cc86SZachary Turner 
358b9c1b51eSKate Stone       if (command.GetArgumentCount() == 1) {
3590d9a201eSRaphael Isemann         if (command[0].ref().getAsInteger(0, frame_idx)) {
360b9c1b51eSKate Stone           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
361f965cc86SZachary Turner                                        command[0].c_str());
362afbb0af8SJim Ingham           return false;
363afbb0af8SJim Ingham         }
364b9c1b51eSKate Stone       } else if (command.GetArgumentCount() == 0) {
36582d4a2b9SJason Molenda         frame_idx = thread->GetSelectedFrameIndex();
366b9c1b51eSKate Stone         if (frame_idx == UINT32_MAX) {
36782d4a2b9SJason Molenda           frame_idx = 0;
36882d4a2b9SJason Molenda         }
369864174e1SGreg Clayton       }
370864174e1SGreg Clayton     }
37130fdc8d8SChris Lattner 
372b9c1b51eSKate Stone     bool success = thread->SetSelectedFrameByIndexNoisily(
373b9c1b51eSKate Stone         frame_idx, result.GetOutputStream());
374b9c1b51eSKate Stone     if (success) {
375f9fc609fSGreg Clayton       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
37630fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
377b9c1b51eSKate Stone     } else {
378b9c1b51eSKate Stone       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
379b9c1b51eSKate Stone                                    frame_idx);
38093208b86SJim Ingham     }
38193208b86SJim Ingham 
38293208b86SJim Ingham     return result.Succeeded();
38330fdc8d8SChris Lattner   }
384864174e1SGreg Clayton 
385864174e1SGreg Clayton   CommandOptions m_options;
386864174e1SGreg Clayton };
387864174e1SGreg Clayton 
3886d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable
3896d56d2ceSJim Ingham // List images with associated information
390b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed {
3916d56d2ceSJim Ingham public:
3927428a18cSKate Stone   CommandObjectFrameVariable(CommandInterpreter &interpreter)
3937428a18cSKate Stone       : CommandObjectParsed(
394b9c1b51eSKate Stone             interpreter, "frame variable",
395b9c1b51eSKate Stone             "Show variables for the current stack frame. Defaults to all "
3967428a18cSKate Stone             "arguments and local variables in scope. Names of argument, "
3977428a18cSKate Stone             "local, file static and file global variables can be specified. "
398ed8a705cSGreg Clayton             "Children of aggregate variables can be specified such as "
399285ae0c0SJim Ingham             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
400285ae0c0SJim Ingham             "not invoke operator overloads if they exist, but directly access "
401285ae0c0SJim Ingham             "the specified element.  If you want to trigger operator overloads "
402285ae0c0SJim Ingham             "use the expression command to print the variable instead."
403285ae0c0SJim Ingham             "\nIt is worth noting that except for overloaded "
404285ae0c0SJim Ingham             "operators, when printing local variables 'expr local_var' and "
405285ae0c0SJim Ingham             "'frame var local_var' produce the same "
406285ae0c0SJim Ingham             "results.  However, 'frame variable' is more efficient, since it "
407285ae0c0SJim Ingham             "uses debug information and memory reads directly, rather than "
408285ae0c0SJim Ingham             "parsing and evaluating an expression, which may even involve "
409285ae0c0SJim Ingham             "JITing and running code in the target program.",
410a925974bSAdrian Prantl             nullptr,
411a925974bSAdrian Prantl             eCommandRequiresFrame | eCommandTryTargetAPILock |
412a925974bSAdrian Prantl                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
413a925974bSAdrian Prantl                 eCommandRequiresProcess),
414e1cfbc79STodd Fiala         m_option_group(),
415b9c1b51eSKate Stone         m_option_variable(
416b9c1b51eSKate Stone             true), // Include the frame specific options by passing "true"
417a925974bSAdrian Prantl         m_option_format(eFormatDefault), m_varobj_options() {
418405fe67fSCaroline Tice     CommandArgumentEntry arg;
419405fe67fSCaroline Tice     CommandArgumentData var_name_arg;
420405fe67fSCaroline Tice 
421405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
422405fe67fSCaroline Tice     var_name_arg.arg_type = eArgTypeVarName;
423405fe67fSCaroline Tice     var_name_arg.arg_repetition = eArgRepeatStar;
424405fe67fSCaroline Tice 
425b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
426b9c1b51eSKate Stone     // argument entry.
427405fe67fSCaroline Tice     arg.push_back(var_name_arg);
428405fe67fSCaroline Tice 
429405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
430405fe67fSCaroline Tice     m_arguments.push_back(arg);
4312837b766SJim Ingham 
432715c2365SGreg Clayton     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
433b9c1b51eSKate Stone     m_option_group.Append(&m_option_format,
434b9c1b51eSKate Stone                           OptionGroupFormat::OPTION_GROUP_FORMAT |
435b9c1b51eSKate Stone                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
436b9c1b51eSKate Stone                           LLDB_OPT_SET_1);
4372837b766SJim Ingham     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
4382837b766SJim Ingham     m_option_group.Finalize();
4396d56d2ceSJim Ingham   }
4406d56d2ceSJim Ingham 
441c8ecc2a9SEugene Zelenko   ~CommandObjectFrameVariable() override = default;
4426d56d2ceSJim Ingham 
443b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
444f21feadcSGreg Clayton 
445ae34ed2cSRaphael Isemann   void
446ae34ed2cSRaphael Isemann   HandleArgumentCompletion(CompletionRequest &request,
4472443bbd4SRaphael Isemann                            OptionElementVector &opt_element_vector) override {
448f21feadcSGreg Clayton     // Arguments are the standard source file completer.
449b9c1b51eSKate Stone     CommandCompletions::InvokeCommonCompletionCallbacks(
450b9c1b51eSKate Stone         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
451a2e76c0bSRaphael Isemann         request, nullptr);
452f21feadcSGreg Clayton   }
4536d56d2ceSJim Ingham 
4545a988416SJim Ingham protected:
45573418dfeSEnrico Granata   llvm::StringRef GetScopeString(VariableSP var_sp) {
45673418dfeSEnrico Granata     if (!var_sp)
457bbea3610SRaphael Isemann       return llvm::StringRef();
45873418dfeSEnrico Granata 
45973418dfeSEnrico Granata     switch (var_sp->GetScope()) {
46073418dfeSEnrico Granata     case eValueTypeVariableGlobal:
46173418dfeSEnrico Granata       return "GLOBAL: ";
46273418dfeSEnrico Granata     case eValueTypeVariableStatic:
46373418dfeSEnrico Granata       return "STATIC: ";
46473418dfeSEnrico Granata     case eValueTypeVariableArgument:
46573418dfeSEnrico Granata       return "ARG: ";
46673418dfeSEnrico Granata     case eValueTypeVariableLocal:
46773418dfeSEnrico Granata       return "LOCAL: ";
46873418dfeSEnrico Granata     case eValueTypeVariableThreadLocal:
46973418dfeSEnrico Granata       return "THREAD: ";
47073418dfeSEnrico Granata     default:
47173418dfeSEnrico Granata       break;
47273418dfeSEnrico Granata     }
47373418dfeSEnrico Granata 
474bbea3610SRaphael Isemann     return llvm::StringRef();
47573418dfeSEnrico Granata   }
47673418dfeSEnrico Granata 
477b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
47805097246SAdrian Prantl     // No need to check "frame" for validity as eCommandRequiresFrame ensures
47905097246SAdrian Prantl     // it is valid
480b57e4a1bSJason Molenda     StackFrame *frame = m_exe_ctx.GetFramePtr();
4811e49e5e7SJohnny Chen 
482a134cc1bSGreg Clayton     Stream &s = result.GetOutputStream();
4836d56d2ceSJim Ingham 
484b9c1b51eSKate Stone     // Be careful about the stack frame, if any summary formatter runs code, it
48505097246SAdrian Prantl     // might clear the StackFrameList for the thread.  So hold onto a shared
48605097246SAdrian Prantl     // pointer to the frame so it stays alive.
487650543f9SJim Ingham 
488b9c1b51eSKate Stone     VariableList *variable_list =
489b9c1b51eSKate Stone         frame->GetVariableList(m_option_variable.show_globals);
490a134cc1bSGreg Clayton 
4916d56d2ceSJim Ingham     VariableSP var_sp;
4926d56d2ceSJim Ingham     ValueObjectSP valobj_sp;
49378a685aaSJim Ingham 
494061858ceSEnrico Granata     TypeSummaryImplSP summary_format_sp;
49517b11749SEnrico Granata     if (!m_option_variable.summary.IsCurrentValueEmpty())
496b9c1b51eSKate Stone       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
497b9c1b51eSKate Stone           ConstString(m_option_variable.summary.GetCurrentValue()),
498b9c1b51eSKate Stone           summary_format_sp);
49917b11749SEnrico Granata     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
500796ac80bSJonas Devlieghere       summary_format_sp = std::make_shared<StringSummaryFormat>(
501b9c1b51eSKate Stone           TypeSummaryImpl::Flags(),
502796ac80bSJonas Devlieghere           m_option_variable.summary_string.GetCurrentValue());
503f9fa6ee5SEnrico Granata 
504b9c1b51eSKate Stone     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
505b9c1b51eSKate Stone         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
506b9c1b51eSKate Stone         summary_format_sp));
507379447a7SEnrico Granata 
508b9c1b51eSKate Stone     const SymbolContext &sym_ctx =
509b9c1b51eSKate Stone         frame->GetSymbolContext(eSymbolContextFunction);
5106754e04fSEnrico Granata     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
5116754e04fSEnrico Granata       m_option_variable.show_globals = true;
5126754e04fSEnrico Granata 
513b9c1b51eSKate Stone     if (variable_list) {
5141deb7962SGreg Clayton       const Format format = m_option_format.GetFormat();
5150c489f58SEnrico Granata       options.SetFormat(format);
5161deb7962SGreg Clayton 
51711eb9c64SZachary Turner       if (!command.empty()) {
51846747022SGreg Clayton         VariableList regex_var_list;
51946747022SGreg Clayton 
52005097246SAdrian Prantl         // If we have any args to the variable command, we will make variable
52105097246SAdrian Prantl         // objects from them...
522f965cc86SZachary Turner         for (auto &entry : command) {
523b9c1b51eSKate Stone           if (m_option_variable.use_regex) {
524c7bece56SGreg Clayton             const size_t regex_start_index = regex_var_list.GetSize();
5250d9a201eSRaphael Isemann             llvm::StringRef name_str = entry.ref();
52695eae423SZachary Turner             RegularExpression regex(name_str);
527f9d90bc5SJan Kratochvil             if (regex.IsValid()) {
52846747022SGreg Clayton               size_t num_matches = 0;
529b9c1b51eSKate Stone               const size_t num_new_regex_vars =
530b9c1b51eSKate Stone                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
53178a685aaSJim Ingham                                                          num_matches);
532b9c1b51eSKate Stone               if (num_new_regex_vars > 0) {
533b9c1b51eSKate Stone                 for (size_t regex_idx = regex_start_index,
534b9c1b51eSKate Stone                             end_index = regex_var_list.GetSize();
535b9c1b51eSKate Stone                      regex_idx < end_index; ++regex_idx) {
53646747022SGreg Clayton                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
537b9c1b51eSKate Stone                   if (var_sp) {
538b9c1b51eSKate Stone                     valobj_sp = frame->GetValueObjectForFrameVariable(
539b9c1b51eSKate Stone                         var_sp, m_varobj_options.use_dynamic);
540b9c1b51eSKate Stone                     if (valobj_sp) {
54173418dfeSEnrico Granata                       std::string scope_string;
54273418dfeSEnrico Granata                       if (m_option_variable.show_scope)
54373418dfeSEnrico Granata                         scope_string = GetScopeString(var_sp).str();
54473418dfeSEnrico Granata 
54573418dfeSEnrico Granata                       if (!scope_string.empty())
546771ef6d4SMalcolm Parsons                         s.PutCString(scope_string);
54773418dfeSEnrico Granata 
548b9c1b51eSKate Stone                       if (m_option_variable.show_decl &&
549b9c1b51eSKate Stone                           var_sp->GetDeclaration().GetFile()) {
55045ba8543SGreg Clayton                         bool show_fullpaths = false;
55145ba8543SGreg Clayton                         bool show_module = true;
552b9c1b51eSKate Stone                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
553b9c1b51eSKate Stone                                                     show_module))
55446747022SGreg Clayton                           s.PutCString(": ");
55546747022SGreg Clayton                       }
5564d93b8cdSEnrico Granata                       valobj_sp->Dump(result.GetOutputStream(), options);
55746747022SGreg Clayton                     }
55846747022SGreg Clayton                   }
55946747022SGreg Clayton                 }
560b9c1b51eSKate Stone               } else if (num_matches == 0) {
561b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: no variables matched "
562b9c1b51eSKate Stone                                                "the regular expression '%s'.\n",
563f965cc86SZachary Turner                                                entry.c_str());
56446747022SGreg Clayton               }
565b9c1b51eSKate Stone             } else {
5663af3f1e8SJonas Devlieghere               if (llvm::Error err = regex.GetError())
5673af3f1e8SJonas Devlieghere                 result.GetErrorStream().Printf(
5683af3f1e8SJonas Devlieghere                     "error: %s\n", llvm::toString(std::move(err)).c_str());
56946747022SGreg Clayton               else
570b9c1b51eSKate Stone                 result.GetErrorStream().Printf(
571b9c1b51eSKate Stone                     "error: unknown regex error when compiling '%s'\n",
572f965cc86SZachary Turner                     entry.c_str());
57346747022SGreg Clayton             }
574b9c1b51eSKate Stone           } else // No regex, either exact variable names or variable
575b9c1b51eSKate Stone                  // expressions.
57646747022SGreg Clayton           {
57797206d57SZachary Turner             Status error;
578b9c1b51eSKate Stone             uint32_t expr_path_options =
579b9c1b51eSKate Stone                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
58046252398SEnrico Granata                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
58146252398SEnrico Granata                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
5822837b766SJim Ingham             lldb::VariableSP var_sp;
583b9c1b51eSKate Stone             valobj_sp = frame->GetValueForVariableExpressionPath(
5840d9a201eSRaphael Isemann                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
585b9c1b51eSKate Stone                 var_sp, error);
586b9c1b51eSKate Stone             if (valobj_sp) {
58773418dfeSEnrico Granata               std::string scope_string;
58873418dfeSEnrico Granata               if (m_option_variable.show_scope)
58973418dfeSEnrico Granata                 scope_string = GetScopeString(var_sp).str();
59073418dfeSEnrico Granata 
59173418dfeSEnrico Granata               if (!scope_string.empty())
592771ef6d4SMalcolm Parsons                 s.PutCString(scope_string);
593b9c1b51eSKate Stone               if (m_option_variable.show_decl && var_sp &&
594b9c1b51eSKate Stone                   var_sp->GetDeclaration().GetFile()) {
595a134cc1bSGreg Clayton                 var_sp->GetDeclaration().DumpStopContext(&s, false);
596a134cc1bSGreg Clayton                 s.PutCString(": ");
597a134cc1bSGreg Clayton               }
5980c489f58SEnrico Granata 
5990c489f58SEnrico Granata               options.SetFormat(format);
600b9c1b51eSKate Stone               options.SetVariableFormatDisplayLanguage(
601b9c1b51eSKate Stone                   valobj_sp->GetPreferredDisplayLanguage());
602887062aeSJohnny Chen 
603887062aeSJohnny Chen               Stream &output_stream = result.GetOutputStream();
604f965cc86SZachary Turner               options.SetRootValueObjectName(
605f965cc86SZachary Turner                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
6064d93b8cdSEnrico Granata               valobj_sp->Dump(output_stream, options);
607b9c1b51eSKate Stone             } else {
608c8ecc2a9SEugene Zelenko               const char *error_cstr = error.AsCString(nullptr);
60954979cddSGreg Clayton               if (error_cstr)
61054979cddSGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
61154979cddSGreg Clayton               else
612b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: unable to find any "
613b9c1b51eSKate Stone                                                "variable expression path that "
614b9c1b51eSKate Stone                                                "matches '%s'.\n",
615f965cc86SZachary Turner                                                entry.c_str());
6166d56d2ceSJim Ingham             }
6176d56d2ceSJim Ingham           }
6186d56d2ceSJim Ingham         }
619b9c1b51eSKate Stone       } else // No command arg specified.  Use variable_list, instead.
6206d56d2ceSJim Ingham       {
621c7bece56SGreg Clayton         const size_t num_variables = variable_list->GetSize();
622b9c1b51eSKate Stone         if (num_variables > 0) {
623b9c1b51eSKate Stone           for (size_t i = 0; i < num_variables; i++) {
6241a65ae11SGreg Clayton             var_sp = variable_list->GetVariableAtIndex(i);
625f955efc0SSylvestre Ledru             switch (var_sp->GetScope()) {
626eb236735SJim Ingham             case eValueTypeVariableGlobal:
627eb236735SJim Ingham               if (!m_option_variable.show_globals)
628eb236735SJim Ingham                 continue;
629eb236735SJim Ingham               break;
630eb236735SJim Ingham             case eValueTypeVariableStatic:
631eb236735SJim Ingham               if (!m_option_variable.show_globals)
632eb236735SJim Ingham                 continue;
633eb236735SJim Ingham               break;
634eb236735SJim Ingham             case eValueTypeVariableArgument:
635eb236735SJim Ingham               if (!m_option_variable.show_args)
636eb236735SJim Ingham                 continue;
637eb236735SJim Ingham               break;
638eb236735SJim Ingham             case eValueTypeVariableLocal:
639eb236735SJim Ingham               if (!m_option_variable.show_locals)
640eb236735SJim Ingham                 continue;
641eb236735SJim Ingham               break;
642eb236735SJim Ingham             default:
643eb236735SJim Ingham               continue;
644eb236735SJim Ingham               break;
645eb236735SJim Ingham             }
646560558ebSEnrico Granata             std::string scope_string;
647eb236735SJim Ingham             if (m_option_variable.show_scope)
64873418dfeSEnrico Granata               scope_string = GetScopeString(var_sp).str();
6496d56d2ceSJim Ingham 
65005097246SAdrian Prantl             // Use the variable object code to make sure we are using the same
65105097246SAdrian Prantl             // APIs as the public API will be using...
652b9c1b51eSKate Stone             valobj_sp = frame->GetValueObjectForFrameVariable(
653b9c1b51eSKate Stone                 var_sp, m_varobj_options.use_dynamic);
654b9c1b51eSKate Stone             if (valobj_sp) {
65505097246SAdrian Prantl               // When dumping all variables, don't print any variables that are
65605097246SAdrian Prantl               // not in scope to avoid extra unneeded output
657b9c1b51eSKate Stone               if (valobj_sp->IsInScope()) {
658b9c1b51eSKate Stone                 if (!valobj_sp->GetTargetSP()
659b9c1b51eSKate Stone                          ->GetDisplayRuntimeSupportValues() &&
660c8ecc2a9SEugene Zelenko                     valobj_sp->IsRuntimeSupportValue())
661560558ebSEnrico Granata                   continue;
662560558ebSEnrico Granata 
663560558ebSEnrico Granata                 if (!scope_string.empty())
664771ef6d4SMalcolm Parsons                   s.PutCString(scope_string);
665560558ebSEnrico Granata 
666b9c1b51eSKate Stone                 if (m_option_variable.show_decl &&
667b9c1b51eSKate Stone                     var_sp->GetDeclaration().GetFile()) {
668a134cc1bSGreg Clayton                   var_sp->GetDeclaration().DumpStopContext(&s, false);
669a134cc1bSGreg Clayton                   s.PutCString(": ");
670a134cc1bSGreg Clayton                 }
6710c489f58SEnrico Granata 
6720c489f58SEnrico Granata                 options.SetFormat(format);
673b9c1b51eSKate Stone                 options.SetVariableFormatDisplayLanguage(
674b9c1b51eSKate Stone                     valobj_sp->GetPreferredDisplayLanguage());
675f965cc86SZachary Turner                 options.SetRootValueObjectName(
676f965cc86SZachary Turner                     var_sp ? var_sp->GetName().AsCString() : nullptr);
6774d93b8cdSEnrico Granata                 valobj_sp->Dump(result.GetOutputStream(), options);
678a134cc1bSGreg Clayton               }
679a134cc1bSGreg Clayton             }
6806d56d2ceSJim Ingham           }
6816d56d2ceSJim Ingham         }
6826d56d2ceSJim Ingham       }
6836d56d2ceSJim Ingham       result.SetStatus(eReturnStatusSuccessFinishResult);
6846d56d2ceSJim Ingham     }
68561a80ba6SEnrico Granata 
68641ae8e74SKuba Mracek     if (m_option_variable.show_recognized_args) {
68741ae8e74SKuba Mracek       auto recognized_frame = frame->GetRecognizedFrame();
68841ae8e74SKuba Mracek       if (recognized_frame) {
68941ae8e74SKuba Mracek         ValueObjectListSP recognized_arg_list =
69041ae8e74SKuba Mracek             recognized_frame->GetRecognizedArguments();
69141ae8e74SKuba Mracek         if (recognized_arg_list) {
69241ae8e74SKuba Mracek           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
69341ae8e74SKuba Mracek             options.SetFormat(m_option_format.GetFormat());
69441ae8e74SKuba Mracek             options.SetVariableFormatDisplayLanguage(
69541ae8e74SKuba Mracek                 rec_value_sp->GetPreferredDisplayLanguage());
69641ae8e74SKuba Mracek             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
69741ae8e74SKuba Mracek             rec_value_sp->Dump(result.GetOutputStream(), options);
69841ae8e74SKuba Mracek           }
69941ae8e74SKuba Mracek         }
70041ae8e74SKuba Mracek       }
70141ae8e74SKuba Mracek     }
70241ae8e74SKuba Mracek 
703b9c1b51eSKate Stone     if (m_interpreter.TruncationWarningNecessary()) {
70461a80ba6SEnrico Granata       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
70561a80ba6SEnrico Granata                                       m_cmd_name.c_str());
70661a80ba6SEnrico Granata       m_interpreter.TruncationWarningGiven();
70761a80ba6SEnrico Granata     }
70861a80ba6SEnrico Granata 
70924fff242SDavide Italiano     // Increment statistics.
71024fff242SDavide Italiano     bool res = result.Succeeded();
711cb2380c9SRaphael Isemann     Target &target = GetSelectedOrDummyTarget();
71224fff242SDavide Italiano     if (res)
713cb2380c9SRaphael Isemann       target.IncrementStats(StatisticKind::FrameVarSuccess);
71424fff242SDavide Italiano     else
715cb2380c9SRaphael Isemann       target.IncrementStats(StatisticKind::FrameVarFailure);
71624fff242SDavide Italiano     return res;
7176d56d2ceSJim Ingham   }
7186d56d2ceSJim Ingham 
7192837b766SJim Ingham   OptionGroupOptions m_option_group;
720715c2365SGreg Clayton   OptionGroupVariable m_option_variable;
7211deb7962SGreg Clayton   OptionGroupFormat m_option_format;
7222837b766SJim Ingham   OptionGroupValueObjectDisplay m_varobj_options;
7236d56d2ceSJim Ingham };
7246d56d2ceSJim Ingham 
72541ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer
72641ae8e74SKuba Mracek 
727ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_recognizer_add
728ec67e734SRaphael Isemann #include "CommandOptions.inc"
72941ae8e74SKuba Mracek 
73041ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
73141ae8e74SKuba Mracek private:
73241ae8e74SKuba Mracek   class CommandOptions : public Options {
73341ae8e74SKuba Mracek   public:
73441ae8e74SKuba Mracek     CommandOptions() : Options() {}
73541ae8e74SKuba Mracek     ~CommandOptions() override = default;
73641ae8e74SKuba Mracek 
73741ae8e74SKuba Mracek     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
73841ae8e74SKuba Mracek                           ExecutionContext *execution_context) override {
73941ae8e74SKuba Mracek       Status error;
74041ae8e74SKuba Mracek       const int short_option = m_getopt_table[option_idx].val;
74141ae8e74SKuba Mracek 
74241ae8e74SKuba Mracek       switch (short_option) {
74354c496daSRoman Podoliaka       case 'f': {
74454c496daSRoman Podoliaka         bool value, success;
74554c496daSRoman Podoliaka         value = OptionArgParser::ToBoolean(option_arg, true, &success);
74654c496daSRoman Podoliaka         if (success) {
74754c496daSRoman Podoliaka           m_first_instruction_only = value;
74854c496daSRoman Podoliaka         } else {
74954c496daSRoman Podoliaka           error.SetErrorStringWithFormat(
75054c496daSRoman Podoliaka               "invalid boolean value '%s' passed for -f option",
75154c496daSRoman Podoliaka               option_arg.str().c_str());
75254c496daSRoman Podoliaka         }
75354c496daSRoman Podoliaka       } break;
75441ae8e74SKuba Mracek       case 'l':
75541ae8e74SKuba Mracek         m_class_name = std::string(option_arg);
75641ae8e74SKuba Mracek         break;
75741ae8e74SKuba Mracek       case 's':
75841ae8e74SKuba Mracek         m_module = std::string(option_arg);
75941ae8e74SKuba Mracek         break;
76041ae8e74SKuba Mracek       case 'n':
761db31e2e1SMed Ismail Bennani         m_symbols.push_back(std::string(option_arg));
76241ae8e74SKuba Mracek         break;
76341ae8e74SKuba Mracek       case 'x':
76441ae8e74SKuba Mracek         m_regex = true;
76541ae8e74SKuba Mracek         break;
76641ae8e74SKuba Mracek       default:
76736162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
76841ae8e74SKuba Mracek       }
76941ae8e74SKuba Mracek 
77041ae8e74SKuba Mracek       return error;
77141ae8e74SKuba Mracek     }
77241ae8e74SKuba Mracek 
77341ae8e74SKuba Mracek     void OptionParsingStarting(ExecutionContext *execution_context) override {
77441ae8e74SKuba Mracek       m_module = "";
775db31e2e1SMed Ismail Bennani       m_symbols.clear();
77641ae8e74SKuba Mracek       m_class_name = "";
77741ae8e74SKuba Mracek       m_regex = false;
77854c496daSRoman Podoliaka       m_first_instruction_only = true;
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;
79054c496daSRoman Podoliaka     bool m_first_instruction_only;
79141ae8e74SKuba Mracek   };
79241ae8e74SKuba Mracek 
79341ae8e74SKuba Mracek   CommandOptions m_options;
79441ae8e74SKuba Mracek 
79541ae8e74SKuba Mracek   Options *GetOptions() override { return &m_options; }
79641ae8e74SKuba Mracek 
79741ae8e74SKuba Mracek protected:
79841ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override;
79941ae8e74SKuba Mracek 
80041ae8e74SKuba Mracek public:
80141ae8e74SKuba Mracek   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
80241ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer add",
80341ae8e74SKuba Mracek                             "Add a new frame recognizer.", nullptr),
80441ae8e74SKuba Mracek         m_options() {
80541ae8e74SKuba Mracek     SetHelpLong(R"(
80641ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on
80741ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source
80841ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments
80941ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments.
81041ae8e74SKuba Mracek 
81141ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class
81241ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a
81341ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type
81441ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize.
81541ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that
81641ae8e74SKuba Mracek represent the recognized arguments.
81741ae8e74SKuba Mracek 
81841ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc
81941ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows:
82041ae8e74SKuba Mracek 
82141ae8e74SKuba Mracek   class LibcFdRecognizer(object):
82241ae8e74SKuba Mracek     def get_recognized_arguments(self, frame):
82341ae8e74SKuba Mracek       if frame.name in ["read", "write", "close"]:
82441ae8e74SKuba Mracek         fd = frame.EvaluateExpression("$arg1").unsigned
82541ae8e74SKuba Mracek         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
82641ae8e74SKuba Mracek         return [value]
82741ae8e74SKuba Mracek       return []
82841ae8e74SKuba Mracek 
82941ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script
83041ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'.
83141ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is
83241ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
83341ae8e74SKuba Mracek in other modules:
83441ae8e74SKuba Mracek 
83541ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py
83641ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
83741ae8e74SKuba Mracek 
83841ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we
83941ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable':
84041ae8e74SKuba Mracek 
84141ae8e74SKuba Mracek (lldb) b read
84241ae8e74SKuba Mracek (lldb) r
84341ae8e74SKuba Mracek Process 1234 stopped
84441ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
84541ae8e74SKuba Mracek     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
84641ae8e74SKuba Mracek (lldb) frame variable
84741ae8e74SKuba Mracek (int) fd = 3
84841ae8e74SKuba Mracek 
84941ae8e74SKuba Mracek     )");
85041ae8e74SKuba Mracek   }
85141ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerAdd() override = default;
85241ae8e74SKuba Mracek };
85341ae8e74SKuba Mracek 
85441ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
85541ae8e74SKuba Mracek                                                 CommandReturnObject &result) {
8564e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
85741ae8e74SKuba Mracek   if (m_options.m_class_name.empty()) {
85841ae8e74SKuba Mracek     result.AppendErrorWithFormat(
85941ae8e74SKuba Mracek         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
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     return false;
86741ae8e74SKuba Mracek   }
86841ae8e74SKuba Mracek 
869db31e2e1SMed Ismail Bennani   if (m_options.m_symbols.empty()) {
870db31e2e1SMed Ismail Bennani     result.AppendErrorWithFormat(
871db31e2e1SMed Ismail Bennani         "%s needs at least one symbol name (-n argument).\n",
872db31e2e1SMed Ismail Bennani         m_cmd_name.c_str());
873db31e2e1SMed Ismail Bennani     return false;
874db31e2e1SMed Ismail Bennani   }
875db31e2e1SMed Ismail Bennani 
876db31e2e1SMed Ismail Bennani   if (m_options.m_regex && m_options.m_symbols.size() > 1) {
877db31e2e1SMed Ismail Bennani     result.AppendErrorWithFormat(
878db31e2e1SMed Ismail Bennani         "%s needs only one symbol regular expression (-n argument).\n",
87941ae8e74SKuba Mracek         m_cmd_name.c_str());
88041ae8e74SKuba Mracek     return false;
88141ae8e74SKuba Mracek   }
88241ae8e74SKuba Mracek 
8832b29b432SJonas Devlieghere   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
88441ae8e74SKuba Mracek 
88541ae8e74SKuba Mracek   if (interpreter &&
88641ae8e74SKuba Mracek       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
887a925974bSAdrian Prantl     result.AppendWarning("The provided class does not exist - please define it "
88841ae8e74SKuba Mracek                          "before attempting to use this frame recognizer");
88941ae8e74SKuba Mracek   }
89041ae8e74SKuba Mracek 
89141ae8e74SKuba Mracek   StackFrameRecognizerSP recognizer_sp =
89241ae8e74SKuba Mracek       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
89341ae8e74SKuba Mracek           interpreter, m_options.m_class_name.c_str()));
89441ae8e74SKuba Mracek   if (m_options.m_regex) {
89541ae8e74SKuba Mracek     auto module =
89641ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_module));
89741ae8e74SKuba Mracek     auto func =
898db31e2e1SMed Ismail Bennani         RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
8991b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
90054c496daSRoman Podoliaka         recognizer_sp, module, func, m_options.m_first_instruction_only);
90141ae8e74SKuba Mracek   } else {
90241ae8e74SKuba Mracek     auto module = ConstString(m_options.m_module);
903db31e2e1SMed Ismail Bennani     std::vector<ConstString> symbols(m_options.m_symbols.begin(),
904db31e2e1SMed Ismail Bennani                                      m_options.m_symbols.end());
9051b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
90654c496daSRoman Podoliaka         recognizer_sp, module, symbols, m_options.m_first_instruction_only);
90741ae8e74SKuba Mracek   }
908f80d2655SKuba Mracek #endif
90941ae8e74SKuba Mracek 
91041ae8e74SKuba Mracek   result.SetStatus(eReturnStatusSuccessFinishNoResult);
91141ae8e74SKuba Mracek   return result.Succeeded();
91241ae8e74SKuba Mracek }
91341ae8e74SKuba Mracek 
91441ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
91541ae8e74SKuba Mracek public:
91641ae8e74SKuba Mracek   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
91741ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer clear",
91841ae8e74SKuba Mracek                             "Delete all frame recognizers.", nullptr) {}
91941ae8e74SKuba Mracek 
92041ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerClear() override = default;
92141ae8e74SKuba Mracek 
92241ae8e74SKuba Mracek protected:
92341ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
9241b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget()
9251b7c9eaeSRaphael Isemann         .GetFrameRecognizerManager()
9261b7c9eaeSRaphael Isemann         .RemoveAllRecognizers();
92741ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
92841ae8e74SKuba Mracek     return result.Succeeded();
92941ae8e74SKuba Mracek   }
93041ae8e74SKuba Mracek };
93141ae8e74SKuba Mracek 
93241ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
93341ae8e74SKuba Mracek public:
93441ae8e74SKuba Mracek   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
93541ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer delete",
93641ae8e74SKuba Mracek                             "Delete an existing frame recognizer.", nullptr) {}
93741ae8e74SKuba Mracek 
93841ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerDelete() override = default;
93941ae8e74SKuba Mracek 
940c37d25f0SGongyu Deng   void
941c37d25f0SGongyu Deng   HandleArgumentCompletion(CompletionRequest &request,
942c37d25f0SGongyu Deng                            OptionElementVector &opt_element_vector) override {
943c37d25f0SGongyu Deng     if (request.GetCursorIndex() != 0)
944c37d25f0SGongyu Deng       return;
945c37d25f0SGongyu Deng 
9461b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
947c37d25f0SGongyu Deng         [&request](uint32_t rid, std::string rname, std::string module,
948c37d25f0SGongyu Deng                    llvm::ArrayRef<lldb_private::ConstString> symbols,
949c37d25f0SGongyu Deng                    bool regexp) {
950c37d25f0SGongyu Deng           StreamString strm;
951c37d25f0SGongyu Deng           if (rname.empty())
952c37d25f0SGongyu Deng             rname = "(internal)";
953c37d25f0SGongyu Deng 
954c37d25f0SGongyu Deng           strm << rname;
955c37d25f0SGongyu Deng           if (!module.empty())
956c37d25f0SGongyu Deng             strm << ", module " << module;
957c37d25f0SGongyu Deng           if (!symbols.empty())
958c37d25f0SGongyu Deng             for (auto &symbol : symbols)
959c37d25f0SGongyu Deng               strm << ", symbol " << symbol;
960c37d25f0SGongyu Deng           if (regexp)
961c37d25f0SGongyu Deng             strm << " (regexp)";
962c37d25f0SGongyu Deng 
963c37d25f0SGongyu Deng           request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
964c37d25f0SGongyu Deng         });
965c37d25f0SGongyu Deng   }
966c37d25f0SGongyu Deng 
96741ae8e74SKuba Mracek protected:
96841ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
96941ae8e74SKuba Mracek     if (command.GetArgumentCount() == 0) {
97041ae8e74SKuba Mracek       if (!m_interpreter.Confirm(
97141ae8e74SKuba Mracek               "About to delete all frame recognizers, do you want to do that?",
97241ae8e74SKuba Mracek               true)) {
97341ae8e74SKuba Mracek         result.AppendMessage("Operation cancelled...");
97441ae8e74SKuba Mracek         return false;
97541ae8e74SKuba Mracek       }
97641ae8e74SKuba Mracek 
9771b7c9eaeSRaphael Isemann       GetSelectedOrDummyTarget()
9781b7c9eaeSRaphael Isemann           .GetFrameRecognizerManager()
9791b7c9eaeSRaphael Isemann           .RemoveAllRecognizers();
98041ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
98141ae8e74SKuba Mracek       return result.Succeeded();
98241ae8e74SKuba Mracek     }
98341ae8e74SKuba Mracek 
98441ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
98541ae8e74SKuba Mracek       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
98641ae8e74SKuba Mracek                                    m_cmd_name.c_str());
98741ae8e74SKuba Mracek       return false;
98841ae8e74SKuba Mracek     }
98941ae8e74SKuba Mracek 
9909010cef2SRaphael Isemann     uint32_t recognizer_id;
9919010cef2SRaphael Isemann     if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
9929010cef2SRaphael Isemann       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
9939010cef2SRaphael Isemann                                    command.GetArgumentAtIndex(0));
9949010cef2SRaphael Isemann       return false;
9959010cef2SRaphael Isemann     }
99641ae8e74SKuba Mracek 
9975477fbc2SRaphael Isemann     if (!GetSelectedOrDummyTarget()
9981b7c9eaeSRaphael Isemann              .GetFrameRecognizerManager()
9995477fbc2SRaphael Isemann              .RemoveRecognizerWithID(recognizer_id)) {
10005477fbc2SRaphael Isemann       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
10015477fbc2SRaphael Isemann                                    command.GetArgumentAtIndex(0));
10025477fbc2SRaphael Isemann       return false;
10035477fbc2SRaphael Isemann     }
100441ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
100541ae8e74SKuba Mracek     return result.Succeeded();
100641ae8e74SKuba Mracek   }
100741ae8e74SKuba Mracek };
100841ae8e74SKuba Mracek 
100941ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed {
101041ae8e74SKuba Mracek public:
101141ae8e74SKuba Mracek   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
101241ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer list",
101341ae8e74SKuba Mracek                             "Show a list of active frame recognizers.",
101441ae8e74SKuba Mracek                             nullptr) {}
101541ae8e74SKuba Mracek 
101641ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerList() override = default;
101741ae8e74SKuba Mracek 
101841ae8e74SKuba Mracek protected:
101941ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
102041ae8e74SKuba Mracek     bool any_printed = false;
10211b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
1022db31e2e1SMed Ismail Bennani         [&result, &any_printed](
1023db31e2e1SMed Ismail Bennani             uint32_t recognizer_id, std::string name, std::string module,
1024db31e2e1SMed Ismail Bennani             llvm::ArrayRef<ConstString> symbols, bool regexp) {
1025cb0c4ee3SMed Ismail Bennani           Stream &stream = result.GetOutputStream();
1026cb0c4ee3SMed Ismail Bennani 
1027cb0c4ee3SMed Ismail Bennani           if (name.empty())
1028a925974bSAdrian Prantl             name = "(internal)";
1029cb0c4ee3SMed Ismail Bennani 
1030cb0c4ee3SMed Ismail Bennani           stream << std::to_string(recognizer_id) << ": " << name;
1031cb0c4ee3SMed Ismail Bennani           if (!module.empty())
1032cb0c4ee3SMed Ismail Bennani             stream << ", module " << module;
1033db31e2e1SMed Ismail Bennani           if (!symbols.empty())
1034db31e2e1SMed Ismail Bennani             for (auto &symbol : symbols)
1035db31e2e1SMed Ismail Bennani               stream << ", symbol " << symbol;
1036cb0c4ee3SMed Ismail Bennani           if (regexp)
1037cb0c4ee3SMed Ismail Bennani             stream << " (regexp)";
1038cb0c4ee3SMed Ismail Bennani 
1039cb0c4ee3SMed Ismail Bennani           stream.EOL();
1040cb0c4ee3SMed Ismail Bennani           stream.Flush();
1041cb0c4ee3SMed Ismail Bennani 
104241ae8e74SKuba Mracek           any_printed = true;
104341ae8e74SKuba Mracek         });
104441ae8e74SKuba Mracek 
104541ae8e74SKuba Mracek     if (any_printed)
104641ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
104741ae8e74SKuba Mracek     else {
104841ae8e74SKuba Mracek       result.GetOutputStream().PutCString("no matching results found.\n");
104941ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishNoResult);
105041ae8e74SKuba Mracek     }
105141ae8e74SKuba Mracek     return result.Succeeded();
105241ae8e74SKuba Mracek   }
105341ae8e74SKuba Mracek };
105441ae8e74SKuba Mracek 
105541ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
105641ae8e74SKuba Mracek public:
105741ae8e74SKuba Mracek   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
105841ae8e74SKuba Mracek       : CommandObjectParsed(
105941ae8e74SKuba Mracek             interpreter, "frame recognizer info",
106041ae8e74SKuba Mracek             "Show which frame recognizer is applied a stack frame (if any).",
106141ae8e74SKuba Mracek             nullptr) {
106241ae8e74SKuba Mracek     CommandArgumentEntry arg;
106341ae8e74SKuba Mracek     CommandArgumentData index_arg;
106441ae8e74SKuba Mracek 
106541ae8e74SKuba Mracek     // Define the first (and only) variant of this arg.
106641ae8e74SKuba Mracek     index_arg.arg_type = eArgTypeFrameIndex;
106741ae8e74SKuba Mracek     index_arg.arg_repetition = eArgRepeatPlain;
106841ae8e74SKuba Mracek 
106941ae8e74SKuba Mracek     // There is only one variant this argument could be; put it into the
107041ae8e74SKuba Mracek     // argument entry.
107141ae8e74SKuba Mracek     arg.push_back(index_arg);
107241ae8e74SKuba Mracek 
107341ae8e74SKuba Mracek     // Push the data for the first argument into the m_arguments vector.
107441ae8e74SKuba Mracek     m_arguments.push_back(arg);
107541ae8e74SKuba Mracek   }
107641ae8e74SKuba Mracek 
107741ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerInfo() override = default;
107841ae8e74SKuba Mracek 
107941ae8e74SKuba Mracek protected:
108041ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
10819010cef2SRaphael Isemann     const char *frame_index_str = command.GetArgumentAtIndex(0);
10829010cef2SRaphael Isemann     uint32_t frame_index;
10839010cef2SRaphael Isemann     if (!llvm::to_integer(frame_index_str, frame_index)) {
10849010cef2SRaphael Isemann       result.AppendErrorWithFormat("'%s' is not a valid frame index.",
10859010cef2SRaphael Isemann                                    frame_index_str);
10869010cef2SRaphael Isemann       return false;
10879010cef2SRaphael Isemann     }
10889010cef2SRaphael Isemann 
108941ae8e74SKuba Mracek     Process *process = m_exe_ctx.GetProcessPtr();
109041ae8e74SKuba Mracek     if (process == nullptr) {
109141ae8e74SKuba Mracek       result.AppendError("no process");
109241ae8e74SKuba Mracek       return false;
109341ae8e74SKuba Mracek     }
109441ae8e74SKuba Mracek     Thread *thread = m_exe_ctx.GetThreadPtr();
109541ae8e74SKuba Mracek     if (thread == nullptr) {
109641ae8e74SKuba Mracek       result.AppendError("no thread");
109741ae8e74SKuba Mracek       return false;
109841ae8e74SKuba Mracek     }
109941ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
110041ae8e74SKuba Mracek       result.AppendErrorWithFormat(
110141ae8e74SKuba Mracek           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
110241ae8e74SKuba Mracek       return false;
110341ae8e74SKuba Mracek     }
110441ae8e74SKuba Mracek 
110541ae8e74SKuba Mracek     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
110641ae8e74SKuba Mracek     if (!frame_sp) {
110741ae8e74SKuba Mracek       result.AppendErrorWithFormat("no frame with index %u", frame_index);
110841ae8e74SKuba Mracek       return false;
110941ae8e74SKuba Mracek     }
111041ae8e74SKuba Mracek 
11111b7c9eaeSRaphael Isemann     auto recognizer = GetSelectedOrDummyTarget()
11121b7c9eaeSRaphael Isemann                           .GetFrameRecognizerManager()
11131b7c9eaeSRaphael Isemann                           .GetRecognizerForFrame(frame_sp);
111441ae8e74SKuba Mracek 
111541ae8e74SKuba Mracek     Stream &output_stream = result.GetOutputStream();
111641ae8e74SKuba Mracek     output_stream.Printf("frame %d ", frame_index);
111741ae8e74SKuba Mracek     if (recognizer) {
111841ae8e74SKuba Mracek       output_stream << "is recognized by ";
111941ae8e74SKuba Mracek       output_stream << recognizer->GetName();
112041ae8e74SKuba Mracek     } else {
112141ae8e74SKuba Mracek       output_stream << "not recognized by any recognizer";
112241ae8e74SKuba Mracek     }
112341ae8e74SKuba Mracek     output_stream.EOL();
112441ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
112541ae8e74SKuba Mracek     return result.Succeeded();
112641ae8e74SKuba Mracek   }
112741ae8e74SKuba Mracek };
112841ae8e74SKuba Mracek 
112941ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword {
113041ae8e74SKuba Mracek public:
113141ae8e74SKuba Mracek   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
113241ae8e74SKuba Mracek       : CommandObjectMultiword(
113341ae8e74SKuba Mracek             interpreter, "frame recognizer",
113441ae8e74SKuba Mracek             "Commands for editing and viewing frame recognizers.",
113541ae8e74SKuba Mracek             "frame recognizer [<sub-command-options>] ") {
1136a925974bSAdrian Prantl     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1137a925974bSAdrian Prantl                               interpreter)));
113841ae8e74SKuba Mracek     LoadSubCommand(
113941ae8e74SKuba Mracek         "clear",
114041ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
114141ae8e74SKuba Mracek     LoadSubCommand(
114241ae8e74SKuba Mracek         "delete",
114341ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1144a925974bSAdrian Prantl     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1145a925974bSAdrian Prantl                                interpreter)));
1146a925974bSAdrian Prantl     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1147a925974bSAdrian Prantl                                interpreter)));
114841ae8e74SKuba Mracek   }
114941ae8e74SKuba Mracek 
115041ae8e74SKuba Mracek   ~CommandObjectFrameRecognizer() override = default;
115141ae8e74SKuba Mracek };
115241ae8e74SKuba Mracek 
115330fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
115430fdc8d8SChris Lattner 
115530fdc8d8SChris Lattner // CommandObjectMultiwordFrame
115630fdc8d8SChris Lattner 
1157b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1158b9c1b51eSKate Stone     CommandInterpreter &interpreter)
1159a925974bSAdrian Prantl     : CommandObjectMultiword(interpreter, "frame",
1160a925974bSAdrian Prantl                              "Commands for selecting and "
1161b9c1b51eSKate Stone                              "examing the current "
1162b9c1b51eSKate Stone                              "thread's stack frames.",
1163b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
1164b9c1b51eSKate Stone   LoadSubCommand("diagnose",
1165b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1166b9c1b51eSKate Stone   LoadSubCommand("info",
1167b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1168b9c1b51eSKate Stone   LoadSubCommand("select",
1169b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1170b9c1b51eSKate Stone   LoadSubCommand("variable",
1171b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
11724e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
1173a925974bSAdrian Prantl   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1174a925974bSAdrian Prantl                                    interpreter)));
117541ae8e74SKuba Mracek #endif
117630fdc8d8SChris Lattner }
117730fdc8d8SChris Lattner 
1178c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1179