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:
52*abb0ed44SKazu Hirata     CommandOptions() { 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",
108722a2fb7SDave 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 |
113*abb0ed44SKazu Hirata                                 eCommandProcessMustBePaused) {
1144740a734SSean Callanan     CommandArgumentEntry arg;
1154740a734SSean Callanan     CommandArgumentData index_arg;
1164740a734SSean Callanan 
1174740a734SSean Callanan     // Define the first (and only) variant of this arg.
1184740a734SSean Callanan     index_arg.arg_type = eArgTypeFrameIndex;
1194740a734SSean Callanan     index_arg.arg_repetition = eArgRepeatOptional;
1204740a734SSean Callanan 
121b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
122b9c1b51eSKate Stone     // argument entry.
1234740a734SSean Callanan     arg.push_back(index_arg);
1244740a734SSean Callanan 
1254740a734SSean Callanan     // Push the data for the first argument into the m_arguments vector.
1264740a734SSean Callanan     m_arguments.push_back(arg);
1274740a734SSean Callanan   }
1284740a734SSean Callanan 
1294740a734SSean Callanan   ~CommandObjectFrameDiagnose() override = default;
1304740a734SSean Callanan 
131b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
1324740a734SSean Callanan 
1334740a734SSean Callanan protected:
134b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1354740a734SSean Callanan     Thread *thread = m_exe_ctx.GetThreadPtr();
1364740a734SSean Callanan     StackFrameSP frame_sp = thread->GetSelectedFrame();
1374740a734SSean Callanan 
1384740a734SSean Callanan     ValueObjectSP valobj_sp;
1394740a734SSean Callanan 
140b9c1b51eSKate Stone     if (m_options.address.hasValue()) {
141b9c1b51eSKate Stone       if (m_options.reg.hasValue() || m_options.offset.hasValue()) {
142b9c1b51eSKate Stone         result.AppendError(
143b9c1b51eSKate Stone             "`frame diagnose --address` is incompatible with other arguments.");
1444740a734SSean Callanan         return false;
1454740a734SSean Callanan       }
1464740a734SSean Callanan       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue());
147b9c1b51eSKate Stone     } else if (m_options.reg.hasValue()) {
148b9c1b51eSKate Stone       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
149b9c1b51eSKate Stone           m_options.reg.getValue(), m_options.offset.getValueOr(0));
150b9c1b51eSKate Stone     } else {
1514740a734SSean Callanan       StopInfoSP stop_info_sp = thread->GetStopInfo();
152b9c1b51eSKate Stone       if (!stop_info_sp) {
1534740a734SSean Callanan         result.AppendError("No arguments provided, and no stop info.");
1544740a734SSean Callanan         return false;
1554740a734SSean Callanan       }
1564740a734SSean Callanan 
1574740a734SSean Callanan       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
1584740a734SSean Callanan     }
1594740a734SSean Callanan 
160b9c1b51eSKate Stone     if (!valobj_sp) {
1614740a734SSean Callanan       result.AppendError("No diagnosis available.");
1624740a734SSean Callanan       return false;
1634740a734SSean Callanan     }
1644740a734SSean Callanan 
165a925974bSAdrian Prantl     DumpValueObjectOptions::DeclPrintingHelper helper =
166a925974bSAdrian Prantl         [&valobj_sp](ConstString type, ConstString var,
167a925974bSAdrian Prantl                      const DumpValueObjectOptions &opts,
1683bc714b2SZachary Turner                      Stream &stream) -> bool {
169b9c1b51eSKate Stone       const ValueObject::GetExpressionPathFormat format = ValueObject::
170b9c1b51eSKate Stone           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
1713014efe0SAlex Langford       valobj_sp->GetExpressionPath(stream, format);
1724740a734SSean Callanan       stream.PutCString(" =");
1734740a734SSean Callanan       return true;
1744740a734SSean Callanan     };
1754740a734SSean Callanan 
1764740a734SSean Callanan     DumpValueObjectOptions options;
1774740a734SSean Callanan     options.SetDeclPrintingHelper(helper);
178b9c1b51eSKate Stone     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
179b9c1b51eSKate Stone                                options);
1804740a734SSean Callanan     printer.PrintValueObject();
1814740a734SSean Callanan 
1824740a734SSean Callanan     return true;
1834740a734SSean Callanan   }
1844740a734SSean Callanan 
1854740a734SSean Callanan   CommandOptions m_options;
1864740a734SSean Callanan };
1874740a734SSean Callanan 
18830fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo
18930fdc8d8SChris Lattner 
19030fdc8d8SChris Lattner // CommandObjectFrameInfo
19130fdc8d8SChris Lattner 
192b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed {
19330fdc8d8SChris Lattner public:
1947428a18cSKate Stone   CommandObjectFrameInfo(CommandInterpreter &interpreter)
195a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame info",
196a925974bSAdrian Prantl                             "List information about the current "
197b9c1b51eSKate Stone                             "stack frame in the current thread.",
198b9c1b51eSKate Stone                             "frame info",
199b9c1b51eSKate Stone                             eCommandRequiresFrame | eCommandTryTargetAPILock |
200a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
201a925974bSAdrian Prantl                                 eCommandProcessMustBePaused) {}
20230fdc8d8SChris Lattner 
203c8ecc2a9SEugene Zelenko   ~CommandObjectFrameInfo() override = default;
20430fdc8d8SChris Lattner 
2055a988416SJim Ingham protected:
206b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
207f9fc609fSGreg Clayton     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
20830fdc8d8SChris Lattner     result.SetStatus(eReturnStatusSuccessFinishResult);
20930fdc8d8SChris Lattner     return result.Succeeded();
21030fdc8d8SChris Lattner   }
21130fdc8d8SChris Lattner };
21230fdc8d8SChris Lattner 
21330fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect
21430fdc8d8SChris Lattner 
21530fdc8d8SChris Lattner // CommandObjectFrameSelect
21630fdc8d8SChris Lattner 
217ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_select
218ec67e734SRaphael Isemann #include "CommandOptions.inc"
2191f0f5b5bSZachary Turner 
220b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed {
22130fdc8d8SChris Lattner public:
222b9c1b51eSKate Stone   class CommandOptions : public Options {
223864174e1SGreg Clayton   public:
224*abb0ed44SKazu Hirata     CommandOptions() { OptionParsingStarting(nullptr); }
225864174e1SGreg Clayton 
226c8ecc2a9SEugene Zelenko     ~CommandOptions() override = default;
227864174e1SGreg Clayton 
22897206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
229b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
23097206d57SZachary Turner       Status error;
2313bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
232b9c1b51eSKate Stone       switch (short_option) {
233dab6f074SRaphael Isemann       case 'r': {
234dab6f074SRaphael Isemann         int32_t offset = 0;
235dab6f074SRaphael Isemann         if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
236b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
237fe11483bSZachary Turner                                          option_arg.str().c_str());
238dab6f074SRaphael Isemann         } else
239dab6f074SRaphael Isemann           relative_frame_offset = offset;
2405a039d55SRaphael Isemann         break;
241dab6f074SRaphael Isemann       }
242864174e1SGreg Clayton 
243864174e1SGreg Clayton       default:
24436162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
245864174e1SGreg Clayton       }
246864174e1SGreg Clayton 
247864174e1SGreg Clayton       return error;
248864174e1SGreg Clayton     }
249864174e1SGreg Clayton 
2505a039d55SRaphael Isemann     void OptionParsingStarting(ExecutionContext *execution_context) override {
251dab6f074SRaphael Isemann       relative_frame_offset.reset();
2525a039d55SRaphael Isemann     }
253864174e1SGreg Clayton 
2541f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
25570602439SZachary Turner       return llvm::makeArrayRef(g_frame_select_options);
2561f0f5b5bSZachary Turner     }
257864174e1SGreg Clayton 
258dab6f074SRaphael Isemann     llvm::Optional<int32_t> relative_frame_offset;
259864174e1SGreg Clayton   };
260864174e1SGreg Clayton 
2617428a18cSKate Stone   CommandObjectFrameSelect(CommandInterpreter &interpreter)
262a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame select",
263a925974bSAdrian Prantl                             "Select the current stack frame by "
264b9c1b51eSKate Stone                             "index from within the current thread "
265b9c1b51eSKate Stone                             "(see 'thread backtrace'.)",
266b9c1b51eSKate Stone                             nullptr,
267b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
268a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
269*abb0ed44SKazu Hirata                                 eCommandProcessMustBePaused) {
270405fe67fSCaroline Tice     CommandArgumentEntry arg;
271405fe67fSCaroline Tice     CommandArgumentData index_arg;
272405fe67fSCaroline Tice 
273405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
274405fe67fSCaroline Tice     index_arg.arg_type = eArgTypeFrameIndex;
275864174e1SGreg Clayton     index_arg.arg_repetition = eArgRepeatOptional;
276405fe67fSCaroline Tice 
277b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
278b9c1b51eSKate Stone     // argument entry.
279405fe67fSCaroline Tice     arg.push_back(index_arg);
280405fe67fSCaroline Tice 
281405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
282405fe67fSCaroline Tice     m_arguments.push_back(arg);
28330fdc8d8SChris Lattner   }
28430fdc8d8SChris Lattner 
285c8ecc2a9SEugene Zelenko   ~CommandObjectFrameSelect() override = default;
28630fdc8d8SChris Lattner 
28780eb4228SGongyu Deng   void
28880eb4228SGongyu Deng   HandleArgumentCompletion(CompletionRequest &request,
28980eb4228SGongyu Deng                            OptionElementVector &opt_element_vector) override {
29066fa73faSGongyu Deng     if (request.GetCursorIndex() != 0)
29180eb4228SGongyu Deng       return;
29280eb4228SGongyu Deng 
29366fa73faSGongyu Deng     CommandCompletions::InvokeCommonCompletionCallbacks(
29466fa73faSGongyu Deng         GetCommandInterpreter(), CommandCompletions::eFrameIndexCompletion,
29566fa73faSGongyu Deng         request, nullptr);
29680eb4228SGongyu Deng   }
29780eb4228SGongyu Deng 
298b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
299864174e1SGreg Clayton 
3005a988416SJim Ingham protected:
301b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
302b9c1b51eSKate Stone     // No need to check "thread" for validity as eCommandRequiresThread ensures
303b9c1b51eSKate Stone     // it is valid
304f9fc609fSGreg Clayton     Thread *thread = m_exe_ctx.GetThreadPtr();
305f9fc609fSGreg Clayton 
306864174e1SGreg Clayton     uint32_t frame_idx = UINT32_MAX;
307dab6f074SRaphael Isemann     if (m_options.relative_frame_offset.hasValue()) {
308864174e1SGreg Clayton       // The one and only argument is a signed relative frame index
309c14ee32dSGreg Clayton       frame_idx = thread->GetSelectedFrameIndex();
310864174e1SGreg Clayton       if (frame_idx == UINT32_MAX)
311864174e1SGreg Clayton         frame_idx = 0;
312864174e1SGreg Clayton 
313dab6f074SRaphael Isemann       if (*m_options.relative_frame_offset < 0) {
314dab6f074SRaphael Isemann         if (static_cast<int32_t>(frame_idx) >=
315dab6f074SRaphael Isemann             -*m_options.relative_frame_offset)
316dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
317b9c1b51eSKate Stone         else {
318b9c1b51eSKate Stone           if (frame_idx == 0) {
31905097246SAdrian Prantl             // If you are already at the bottom of the stack, then just warn
32005097246SAdrian Prantl             // and don't reset the frame.
3217428a18cSKate Stone             result.AppendError("Already at the bottom of the stack.");
322213b4546SJim Ingham             return false;
323b9c1b51eSKate Stone           } else
324864174e1SGreg Clayton             frame_idx = 0;
325864174e1SGreg Clayton         }
326dab6f074SRaphael Isemann       } else if (*m_options.relative_frame_offset > 0) {
327b9c1b51eSKate Stone         // I don't want "up 20" where "20" takes you past the top of the stack
328b9c1b51eSKate Stone         // to produce
329b9c1b51eSKate Stone         // an error, but rather to just go to the top.  So I have to count the
330b9c1b51eSKate Stone         // stack here...
331b0c72a5fSJim Ingham         const uint32_t num_frames = thread->GetStackFrameCount();
332b9c1b51eSKate Stone         if (static_cast<int32_t>(num_frames - frame_idx) >
333dab6f074SRaphael Isemann             *m_options.relative_frame_offset)
334dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
335b9c1b51eSKate Stone         else {
336b9c1b51eSKate Stone           if (frame_idx == num_frames - 1) {
337b9c1b51eSKate Stone             // If we are already at the top of the stack, just warn and don't
338b9c1b51eSKate Stone             // reset the frame.
3397428a18cSKate Stone             result.AppendError("Already at the top of the stack.");
340213b4546SJim Ingham             return false;
341b9c1b51eSKate Stone           } else
342864174e1SGreg Clayton             frame_idx = num_frames - 1;
343864174e1SGreg Clayton         }
344864174e1SGreg Clayton       }
345b9c1b51eSKate Stone     } else {
346f965cc86SZachary Turner       if (command.GetArgumentCount() > 1) {
347f965cc86SZachary Turner         result.AppendErrorWithFormat(
348f965cc86SZachary Turner             "too many arguments; expected frame-index, saw '%s'.\n",
349867e7d17SZachary Turner             command[0].c_str());
350f965cc86SZachary Turner         m_options.GenerateOptionUsage(
351f965cc86SZachary Turner             result.GetErrorStream(), this,
352f965cc86SZachary Turner             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
353f965cc86SZachary Turner         return false;
354f965cc86SZachary Turner       }
355f965cc86SZachary Turner 
356b9c1b51eSKate Stone       if (command.GetArgumentCount() == 1) {
3570d9a201eSRaphael Isemann         if (command[0].ref().getAsInteger(0, frame_idx)) {
358b9c1b51eSKate Stone           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
359f965cc86SZachary Turner                                        command[0].c_str());
360afbb0af8SJim Ingham           return false;
361afbb0af8SJim Ingham         }
362b9c1b51eSKate Stone       } else if (command.GetArgumentCount() == 0) {
36382d4a2b9SJason Molenda         frame_idx = thread->GetSelectedFrameIndex();
364b9c1b51eSKate Stone         if (frame_idx == UINT32_MAX) {
36582d4a2b9SJason Molenda           frame_idx = 0;
36682d4a2b9SJason Molenda         }
367864174e1SGreg Clayton       }
368864174e1SGreg Clayton     }
36930fdc8d8SChris Lattner 
370b9c1b51eSKate Stone     bool success = thread->SetSelectedFrameByIndexNoisily(
371b9c1b51eSKate Stone         frame_idx, result.GetOutputStream());
372b9c1b51eSKate Stone     if (success) {
373f9fc609fSGreg Clayton       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
37430fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
375b9c1b51eSKate Stone     } else {
376b9c1b51eSKate Stone       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
377b9c1b51eSKate Stone                                    frame_idx);
37893208b86SJim Ingham     }
37993208b86SJim Ingham 
38093208b86SJim Ingham     return result.Succeeded();
38130fdc8d8SChris Lattner   }
382864174e1SGreg Clayton 
383864174e1SGreg Clayton   CommandOptions m_options;
384864174e1SGreg Clayton };
385864174e1SGreg Clayton 
3866d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable
3876d56d2ceSJim Ingham // List images with associated information
388b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed {
3896d56d2ceSJim Ingham public:
3907428a18cSKate Stone   CommandObjectFrameVariable(CommandInterpreter &interpreter)
3917428a18cSKate Stone       : CommandObjectParsed(
392b9c1b51eSKate Stone             interpreter, "frame variable",
393b9c1b51eSKate Stone             "Show variables for the current stack frame. Defaults to all "
3947428a18cSKate Stone             "arguments and local variables in scope. Names of argument, "
395ef6817f9SDave Lee             "local, file static and file global variables can be specified.",
396a925974bSAdrian Prantl             nullptr,
397a925974bSAdrian Prantl             eCommandRequiresFrame | eCommandTryTargetAPILock |
398a925974bSAdrian Prantl                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
399a925974bSAdrian Prantl                 eCommandRequiresProcess),
400b9c1b51eSKate Stone         m_option_variable(
401b9c1b51eSKate Stone             true), // Include the frame specific options by passing "true"
402*abb0ed44SKazu Hirata         m_option_format(eFormatDefault) {
403ef6817f9SDave Lee     SetHelpLong(R"(
404ef6817f9SDave Lee Children of aggregate variables can be specified such as 'var->child.x'.  In
405ef6817f9SDave Lee 'frame variable', the operators -> and [] do not invoke operator overloads if
406ef6817f9SDave Lee they exist, but directly access the specified element.  If you want to trigger
407ef6817f9SDave Lee operator overloads use the expression command to print the variable instead.
408ef6817f9SDave Lee 
409ef6817f9SDave Lee It is worth noting that except for overloaded operators, when printing local
410ef6817f9SDave Lee variables 'expr local_var' and 'frame var local_var' produce the same results.
411ef6817f9SDave Lee However, 'frame variable' is more efficient, since it uses debug information and
412ef6817f9SDave Lee memory reads directly, rather than parsing and evaluating an expression, which
413ef6817f9SDave Lee may even involve JITing and running code in the target program.)");
414ef6817f9SDave Lee 
415405fe67fSCaroline Tice     CommandArgumentEntry arg;
416405fe67fSCaroline Tice     CommandArgumentData var_name_arg;
417405fe67fSCaroline Tice 
418405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
419405fe67fSCaroline Tice     var_name_arg.arg_type = eArgTypeVarName;
420405fe67fSCaroline Tice     var_name_arg.arg_repetition = eArgRepeatStar;
421405fe67fSCaroline Tice 
422b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
423b9c1b51eSKate Stone     // argument entry.
424405fe67fSCaroline Tice     arg.push_back(var_name_arg);
425405fe67fSCaroline Tice 
426405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
427405fe67fSCaroline Tice     m_arguments.push_back(arg);
4282837b766SJim Ingham 
429715c2365SGreg Clayton     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
430b9c1b51eSKate Stone     m_option_group.Append(&m_option_format,
431b9c1b51eSKate Stone                           OptionGroupFormat::OPTION_GROUP_FORMAT |
432b9c1b51eSKate Stone                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
433b9c1b51eSKate Stone                           LLDB_OPT_SET_1);
4342837b766SJim Ingham     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
4352837b766SJim Ingham     m_option_group.Finalize();
4366d56d2ceSJim Ingham   }
4376d56d2ceSJim Ingham 
438c8ecc2a9SEugene Zelenko   ~CommandObjectFrameVariable() override = default;
4396d56d2ceSJim Ingham 
440b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
441f21feadcSGreg Clayton 
442ae34ed2cSRaphael Isemann   void
443ae34ed2cSRaphael Isemann   HandleArgumentCompletion(CompletionRequest &request,
4442443bbd4SRaphael Isemann                            OptionElementVector &opt_element_vector) override {
445f21feadcSGreg Clayton     // Arguments are the standard source file completer.
446b9c1b51eSKate Stone     CommandCompletions::InvokeCommonCompletionCallbacks(
447b9c1b51eSKate Stone         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
448a2e76c0bSRaphael Isemann         request, nullptr);
449f21feadcSGreg Clayton   }
4506d56d2ceSJim Ingham 
4515a988416SJim Ingham protected:
45273418dfeSEnrico Granata   llvm::StringRef GetScopeString(VariableSP var_sp) {
45373418dfeSEnrico Granata     if (!var_sp)
454bbea3610SRaphael Isemann       return llvm::StringRef();
45573418dfeSEnrico Granata 
45673418dfeSEnrico Granata     switch (var_sp->GetScope()) {
45773418dfeSEnrico Granata     case eValueTypeVariableGlobal:
45873418dfeSEnrico Granata       return "GLOBAL: ";
45973418dfeSEnrico Granata     case eValueTypeVariableStatic:
46073418dfeSEnrico Granata       return "STATIC: ";
46173418dfeSEnrico Granata     case eValueTypeVariableArgument:
46273418dfeSEnrico Granata       return "ARG: ";
46373418dfeSEnrico Granata     case eValueTypeVariableLocal:
46473418dfeSEnrico Granata       return "LOCAL: ";
46573418dfeSEnrico Granata     case eValueTypeVariableThreadLocal:
46673418dfeSEnrico Granata       return "THREAD: ";
46773418dfeSEnrico Granata     default:
46873418dfeSEnrico Granata       break;
46973418dfeSEnrico Granata     }
47073418dfeSEnrico Granata 
471bbea3610SRaphael Isemann     return llvm::StringRef();
47273418dfeSEnrico Granata   }
47373418dfeSEnrico Granata 
474b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
47505097246SAdrian Prantl     // No need to check "frame" for validity as eCommandRequiresFrame ensures
47605097246SAdrian Prantl     // it is valid
477b57e4a1bSJason Molenda     StackFrame *frame = m_exe_ctx.GetFramePtr();
4781e49e5e7SJohnny Chen 
479a134cc1bSGreg Clayton     Stream &s = result.GetOutputStream();
4806d56d2ceSJim Ingham 
481b9c1b51eSKate Stone     // Be careful about the stack frame, if any summary formatter runs code, it
48205097246SAdrian Prantl     // might clear the StackFrameList for the thread.  So hold onto a shared
48305097246SAdrian Prantl     // pointer to the frame so it stays alive.
484650543f9SJim Ingham 
485b9c1b51eSKate Stone     VariableList *variable_list =
486b9c1b51eSKate Stone         frame->GetVariableList(m_option_variable.show_globals);
487a134cc1bSGreg Clayton 
4886d56d2ceSJim Ingham     VariableSP var_sp;
4896d56d2ceSJim Ingham     ValueObjectSP valobj_sp;
49078a685aaSJim Ingham 
491061858ceSEnrico Granata     TypeSummaryImplSP summary_format_sp;
49217b11749SEnrico Granata     if (!m_option_variable.summary.IsCurrentValueEmpty())
493b9c1b51eSKate Stone       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
494b9c1b51eSKate Stone           ConstString(m_option_variable.summary.GetCurrentValue()),
495b9c1b51eSKate Stone           summary_format_sp);
49617b11749SEnrico Granata     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
497796ac80bSJonas Devlieghere       summary_format_sp = std::make_shared<StringSummaryFormat>(
498b9c1b51eSKate Stone           TypeSummaryImpl::Flags(),
499796ac80bSJonas Devlieghere           m_option_variable.summary_string.GetCurrentValue());
500f9fa6ee5SEnrico Granata 
501b9c1b51eSKate Stone     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
502b9c1b51eSKate Stone         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
503b9c1b51eSKate Stone         summary_format_sp));
504379447a7SEnrico Granata 
505b9c1b51eSKate Stone     const SymbolContext &sym_ctx =
506b9c1b51eSKate Stone         frame->GetSymbolContext(eSymbolContextFunction);
5076754e04fSEnrico Granata     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
5086754e04fSEnrico Granata       m_option_variable.show_globals = true;
5096754e04fSEnrico Granata 
510b9c1b51eSKate Stone     if (variable_list) {
5111deb7962SGreg Clayton       const Format format = m_option_format.GetFormat();
5120c489f58SEnrico Granata       options.SetFormat(format);
5131deb7962SGreg Clayton 
51411eb9c64SZachary Turner       if (!command.empty()) {
51546747022SGreg Clayton         VariableList regex_var_list;
51646747022SGreg Clayton 
51705097246SAdrian Prantl         // If we have any args to the variable command, we will make variable
51805097246SAdrian Prantl         // objects from them...
519f965cc86SZachary Turner         for (auto &entry : command) {
520b9c1b51eSKate Stone           if (m_option_variable.use_regex) {
521c7bece56SGreg Clayton             const size_t regex_start_index = regex_var_list.GetSize();
5220d9a201eSRaphael Isemann             llvm::StringRef name_str = entry.ref();
52395eae423SZachary Turner             RegularExpression regex(name_str);
524f9d90bc5SJan Kratochvil             if (regex.IsValid()) {
52546747022SGreg Clayton               size_t num_matches = 0;
526b9c1b51eSKate Stone               const size_t num_new_regex_vars =
527b9c1b51eSKate Stone                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
52878a685aaSJim Ingham                                                          num_matches);
529b9c1b51eSKate Stone               if (num_new_regex_vars > 0) {
530b9c1b51eSKate Stone                 for (size_t regex_idx = regex_start_index,
531b9c1b51eSKate Stone                             end_index = regex_var_list.GetSize();
532b9c1b51eSKate Stone                      regex_idx < end_index; ++regex_idx) {
53346747022SGreg Clayton                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
534b9c1b51eSKate Stone                   if (var_sp) {
535b9c1b51eSKate Stone                     valobj_sp = frame->GetValueObjectForFrameVariable(
536b9c1b51eSKate Stone                         var_sp, m_varobj_options.use_dynamic);
537b9c1b51eSKate Stone                     if (valobj_sp) {
53873418dfeSEnrico Granata                       std::string scope_string;
53973418dfeSEnrico Granata                       if (m_option_variable.show_scope)
54073418dfeSEnrico Granata                         scope_string = GetScopeString(var_sp).str();
54173418dfeSEnrico Granata 
54273418dfeSEnrico Granata                       if (!scope_string.empty())
543771ef6d4SMalcolm Parsons                         s.PutCString(scope_string);
54473418dfeSEnrico Granata 
545b9c1b51eSKate Stone                       if (m_option_variable.show_decl &&
546b9c1b51eSKate Stone                           var_sp->GetDeclaration().GetFile()) {
54745ba8543SGreg Clayton                         bool show_fullpaths = false;
54845ba8543SGreg Clayton                         bool show_module = true;
549b9c1b51eSKate Stone                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
550b9c1b51eSKate Stone                                                     show_module))
55146747022SGreg Clayton                           s.PutCString(": ");
55246747022SGreg Clayton                       }
5534d93b8cdSEnrico Granata                       valobj_sp->Dump(result.GetOutputStream(), options);
55446747022SGreg Clayton                     }
55546747022SGreg Clayton                   }
55646747022SGreg Clayton                 }
557b9c1b51eSKate Stone               } else if (num_matches == 0) {
558696f9706SDave Lee                 result.AppendErrorWithFormat(
559696f9706SDave Lee                     "no variables matched the regular expression '%s'.",
560f965cc86SZachary Turner                     entry.c_str());
56146747022SGreg Clayton               }
562b9c1b51eSKate Stone             } else {
5633af3f1e8SJonas Devlieghere               if (llvm::Error err = regex.GetError())
564696f9706SDave Lee                 result.AppendError(llvm::toString(std::move(err)));
56546747022SGreg Clayton               else
566696f9706SDave Lee                 result.AppendErrorWithFormat(
567696f9706SDave Lee                     "unknown regex error when compiling '%s'", entry.c_str());
56846747022SGreg Clayton             }
569b9c1b51eSKate Stone           } else // No regex, either exact variable names or variable
570b9c1b51eSKate Stone                  // expressions.
57146747022SGreg Clayton           {
57297206d57SZachary Turner             Status error;
573b9c1b51eSKate Stone             uint32_t expr_path_options =
574b9c1b51eSKate Stone                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
57546252398SEnrico Granata                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
57646252398SEnrico Granata                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
5772837b766SJim Ingham             lldb::VariableSP var_sp;
578b9c1b51eSKate Stone             valobj_sp = frame->GetValueForVariableExpressionPath(
5790d9a201eSRaphael Isemann                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
580b9c1b51eSKate Stone                 var_sp, error);
581b9c1b51eSKate Stone             if (valobj_sp) {
58273418dfeSEnrico Granata               std::string scope_string;
58373418dfeSEnrico Granata               if (m_option_variable.show_scope)
58473418dfeSEnrico Granata                 scope_string = GetScopeString(var_sp).str();
58573418dfeSEnrico Granata 
58673418dfeSEnrico Granata               if (!scope_string.empty())
587771ef6d4SMalcolm Parsons                 s.PutCString(scope_string);
588b9c1b51eSKate Stone               if (m_option_variable.show_decl && var_sp &&
589b9c1b51eSKate Stone                   var_sp->GetDeclaration().GetFile()) {
590a134cc1bSGreg Clayton                 var_sp->GetDeclaration().DumpStopContext(&s, false);
591a134cc1bSGreg Clayton                 s.PutCString(": ");
592a134cc1bSGreg Clayton               }
5930c489f58SEnrico Granata 
5940c489f58SEnrico Granata               options.SetFormat(format);
595b9c1b51eSKate Stone               options.SetVariableFormatDisplayLanguage(
596b9c1b51eSKate Stone                   valobj_sp->GetPreferredDisplayLanguage());
597887062aeSJohnny Chen 
598887062aeSJohnny Chen               Stream &output_stream = result.GetOutputStream();
599f965cc86SZachary Turner               options.SetRootValueObjectName(
600f965cc86SZachary Turner                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
6014d93b8cdSEnrico Granata               valobj_sp->Dump(output_stream, options);
602b9c1b51eSKate Stone             } else {
603696f9706SDave Lee               if (auto error_cstr = error.AsCString(nullptr))
604696f9706SDave Lee                 result.AppendError(error_cstr);
60554979cddSGreg Clayton               else
606696f9706SDave Lee                 result.AppendErrorWithFormat(
607696f9706SDave Lee                     "unable to find any variable expression path that matches "
608696f9706SDave Lee                     "'%s'.",
609f965cc86SZachary Turner                     entry.c_str());
6106d56d2ceSJim Ingham             }
6116d56d2ceSJim Ingham           }
6126d56d2ceSJim Ingham         }
613b9c1b51eSKate Stone       } else // No command arg specified.  Use variable_list, instead.
6146d56d2ceSJim Ingham       {
615c7bece56SGreg Clayton         const size_t num_variables = variable_list->GetSize();
616b9c1b51eSKate Stone         if (num_variables > 0) {
617b9c1b51eSKate Stone           for (size_t i = 0; i < num_variables; i++) {
6181a65ae11SGreg Clayton             var_sp = variable_list->GetVariableAtIndex(i);
619f955efc0SSylvestre Ledru             switch (var_sp->GetScope()) {
620eb236735SJim Ingham             case eValueTypeVariableGlobal:
621eb236735SJim Ingham               if (!m_option_variable.show_globals)
622eb236735SJim Ingham                 continue;
623eb236735SJim Ingham               break;
624eb236735SJim Ingham             case eValueTypeVariableStatic:
625eb236735SJim Ingham               if (!m_option_variable.show_globals)
626eb236735SJim Ingham                 continue;
627eb236735SJim Ingham               break;
628eb236735SJim Ingham             case eValueTypeVariableArgument:
629eb236735SJim Ingham               if (!m_option_variable.show_args)
630eb236735SJim Ingham                 continue;
631eb236735SJim Ingham               break;
632eb236735SJim Ingham             case eValueTypeVariableLocal:
633eb236735SJim Ingham               if (!m_option_variable.show_locals)
634eb236735SJim Ingham                 continue;
635eb236735SJim Ingham               break;
636eb236735SJim Ingham             default:
637eb236735SJim Ingham               continue;
638eb236735SJim Ingham               break;
639eb236735SJim Ingham             }
640560558ebSEnrico Granata             std::string scope_string;
641eb236735SJim Ingham             if (m_option_variable.show_scope)
64273418dfeSEnrico Granata               scope_string = GetScopeString(var_sp).str();
6436d56d2ceSJim Ingham 
64405097246SAdrian Prantl             // Use the variable object code to make sure we are using the same
64505097246SAdrian Prantl             // APIs as the public API will be using...
646b9c1b51eSKate Stone             valobj_sp = frame->GetValueObjectForFrameVariable(
647b9c1b51eSKate Stone                 var_sp, m_varobj_options.use_dynamic);
648b9c1b51eSKate Stone             if (valobj_sp) {
64905097246SAdrian Prantl               // When dumping all variables, don't print any variables that are
65005097246SAdrian Prantl               // not in scope to avoid extra unneeded output
651b9c1b51eSKate Stone               if (valobj_sp->IsInScope()) {
652b9c1b51eSKate Stone                 if (!valobj_sp->GetTargetSP()
653b9c1b51eSKate Stone                          ->GetDisplayRuntimeSupportValues() &&
654c8ecc2a9SEugene Zelenko                     valobj_sp->IsRuntimeSupportValue())
655560558ebSEnrico Granata                   continue;
656560558ebSEnrico Granata 
657560558ebSEnrico Granata                 if (!scope_string.empty())
658771ef6d4SMalcolm Parsons                   s.PutCString(scope_string);
659560558ebSEnrico Granata 
660b9c1b51eSKate Stone                 if (m_option_variable.show_decl &&
661b9c1b51eSKate Stone                     var_sp->GetDeclaration().GetFile()) {
662a134cc1bSGreg Clayton                   var_sp->GetDeclaration().DumpStopContext(&s, false);
663a134cc1bSGreg Clayton                   s.PutCString(": ");
664a134cc1bSGreg Clayton                 }
6650c489f58SEnrico Granata 
6660c489f58SEnrico Granata                 options.SetFormat(format);
667b9c1b51eSKate Stone                 options.SetVariableFormatDisplayLanguage(
668b9c1b51eSKate Stone                     valobj_sp->GetPreferredDisplayLanguage());
669f965cc86SZachary Turner                 options.SetRootValueObjectName(
670f965cc86SZachary Turner                     var_sp ? var_sp->GetName().AsCString() : nullptr);
6714d93b8cdSEnrico Granata                 valobj_sp->Dump(result.GetOutputStream(), options);
672a134cc1bSGreg Clayton               }
673a134cc1bSGreg Clayton             }
6746d56d2ceSJim Ingham           }
6756d56d2ceSJim Ingham         }
6766d56d2ceSJim Ingham       }
677696f9706SDave Lee       if (result.GetStatus() != eReturnStatusFailed)
6786d56d2ceSJim Ingham         result.SetStatus(eReturnStatusSuccessFinishResult);
6796d56d2ceSJim Ingham     }
68061a80ba6SEnrico Granata 
68141ae8e74SKuba Mracek     if (m_option_variable.show_recognized_args) {
68241ae8e74SKuba Mracek       auto recognized_frame = frame->GetRecognizedFrame();
68341ae8e74SKuba Mracek       if (recognized_frame) {
68441ae8e74SKuba Mracek         ValueObjectListSP recognized_arg_list =
68541ae8e74SKuba Mracek             recognized_frame->GetRecognizedArguments();
68641ae8e74SKuba Mracek         if (recognized_arg_list) {
68741ae8e74SKuba Mracek           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
68841ae8e74SKuba Mracek             options.SetFormat(m_option_format.GetFormat());
68941ae8e74SKuba Mracek             options.SetVariableFormatDisplayLanguage(
69041ae8e74SKuba Mracek                 rec_value_sp->GetPreferredDisplayLanguage());
69141ae8e74SKuba Mracek             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
69241ae8e74SKuba Mracek             rec_value_sp->Dump(result.GetOutputStream(), options);
69341ae8e74SKuba Mracek           }
69441ae8e74SKuba Mracek         }
69541ae8e74SKuba Mracek       }
69641ae8e74SKuba Mracek     }
69741ae8e74SKuba Mracek 
698b9c1b51eSKate Stone     if (m_interpreter.TruncationWarningNecessary()) {
69961a80ba6SEnrico Granata       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
70061a80ba6SEnrico Granata                                       m_cmd_name.c_str());
70161a80ba6SEnrico Granata       m_interpreter.TruncationWarningGiven();
70261a80ba6SEnrico Granata     }
70361a80ba6SEnrico Granata 
70424fff242SDavide Italiano     // Increment statistics.
70524fff242SDavide Italiano     bool res = result.Succeeded();
706d7b33853SGreg Clayton     TargetStats &target_stats = GetSelectedOrDummyTarget().GetStatistics();
70724fff242SDavide Italiano     if (res)
708d7b33853SGreg Clayton       target_stats.GetFrameVariableStats().NotifySuccess();
70924fff242SDavide Italiano     else
710d7b33853SGreg Clayton       target_stats.GetFrameVariableStats().NotifyFailure();
71124fff242SDavide Italiano     return res;
7126d56d2ceSJim Ingham   }
7136d56d2ceSJim Ingham 
7142837b766SJim Ingham   OptionGroupOptions m_option_group;
715715c2365SGreg Clayton   OptionGroupVariable m_option_variable;
7161deb7962SGreg Clayton   OptionGroupFormat m_option_format;
7172837b766SJim Ingham   OptionGroupValueObjectDisplay m_varobj_options;
7186d56d2ceSJim Ingham };
7196d56d2ceSJim Ingham 
72041ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer
72141ae8e74SKuba Mracek 
722ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_recognizer_add
723ec67e734SRaphael Isemann #include "CommandOptions.inc"
72441ae8e74SKuba Mracek 
72541ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
72641ae8e74SKuba Mracek private:
72741ae8e74SKuba Mracek   class CommandOptions : public Options {
72841ae8e74SKuba Mracek   public:
729*abb0ed44SKazu Hirata     CommandOptions() {}
73041ae8e74SKuba Mracek     ~CommandOptions() override = default;
73141ae8e74SKuba Mracek 
73241ae8e74SKuba Mracek     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
73341ae8e74SKuba Mracek                           ExecutionContext *execution_context) override {
73441ae8e74SKuba Mracek       Status error;
73541ae8e74SKuba Mracek       const int short_option = m_getopt_table[option_idx].val;
73641ae8e74SKuba Mracek 
73741ae8e74SKuba Mracek       switch (short_option) {
73854c496daSRoman Podoliaka       case 'f': {
73954c496daSRoman Podoliaka         bool value, success;
74054c496daSRoman Podoliaka         value = OptionArgParser::ToBoolean(option_arg, true, &success);
74154c496daSRoman Podoliaka         if (success) {
74254c496daSRoman Podoliaka           m_first_instruction_only = value;
74354c496daSRoman Podoliaka         } else {
74454c496daSRoman Podoliaka           error.SetErrorStringWithFormat(
74554c496daSRoman Podoliaka               "invalid boolean value '%s' passed for -f option",
74654c496daSRoman Podoliaka               option_arg.str().c_str());
74754c496daSRoman Podoliaka         }
74854c496daSRoman Podoliaka       } break;
74941ae8e74SKuba Mracek       case 'l':
75041ae8e74SKuba Mracek         m_class_name = std::string(option_arg);
75141ae8e74SKuba Mracek         break;
75241ae8e74SKuba Mracek       case 's':
75341ae8e74SKuba Mracek         m_module = std::string(option_arg);
75441ae8e74SKuba Mracek         break;
75541ae8e74SKuba Mracek       case 'n':
756db31e2e1SMed Ismail Bennani         m_symbols.push_back(std::string(option_arg));
75741ae8e74SKuba Mracek         break;
75841ae8e74SKuba Mracek       case 'x':
75941ae8e74SKuba Mracek         m_regex = true;
76041ae8e74SKuba Mracek         break;
76141ae8e74SKuba Mracek       default:
76236162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
76341ae8e74SKuba Mracek       }
76441ae8e74SKuba Mracek 
76541ae8e74SKuba Mracek       return error;
76641ae8e74SKuba Mracek     }
76741ae8e74SKuba Mracek 
76841ae8e74SKuba Mracek     void OptionParsingStarting(ExecutionContext *execution_context) override {
76941ae8e74SKuba Mracek       m_module = "";
770db31e2e1SMed Ismail Bennani       m_symbols.clear();
77141ae8e74SKuba Mracek       m_class_name = "";
77241ae8e74SKuba Mracek       m_regex = false;
77354c496daSRoman Podoliaka       m_first_instruction_only = true;
77441ae8e74SKuba Mracek     }
77541ae8e74SKuba Mracek 
77641ae8e74SKuba Mracek     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
77741ae8e74SKuba Mracek       return llvm::makeArrayRef(g_frame_recognizer_add_options);
77841ae8e74SKuba Mracek     }
77941ae8e74SKuba Mracek 
78041ae8e74SKuba Mracek     // Instance variables to hold the values for command options.
78141ae8e74SKuba Mracek     std::string m_class_name;
78241ae8e74SKuba Mracek     std::string m_module;
783db31e2e1SMed Ismail Bennani     std::vector<std::string> m_symbols;
78441ae8e74SKuba Mracek     bool m_regex;
78554c496daSRoman Podoliaka     bool m_first_instruction_only;
78641ae8e74SKuba Mracek   };
78741ae8e74SKuba Mracek 
78841ae8e74SKuba Mracek   CommandOptions m_options;
78941ae8e74SKuba Mracek 
79041ae8e74SKuba Mracek   Options *GetOptions() override { return &m_options; }
79141ae8e74SKuba Mracek 
79241ae8e74SKuba Mracek protected:
79341ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override;
79441ae8e74SKuba Mracek 
79541ae8e74SKuba Mracek public:
79641ae8e74SKuba Mracek   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
79741ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer add",
798*abb0ed44SKazu Hirata                             "Add a new frame recognizer.", nullptr) {
79941ae8e74SKuba Mracek     SetHelpLong(R"(
80041ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on
80141ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source
80241ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments
80341ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments.
80441ae8e74SKuba Mracek 
80541ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class
80641ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a
80741ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type
80841ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize.
80941ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that
81041ae8e74SKuba Mracek represent the recognized arguments.
81141ae8e74SKuba Mracek 
81241ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc
81341ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows:
81441ae8e74SKuba Mracek 
81541ae8e74SKuba Mracek   class LibcFdRecognizer(object):
81641ae8e74SKuba Mracek     def get_recognized_arguments(self, frame):
81741ae8e74SKuba Mracek       if frame.name in ["read", "write", "close"]:
81841ae8e74SKuba Mracek         fd = frame.EvaluateExpression("$arg1").unsigned
81941ae8e74SKuba Mracek         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
82041ae8e74SKuba Mracek         return [value]
82141ae8e74SKuba Mracek       return []
82241ae8e74SKuba Mracek 
82341ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script
82441ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'.
82541ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is
82641ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
82741ae8e74SKuba Mracek in other modules:
82841ae8e74SKuba Mracek 
82941ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py
83041ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
83141ae8e74SKuba Mracek 
83241ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we
83341ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable':
83441ae8e74SKuba Mracek 
83541ae8e74SKuba Mracek (lldb) b read
83641ae8e74SKuba Mracek (lldb) r
83741ae8e74SKuba Mracek Process 1234 stopped
83841ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
83941ae8e74SKuba Mracek     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
84041ae8e74SKuba Mracek (lldb) frame variable
84141ae8e74SKuba Mracek (int) fd = 3
84241ae8e74SKuba Mracek 
84341ae8e74SKuba Mracek     )");
84441ae8e74SKuba Mracek   }
84541ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerAdd() override = default;
84641ae8e74SKuba Mracek };
84741ae8e74SKuba Mracek 
84841ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
84941ae8e74SKuba Mracek                                                 CommandReturnObject &result) {
8504e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
85141ae8e74SKuba Mracek   if (m_options.m_class_name.empty()) {
85241ae8e74SKuba Mracek     result.AppendErrorWithFormat(
85341ae8e74SKuba Mracek         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
85441ae8e74SKuba Mracek     return false;
85541ae8e74SKuba Mracek   }
85641ae8e74SKuba Mracek 
85741ae8e74SKuba Mracek   if (m_options.m_module.empty()) {
85841ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
85941ae8e74SKuba Mracek                                  m_cmd_name.c_str());
86041ae8e74SKuba Mracek     return false;
86141ae8e74SKuba Mracek   }
86241ae8e74SKuba Mracek 
863db31e2e1SMed Ismail Bennani   if (m_options.m_symbols.empty()) {
864db31e2e1SMed Ismail Bennani     result.AppendErrorWithFormat(
865db31e2e1SMed Ismail Bennani         "%s needs at least one symbol name (-n argument).\n",
866db31e2e1SMed Ismail Bennani         m_cmd_name.c_str());
867db31e2e1SMed Ismail Bennani     return false;
868db31e2e1SMed Ismail Bennani   }
869db31e2e1SMed Ismail Bennani 
870db31e2e1SMed Ismail Bennani   if (m_options.m_regex && m_options.m_symbols.size() > 1) {
871db31e2e1SMed Ismail Bennani     result.AppendErrorWithFormat(
872db31e2e1SMed Ismail Bennani         "%s needs only one symbol regular expression (-n argument).\n",
87341ae8e74SKuba Mracek         m_cmd_name.c_str());
87441ae8e74SKuba Mracek     return false;
87541ae8e74SKuba Mracek   }
87641ae8e74SKuba Mracek 
8772b29b432SJonas Devlieghere   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
87841ae8e74SKuba Mracek 
87941ae8e74SKuba Mracek   if (interpreter &&
88041ae8e74SKuba Mracek       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
881a925974bSAdrian Prantl     result.AppendWarning("The provided class does not exist - please define it "
88241ae8e74SKuba Mracek                          "before attempting to use this frame recognizer");
88341ae8e74SKuba Mracek   }
88441ae8e74SKuba Mracek 
88541ae8e74SKuba Mracek   StackFrameRecognizerSP recognizer_sp =
88641ae8e74SKuba Mracek       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
88741ae8e74SKuba Mracek           interpreter, m_options.m_class_name.c_str()));
88841ae8e74SKuba Mracek   if (m_options.m_regex) {
88941ae8e74SKuba Mracek     auto module =
89041ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_module));
89141ae8e74SKuba Mracek     auto func =
892db31e2e1SMed Ismail Bennani         RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
8931b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
89454c496daSRoman Podoliaka         recognizer_sp, module, func, m_options.m_first_instruction_only);
89541ae8e74SKuba Mracek   } else {
89641ae8e74SKuba Mracek     auto module = ConstString(m_options.m_module);
897db31e2e1SMed Ismail Bennani     std::vector<ConstString> symbols(m_options.m_symbols.begin(),
898db31e2e1SMed Ismail Bennani                                      m_options.m_symbols.end());
8991b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
90054c496daSRoman Podoliaka         recognizer_sp, module, symbols, m_options.m_first_instruction_only);
90141ae8e74SKuba Mracek   }
902f80d2655SKuba Mracek #endif
90341ae8e74SKuba Mracek 
90441ae8e74SKuba Mracek   result.SetStatus(eReturnStatusSuccessFinishNoResult);
90541ae8e74SKuba Mracek   return result.Succeeded();
90641ae8e74SKuba Mracek }
90741ae8e74SKuba Mracek 
90841ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
90941ae8e74SKuba Mracek public:
91041ae8e74SKuba Mracek   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
91141ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer clear",
91241ae8e74SKuba Mracek                             "Delete all frame recognizers.", nullptr) {}
91341ae8e74SKuba Mracek 
91441ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerClear() override = default;
91541ae8e74SKuba Mracek 
91641ae8e74SKuba Mracek protected:
91741ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
9181b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget()
9191b7c9eaeSRaphael Isemann         .GetFrameRecognizerManager()
9201b7c9eaeSRaphael Isemann         .RemoveAllRecognizers();
92141ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
92241ae8e74SKuba Mracek     return result.Succeeded();
92341ae8e74SKuba Mracek   }
92441ae8e74SKuba Mracek };
92541ae8e74SKuba Mracek 
92641ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
92741ae8e74SKuba Mracek public:
92841ae8e74SKuba Mracek   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
92941ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer delete",
93041ae8e74SKuba Mracek                             "Delete an existing frame recognizer.", nullptr) {}
93141ae8e74SKuba Mracek 
93241ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerDelete() override = default;
93341ae8e74SKuba Mracek 
934c37d25f0SGongyu Deng   void
935c37d25f0SGongyu Deng   HandleArgumentCompletion(CompletionRequest &request,
936c37d25f0SGongyu Deng                            OptionElementVector &opt_element_vector) override {
937c37d25f0SGongyu Deng     if (request.GetCursorIndex() != 0)
938c37d25f0SGongyu Deng       return;
939c37d25f0SGongyu Deng 
9401b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
941c37d25f0SGongyu Deng         [&request](uint32_t rid, std::string rname, std::string module,
942c37d25f0SGongyu Deng                    llvm::ArrayRef<lldb_private::ConstString> symbols,
943c37d25f0SGongyu Deng                    bool regexp) {
944c37d25f0SGongyu Deng           StreamString strm;
945c37d25f0SGongyu Deng           if (rname.empty())
946c37d25f0SGongyu Deng             rname = "(internal)";
947c37d25f0SGongyu Deng 
948c37d25f0SGongyu Deng           strm << rname;
949c37d25f0SGongyu Deng           if (!module.empty())
950c37d25f0SGongyu Deng             strm << ", module " << module;
951c37d25f0SGongyu Deng           if (!symbols.empty())
952c37d25f0SGongyu Deng             for (auto &symbol : symbols)
953c37d25f0SGongyu Deng               strm << ", symbol " << symbol;
954c37d25f0SGongyu Deng           if (regexp)
955c37d25f0SGongyu Deng             strm << " (regexp)";
956c37d25f0SGongyu Deng 
957c37d25f0SGongyu Deng           request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
958c37d25f0SGongyu Deng         });
959c37d25f0SGongyu Deng   }
960c37d25f0SGongyu Deng 
96141ae8e74SKuba Mracek protected:
96241ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
96341ae8e74SKuba Mracek     if (command.GetArgumentCount() == 0) {
96441ae8e74SKuba Mracek       if (!m_interpreter.Confirm(
96541ae8e74SKuba Mracek               "About to delete all frame recognizers, do you want to do that?",
96641ae8e74SKuba Mracek               true)) {
96741ae8e74SKuba Mracek         result.AppendMessage("Operation cancelled...");
96841ae8e74SKuba Mracek         return false;
96941ae8e74SKuba Mracek       }
97041ae8e74SKuba Mracek 
9711b7c9eaeSRaphael Isemann       GetSelectedOrDummyTarget()
9721b7c9eaeSRaphael Isemann           .GetFrameRecognizerManager()
9731b7c9eaeSRaphael Isemann           .RemoveAllRecognizers();
97441ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
97541ae8e74SKuba Mracek       return result.Succeeded();
97641ae8e74SKuba Mracek     }
97741ae8e74SKuba Mracek 
97841ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
97941ae8e74SKuba Mracek       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
98041ae8e74SKuba Mracek                                    m_cmd_name.c_str());
98141ae8e74SKuba Mracek       return false;
98241ae8e74SKuba Mracek     }
98341ae8e74SKuba Mracek 
9849010cef2SRaphael Isemann     uint32_t recognizer_id;
9859010cef2SRaphael Isemann     if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
9869010cef2SRaphael Isemann       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
9879010cef2SRaphael Isemann                                    command.GetArgumentAtIndex(0));
9889010cef2SRaphael Isemann       return false;
9899010cef2SRaphael Isemann     }
99041ae8e74SKuba Mracek 
9915477fbc2SRaphael Isemann     if (!GetSelectedOrDummyTarget()
9921b7c9eaeSRaphael Isemann              .GetFrameRecognizerManager()
9935477fbc2SRaphael Isemann              .RemoveRecognizerWithID(recognizer_id)) {
9945477fbc2SRaphael Isemann       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
9955477fbc2SRaphael Isemann                                    command.GetArgumentAtIndex(0));
9965477fbc2SRaphael Isemann       return false;
9975477fbc2SRaphael Isemann     }
99841ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
99941ae8e74SKuba Mracek     return result.Succeeded();
100041ae8e74SKuba Mracek   }
100141ae8e74SKuba Mracek };
100241ae8e74SKuba Mracek 
100341ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed {
100441ae8e74SKuba Mracek public:
100541ae8e74SKuba Mracek   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
100641ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer list",
100741ae8e74SKuba Mracek                             "Show a list of active frame recognizers.",
100841ae8e74SKuba Mracek                             nullptr) {}
100941ae8e74SKuba Mracek 
101041ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerList() override = default;
101141ae8e74SKuba Mracek 
101241ae8e74SKuba Mracek protected:
101341ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
101441ae8e74SKuba Mracek     bool any_printed = false;
10151b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
1016db31e2e1SMed Ismail Bennani         [&result, &any_printed](
1017db31e2e1SMed Ismail Bennani             uint32_t recognizer_id, std::string name, std::string module,
1018db31e2e1SMed Ismail Bennani             llvm::ArrayRef<ConstString> symbols, bool regexp) {
1019cb0c4ee3SMed Ismail Bennani           Stream &stream = result.GetOutputStream();
1020cb0c4ee3SMed Ismail Bennani 
1021cb0c4ee3SMed Ismail Bennani           if (name.empty())
1022a925974bSAdrian Prantl             name = "(internal)";
1023cb0c4ee3SMed Ismail Bennani 
1024cb0c4ee3SMed Ismail Bennani           stream << std::to_string(recognizer_id) << ": " << name;
1025cb0c4ee3SMed Ismail Bennani           if (!module.empty())
1026cb0c4ee3SMed Ismail Bennani             stream << ", module " << module;
1027db31e2e1SMed Ismail Bennani           if (!symbols.empty())
1028db31e2e1SMed Ismail Bennani             for (auto &symbol : symbols)
1029db31e2e1SMed Ismail Bennani               stream << ", symbol " << symbol;
1030cb0c4ee3SMed Ismail Bennani           if (regexp)
1031cb0c4ee3SMed Ismail Bennani             stream << " (regexp)";
1032cb0c4ee3SMed Ismail Bennani 
1033cb0c4ee3SMed Ismail Bennani           stream.EOL();
1034cb0c4ee3SMed Ismail Bennani           stream.Flush();
1035cb0c4ee3SMed Ismail Bennani 
103641ae8e74SKuba Mracek           any_printed = true;
103741ae8e74SKuba Mracek         });
103841ae8e74SKuba Mracek 
103941ae8e74SKuba Mracek     if (any_printed)
104041ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
104141ae8e74SKuba Mracek     else {
104241ae8e74SKuba Mracek       result.GetOutputStream().PutCString("no matching results found.\n");
104341ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishNoResult);
104441ae8e74SKuba Mracek     }
104541ae8e74SKuba Mracek     return result.Succeeded();
104641ae8e74SKuba Mracek   }
104741ae8e74SKuba Mracek };
104841ae8e74SKuba Mracek 
104941ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
105041ae8e74SKuba Mracek public:
105141ae8e74SKuba Mracek   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
105241ae8e74SKuba Mracek       : CommandObjectParsed(
105341ae8e74SKuba Mracek             interpreter, "frame recognizer info",
105441ae8e74SKuba Mracek             "Show which frame recognizer is applied a stack frame (if any).",
105541ae8e74SKuba Mracek             nullptr) {
105641ae8e74SKuba Mracek     CommandArgumentEntry arg;
105741ae8e74SKuba Mracek     CommandArgumentData index_arg;
105841ae8e74SKuba Mracek 
105941ae8e74SKuba Mracek     // Define the first (and only) variant of this arg.
106041ae8e74SKuba Mracek     index_arg.arg_type = eArgTypeFrameIndex;
106141ae8e74SKuba Mracek     index_arg.arg_repetition = eArgRepeatPlain;
106241ae8e74SKuba Mracek 
106341ae8e74SKuba Mracek     // There is only one variant this argument could be; put it into the
106441ae8e74SKuba Mracek     // argument entry.
106541ae8e74SKuba Mracek     arg.push_back(index_arg);
106641ae8e74SKuba Mracek 
106741ae8e74SKuba Mracek     // Push the data for the first argument into the m_arguments vector.
106841ae8e74SKuba Mracek     m_arguments.push_back(arg);
106941ae8e74SKuba Mracek   }
107041ae8e74SKuba Mracek 
107141ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerInfo() override = default;
107241ae8e74SKuba Mracek 
107341ae8e74SKuba Mracek protected:
107441ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
10759010cef2SRaphael Isemann     const char *frame_index_str = command.GetArgumentAtIndex(0);
10769010cef2SRaphael Isemann     uint32_t frame_index;
10779010cef2SRaphael Isemann     if (!llvm::to_integer(frame_index_str, frame_index)) {
10789010cef2SRaphael Isemann       result.AppendErrorWithFormat("'%s' is not a valid frame index.",
10799010cef2SRaphael Isemann                                    frame_index_str);
10809010cef2SRaphael Isemann       return false;
10819010cef2SRaphael Isemann     }
10829010cef2SRaphael Isemann 
108341ae8e74SKuba Mracek     Process *process = m_exe_ctx.GetProcessPtr();
108441ae8e74SKuba Mracek     if (process == nullptr) {
108541ae8e74SKuba Mracek       result.AppendError("no process");
108641ae8e74SKuba Mracek       return false;
108741ae8e74SKuba Mracek     }
108841ae8e74SKuba Mracek     Thread *thread = m_exe_ctx.GetThreadPtr();
108941ae8e74SKuba Mracek     if (thread == nullptr) {
109041ae8e74SKuba Mracek       result.AppendError("no thread");
109141ae8e74SKuba Mracek       return false;
109241ae8e74SKuba Mracek     }
109341ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
109441ae8e74SKuba Mracek       result.AppendErrorWithFormat(
109541ae8e74SKuba Mracek           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
109641ae8e74SKuba Mracek       return false;
109741ae8e74SKuba Mracek     }
109841ae8e74SKuba Mracek 
109941ae8e74SKuba Mracek     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
110041ae8e74SKuba Mracek     if (!frame_sp) {
110141ae8e74SKuba Mracek       result.AppendErrorWithFormat("no frame with index %u", frame_index);
110241ae8e74SKuba Mracek       return false;
110341ae8e74SKuba Mracek     }
110441ae8e74SKuba Mracek 
11051b7c9eaeSRaphael Isemann     auto recognizer = GetSelectedOrDummyTarget()
11061b7c9eaeSRaphael Isemann                           .GetFrameRecognizerManager()
11071b7c9eaeSRaphael Isemann                           .GetRecognizerForFrame(frame_sp);
110841ae8e74SKuba Mracek 
110941ae8e74SKuba Mracek     Stream &output_stream = result.GetOutputStream();
111041ae8e74SKuba Mracek     output_stream.Printf("frame %d ", frame_index);
111141ae8e74SKuba Mracek     if (recognizer) {
111241ae8e74SKuba Mracek       output_stream << "is recognized by ";
111341ae8e74SKuba Mracek       output_stream << recognizer->GetName();
111441ae8e74SKuba Mracek     } else {
111541ae8e74SKuba Mracek       output_stream << "not recognized by any recognizer";
111641ae8e74SKuba Mracek     }
111741ae8e74SKuba Mracek     output_stream.EOL();
111841ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
111941ae8e74SKuba Mracek     return result.Succeeded();
112041ae8e74SKuba Mracek   }
112141ae8e74SKuba Mracek };
112241ae8e74SKuba Mracek 
112341ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword {
112441ae8e74SKuba Mracek public:
112541ae8e74SKuba Mracek   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
112641ae8e74SKuba Mracek       : CommandObjectMultiword(
112741ae8e74SKuba Mracek             interpreter, "frame recognizer",
112841ae8e74SKuba Mracek             "Commands for editing and viewing frame recognizers.",
112941ae8e74SKuba Mracek             "frame recognizer [<sub-command-options>] ") {
1130a925974bSAdrian Prantl     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1131a925974bSAdrian Prantl                               interpreter)));
113241ae8e74SKuba Mracek     LoadSubCommand(
113341ae8e74SKuba Mracek         "clear",
113441ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
113541ae8e74SKuba Mracek     LoadSubCommand(
113641ae8e74SKuba Mracek         "delete",
113741ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1138a925974bSAdrian Prantl     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1139a925974bSAdrian Prantl                                interpreter)));
1140a925974bSAdrian Prantl     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1141a925974bSAdrian Prantl                                interpreter)));
114241ae8e74SKuba Mracek   }
114341ae8e74SKuba Mracek 
114441ae8e74SKuba Mracek   ~CommandObjectFrameRecognizer() override = default;
114541ae8e74SKuba Mracek };
114641ae8e74SKuba Mracek 
114730fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
114830fdc8d8SChris Lattner 
114930fdc8d8SChris Lattner // CommandObjectMultiwordFrame
115030fdc8d8SChris Lattner 
1151b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1152b9c1b51eSKate Stone     CommandInterpreter &interpreter)
1153a925974bSAdrian Prantl     : CommandObjectMultiword(interpreter, "frame",
1154a925974bSAdrian Prantl                              "Commands for selecting and "
1155b9c1b51eSKate Stone                              "examing the current "
1156b9c1b51eSKate Stone                              "thread's stack frames.",
1157b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
1158b9c1b51eSKate Stone   LoadSubCommand("diagnose",
1159b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1160b9c1b51eSKate Stone   LoadSubCommand("info",
1161b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1162b9c1b51eSKate Stone   LoadSubCommand("select",
1163b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1164b9c1b51eSKate Stone   LoadSubCommand("variable",
1165b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
11664e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
1167a925974bSAdrian Prantl   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1168a925974bSAdrian Prantl                                    interpreter)));
116941ae8e74SKuba Mracek #endif
117030fdc8d8SChris Lattner }
117130fdc8d8SChris Lattner 
1172c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1173