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"
171deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h"
182837b766SJim Ingham #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
19715c2365SGreg Clayton #include "lldb/Interpreter/OptionGroupVariable.h"
20b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h"
216754e04fSEnrico Granata #include "lldb/Symbol/Function.h"
226d56d2ceSJim Ingham #include "lldb/Symbol/SymbolContext.h"
236d56d2ceSJim Ingham #include "lldb/Symbol/Variable.h"
246d56d2ceSJim Ingham #include "lldb/Symbol/VariableList.h"
25b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h"
2641ae8e74SKuba Mracek #include "lldb/Target/StackFrameRecognizer.h"
274740a734SSean Callanan #include "lldb/Target/StopInfo.h"
286d56d2ceSJim Ingham #include "lldb/Target/Target.h"
29b9c1b51eSKate Stone #include "lldb/Target/Thread.h"
30145d95c9SPavel Labath #include "lldb/Utility/Args.h"
3130fdc8d8SChris Lattner 
32796ac80bSJonas Devlieghere #include <memory>
33796ac80bSJonas Devlieghere #include <string>
34796ac80bSJonas Devlieghere 
3530fdc8d8SChris Lattner using namespace lldb;
3630fdc8d8SChris Lattner using namespace lldb_private;
3730fdc8d8SChris Lattner 
384740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose
394740a734SSean Callanan 
404740a734SSean Callanan // CommandObjectFrameInfo
414740a734SSean Callanan 
424740a734SSean Callanan // CommandObjectFrameDiagnose
434740a734SSean Callanan 
44ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_diag
45ec67e734SRaphael Isemann #include "CommandOptions.inc"
461f0f5b5bSZachary Turner 
47b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed {
484740a734SSean Callanan public:
49b9c1b51eSKate Stone   class CommandOptions : public Options {
504740a734SSean Callanan   public:
51b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
524740a734SSean Callanan 
534740a734SSean Callanan     ~CommandOptions() override = default;
544740a734SSean Callanan 
5597206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
56b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
5797206d57SZachary Turner       Status error;
584740a734SSean Callanan       const int short_option = m_getopt_table[option_idx].val;
59b9c1b51eSKate Stone       switch (short_option) {
604740a734SSean Callanan       case 'r':
614740a734SSean Callanan         reg = ConstString(option_arg);
624740a734SSean Callanan         break;
634740a734SSean Callanan 
64b9c1b51eSKate Stone       case 'a': {
65fe11483bSZachary Turner         address.emplace();
66fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *address)) {
674740a734SSean Callanan           address.reset();
68b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid address argument '%s'",
69fe11483bSZachary Turner                                          option_arg.str().c_str());
704740a734SSean Callanan         }
71b9c1b51eSKate Stone       } break;
724740a734SSean Callanan 
73b9c1b51eSKate Stone       case 'o': {
74fe11483bSZachary Turner         offset.emplace();
75fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *offset)) {
764740a734SSean Callanan           offset.reset();
77b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid offset argument '%s'",
78fe11483bSZachary Turner                                          option_arg.str().c_str());
794740a734SSean Callanan         }
80b9c1b51eSKate Stone       } break;
814740a734SSean Callanan 
824740a734SSean Callanan       default:
8336162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
844740a734SSean Callanan       }
854740a734SSean Callanan 
864740a734SSean Callanan       return error;
874740a734SSean Callanan     }
884740a734SSean Callanan 
89b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
904740a734SSean Callanan       address.reset();
914740a734SSean Callanan       reg.reset();
924740a734SSean Callanan       offset.reset();
934740a734SSean Callanan     }
944740a734SSean Callanan 
951f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
9670602439SZachary Turner       return llvm::makeArrayRef(g_frame_diag_options);
971f0f5b5bSZachary Turner     }
984740a734SSean Callanan 
994740a734SSean Callanan     // Options.
1004740a734SSean Callanan     llvm::Optional<lldb::addr_t> address;
1014740a734SSean Callanan     llvm::Optional<ConstString> reg;
1024740a734SSean Callanan     llvm::Optional<int64_t> offset;
1034740a734SSean Callanan   };
1044740a734SSean Callanan 
1054740a734SSean Callanan   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
1064740a734SSean Callanan       : CommandObjectParsed(interpreter, "frame diagnose",
107b9c1b51eSKate Stone                             "Try to determine what path path the current stop "
108b9c1b51eSKate Stone                             "location used to get to a register or address",
109b9c1b51eSKate Stone                             nullptr,
110b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
111b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched |
1124740a734SSean Callanan                                 eCommandProcessMustBePaused),
113b9c1b51eSKate Stone         m_options() {
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         result.SetStatus(eReturnStatusFailed);
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         result.SetStatus(eReturnStatusFailed);
1564740a734SSean Callanan         return false;
1574740a734SSean Callanan       }
1584740a734SSean Callanan 
1594740a734SSean Callanan       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
1604740a734SSean Callanan     }
1614740a734SSean Callanan 
162b9c1b51eSKate Stone     if (!valobj_sp) {
1634740a734SSean Callanan       result.AppendError("No diagnosis available.");
1644740a734SSean Callanan       result.SetStatus(eReturnStatusFailed);
1654740a734SSean Callanan       return false;
1664740a734SSean Callanan     }
1674740a734SSean Callanan 
168a925974bSAdrian Prantl     DumpValueObjectOptions::DeclPrintingHelper helper =
169a925974bSAdrian Prantl         [&valobj_sp](ConstString type, ConstString var,
170a925974bSAdrian Prantl                      const DumpValueObjectOptions &opts,
1713bc714b2SZachary Turner                      Stream &stream) -> bool {
172b9c1b51eSKate Stone       const ValueObject::GetExpressionPathFormat format = ValueObject::
173b9c1b51eSKate Stone           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
1743014efe0SAlex Langford       valobj_sp->GetExpressionPath(stream, format);
1754740a734SSean Callanan       stream.PutCString(" =");
1764740a734SSean Callanan       return true;
1774740a734SSean Callanan     };
1784740a734SSean Callanan 
1794740a734SSean Callanan     DumpValueObjectOptions options;
1804740a734SSean Callanan     options.SetDeclPrintingHelper(helper);
181b9c1b51eSKate Stone     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
182b9c1b51eSKate Stone                                options);
1834740a734SSean Callanan     printer.PrintValueObject();
1844740a734SSean Callanan 
1854740a734SSean Callanan     return true;
1864740a734SSean Callanan   }
1874740a734SSean Callanan 
1884740a734SSean Callanan   CommandOptions m_options;
1894740a734SSean Callanan };
1904740a734SSean Callanan 
19130fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo
19230fdc8d8SChris Lattner 
19330fdc8d8SChris Lattner // CommandObjectFrameInfo
19430fdc8d8SChris Lattner 
195b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed {
19630fdc8d8SChris Lattner public:
1977428a18cSKate Stone   CommandObjectFrameInfo(CommandInterpreter &interpreter)
198a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame info",
199a925974bSAdrian Prantl                             "List information about the current "
200b9c1b51eSKate Stone                             "stack frame in the current thread.",
201b9c1b51eSKate Stone                             "frame info",
202b9c1b51eSKate Stone                             eCommandRequiresFrame | eCommandTryTargetAPILock |
203a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
204a925974bSAdrian Prantl                                 eCommandProcessMustBePaused) {}
20530fdc8d8SChris Lattner 
206c8ecc2a9SEugene Zelenko   ~CommandObjectFrameInfo() override = default;
20730fdc8d8SChris Lattner 
2085a988416SJim Ingham protected:
209b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
210f9fc609fSGreg Clayton     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
21130fdc8d8SChris Lattner     result.SetStatus(eReturnStatusSuccessFinishResult);
21230fdc8d8SChris Lattner     return result.Succeeded();
21330fdc8d8SChris Lattner   }
21430fdc8d8SChris Lattner };
21530fdc8d8SChris Lattner 
21630fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect
21730fdc8d8SChris Lattner 
21830fdc8d8SChris Lattner // CommandObjectFrameSelect
21930fdc8d8SChris Lattner 
220ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_select
221ec67e734SRaphael Isemann #include "CommandOptions.inc"
2221f0f5b5bSZachary Turner 
223b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed {
22430fdc8d8SChris Lattner public:
225b9c1b51eSKate Stone   class CommandOptions : public Options {
226864174e1SGreg Clayton   public:
227b9c1b51eSKate Stone     CommandOptions() : Options() { OptionParsingStarting(nullptr); }
228864174e1SGreg Clayton 
229c8ecc2a9SEugene Zelenko     ~CommandOptions() override = default;
230864174e1SGreg Clayton 
23197206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
232b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
23397206d57SZachary Turner       Status error;
2343bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
235b9c1b51eSKate Stone       switch (short_option) {
236dab6f074SRaphael Isemann       case 'r': {
237dab6f074SRaphael Isemann         int32_t offset = 0;
238dab6f074SRaphael Isemann         if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
239b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
240fe11483bSZachary Turner                                          option_arg.str().c_str());
241dab6f074SRaphael Isemann         } else
242dab6f074SRaphael Isemann           relative_frame_offset = offset;
2435a039d55SRaphael Isemann         break;
244dab6f074SRaphael Isemann       }
245864174e1SGreg Clayton 
246864174e1SGreg Clayton       default:
24736162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
248864174e1SGreg Clayton       }
249864174e1SGreg Clayton 
250864174e1SGreg Clayton       return error;
251864174e1SGreg Clayton     }
252864174e1SGreg Clayton 
2535a039d55SRaphael Isemann     void OptionParsingStarting(ExecutionContext *execution_context) override {
254dab6f074SRaphael Isemann       relative_frame_offset.reset();
2555a039d55SRaphael Isemann     }
256864174e1SGreg Clayton 
2571f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
25870602439SZachary Turner       return llvm::makeArrayRef(g_frame_select_options);
2591f0f5b5bSZachary Turner     }
260864174e1SGreg Clayton 
261dab6f074SRaphael Isemann     llvm::Optional<int32_t> relative_frame_offset;
262864174e1SGreg Clayton   };
263864174e1SGreg Clayton 
2647428a18cSKate Stone   CommandObjectFrameSelect(CommandInterpreter &interpreter)
265a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame select",
266a925974bSAdrian Prantl                             "Select the current stack frame by "
267b9c1b51eSKate Stone                             "index from within the current thread "
268b9c1b51eSKate Stone                             "(see 'thread backtrace'.)",
269b9c1b51eSKate Stone                             nullptr,
270b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
271a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
272a925974bSAdrian Prantl                                 eCommandProcessMustBePaused),
273b9c1b51eSKate Stone         m_options() {
274405fe67fSCaroline Tice     CommandArgumentEntry arg;
275405fe67fSCaroline Tice     CommandArgumentData index_arg;
276405fe67fSCaroline Tice 
277405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
278405fe67fSCaroline Tice     index_arg.arg_type = eArgTypeFrameIndex;
279864174e1SGreg Clayton     index_arg.arg_repetition = eArgRepeatOptional;
280405fe67fSCaroline Tice 
281b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
282b9c1b51eSKate Stone     // argument entry.
283405fe67fSCaroline Tice     arg.push_back(index_arg);
284405fe67fSCaroline Tice 
285405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
286405fe67fSCaroline Tice     m_arguments.push_back(arg);
28730fdc8d8SChris Lattner   }
28830fdc8d8SChris Lattner 
289c8ecc2a9SEugene Zelenko   ~CommandObjectFrameSelect() override = default;
29030fdc8d8SChris Lattner 
29180eb4228SGongyu Deng   void
29280eb4228SGongyu Deng   HandleArgumentCompletion(CompletionRequest &request,
29380eb4228SGongyu Deng                            OptionElementVector &opt_element_vector) override {
294*66fa73faSGongyu Deng     if (request.GetCursorIndex() != 0)
29580eb4228SGongyu Deng       return;
29680eb4228SGongyu Deng 
297*66fa73faSGongyu Deng     CommandCompletions::InvokeCommonCompletionCallbacks(
298*66fa73faSGongyu Deng         GetCommandInterpreter(), CommandCompletions::eFrameIndexCompletion,
299*66fa73faSGongyu Deng         request, nullptr);
30080eb4228SGongyu Deng   }
30180eb4228SGongyu Deng 
302b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
303864174e1SGreg Clayton 
3045a988416SJim Ingham protected:
305b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
306b9c1b51eSKate Stone     // No need to check "thread" for validity as eCommandRequiresThread ensures
307b9c1b51eSKate Stone     // it is valid
308f9fc609fSGreg Clayton     Thread *thread = m_exe_ctx.GetThreadPtr();
309f9fc609fSGreg Clayton 
310864174e1SGreg Clayton     uint32_t frame_idx = UINT32_MAX;
311dab6f074SRaphael Isemann     if (m_options.relative_frame_offset.hasValue()) {
312864174e1SGreg Clayton       // The one and only argument is a signed relative frame index
313c14ee32dSGreg Clayton       frame_idx = thread->GetSelectedFrameIndex();
314864174e1SGreg Clayton       if (frame_idx == UINT32_MAX)
315864174e1SGreg Clayton         frame_idx = 0;
316864174e1SGreg Clayton 
317dab6f074SRaphael Isemann       if (*m_options.relative_frame_offset < 0) {
318dab6f074SRaphael Isemann         if (static_cast<int32_t>(frame_idx) >=
319dab6f074SRaphael Isemann             -*m_options.relative_frame_offset)
320dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
321b9c1b51eSKate Stone         else {
322b9c1b51eSKate Stone           if (frame_idx == 0) {
32305097246SAdrian Prantl             // If you are already at the bottom of the stack, then just warn
32405097246SAdrian Prantl             // and don't reset the frame.
3257428a18cSKate Stone             result.AppendError("Already at the bottom of the stack.");
326213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
327213b4546SJim Ingham             return false;
328b9c1b51eSKate Stone           } else
329864174e1SGreg Clayton             frame_idx = 0;
330864174e1SGreg Clayton         }
331dab6f074SRaphael Isemann       } else if (*m_options.relative_frame_offset > 0) {
332b9c1b51eSKate Stone         // I don't want "up 20" where "20" takes you past the top of the stack
333b9c1b51eSKate Stone         // to produce
334b9c1b51eSKate Stone         // an error, but rather to just go to the top.  So I have to count the
335b9c1b51eSKate Stone         // stack here...
336b0c72a5fSJim Ingham         const uint32_t num_frames = thread->GetStackFrameCount();
337b9c1b51eSKate Stone         if (static_cast<int32_t>(num_frames - frame_idx) >
338dab6f074SRaphael Isemann             *m_options.relative_frame_offset)
339dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
340b9c1b51eSKate Stone         else {
341b9c1b51eSKate Stone           if (frame_idx == num_frames - 1) {
342b9c1b51eSKate Stone             // If we are already at the top of the stack, just warn and don't
343b9c1b51eSKate Stone             // reset the frame.
3447428a18cSKate Stone             result.AppendError("Already at the top of the stack.");
345213b4546SJim Ingham             result.SetStatus(eReturnStatusFailed);
346213b4546SJim Ingham             return false;
347b9c1b51eSKate Stone           } else
348864174e1SGreg Clayton             frame_idx = num_frames - 1;
349864174e1SGreg Clayton         }
350864174e1SGreg Clayton       }
351b9c1b51eSKate Stone     } else {
352f965cc86SZachary Turner       if (command.GetArgumentCount() > 1) {
353f965cc86SZachary Turner         result.AppendErrorWithFormat(
354f965cc86SZachary Turner             "too many arguments; expected frame-index, saw '%s'.\n",
355867e7d17SZachary Turner             command[0].c_str());
356f965cc86SZachary Turner         m_options.GenerateOptionUsage(
357f965cc86SZachary Turner             result.GetErrorStream(), this,
358f965cc86SZachary Turner             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
359f965cc86SZachary Turner         return false;
360f965cc86SZachary Turner       }
361f965cc86SZachary Turner 
362b9c1b51eSKate Stone       if (command.GetArgumentCount() == 1) {
3630d9a201eSRaphael Isemann         if (command[0].ref().getAsInteger(0, frame_idx)) {
364b9c1b51eSKate Stone           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
365f965cc86SZachary Turner                                        command[0].c_str());
366afbb0af8SJim Ingham           result.SetStatus(eReturnStatusFailed);
367afbb0af8SJim Ingham           return false;
368afbb0af8SJim Ingham         }
369b9c1b51eSKate Stone       } else if (command.GetArgumentCount() == 0) {
37082d4a2b9SJason Molenda         frame_idx = thread->GetSelectedFrameIndex();
371b9c1b51eSKate Stone         if (frame_idx == UINT32_MAX) {
37282d4a2b9SJason Molenda           frame_idx = 0;
37382d4a2b9SJason Molenda         }
374864174e1SGreg Clayton       }
375864174e1SGreg Clayton     }
37630fdc8d8SChris Lattner 
377b9c1b51eSKate Stone     bool success = thread->SetSelectedFrameByIndexNoisily(
378b9c1b51eSKate Stone         frame_idx, result.GetOutputStream());
379b9c1b51eSKate Stone     if (success) {
380f9fc609fSGreg Clayton       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
38130fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
382b9c1b51eSKate Stone     } else {
383b9c1b51eSKate Stone       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
384b9c1b51eSKate Stone                                    frame_idx);
38530fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
38693208b86SJim Ingham     }
38793208b86SJim Ingham 
38893208b86SJim Ingham     return result.Succeeded();
38930fdc8d8SChris Lattner   }
390864174e1SGreg Clayton 
391864174e1SGreg Clayton   CommandOptions m_options;
392864174e1SGreg Clayton };
393864174e1SGreg Clayton 
3946d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable
3956d56d2ceSJim Ingham // List images with associated information
396b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed {
3976d56d2ceSJim Ingham public:
3987428a18cSKate Stone   CommandObjectFrameVariable(CommandInterpreter &interpreter)
3997428a18cSKate Stone       : CommandObjectParsed(
400b9c1b51eSKate Stone             interpreter, "frame variable",
401b9c1b51eSKate Stone             "Show variables for the current stack frame. Defaults to all "
4027428a18cSKate Stone             "arguments and local variables in scope. Names of argument, "
4037428a18cSKate Stone             "local, file static and file global variables can be specified. "
404ed8a705cSGreg Clayton             "Children of aggregate variables can be specified such as "
405285ae0c0SJim Ingham             "'var->child.x'.  The -> and [] operators in 'frame variable' do "
406285ae0c0SJim Ingham             "not invoke operator overloads if they exist, but directly access "
407285ae0c0SJim Ingham             "the specified element.  If you want to trigger operator overloads "
408285ae0c0SJim Ingham             "use the expression command to print the variable instead."
409285ae0c0SJim Ingham             "\nIt is worth noting that except for overloaded "
410285ae0c0SJim Ingham             "operators, when printing local variables 'expr local_var' and "
411285ae0c0SJim Ingham             "'frame var local_var' produce the same "
412285ae0c0SJim Ingham             "results.  However, 'frame variable' is more efficient, since it "
413285ae0c0SJim Ingham             "uses debug information and memory reads directly, rather than "
414285ae0c0SJim Ingham             "parsing and evaluating an expression, which may even involve "
415285ae0c0SJim Ingham             "JITing and running code in the target program.",
416a925974bSAdrian Prantl             nullptr,
417a925974bSAdrian Prantl             eCommandRequiresFrame | eCommandTryTargetAPILock |
418a925974bSAdrian Prantl                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
419a925974bSAdrian Prantl                 eCommandRequiresProcess),
420e1cfbc79STodd Fiala         m_option_group(),
421b9c1b51eSKate Stone         m_option_variable(
422b9c1b51eSKate Stone             true), // Include the frame specific options by passing "true"
423a925974bSAdrian Prantl         m_option_format(eFormatDefault), m_varobj_options() {
424405fe67fSCaroline Tice     CommandArgumentEntry arg;
425405fe67fSCaroline Tice     CommandArgumentData var_name_arg;
426405fe67fSCaroline Tice 
427405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
428405fe67fSCaroline Tice     var_name_arg.arg_type = eArgTypeVarName;
429405fe67fSCaroline Tice     var_name_arg.arg_repetition = eArgRepeatStar;
430405fe67fSCaroline Tice 
431b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
432b9c1b51eSKate Stone     // argument entry.
433405fe67fSCaroline Tice     arg.push_back(var_name_arg);
434405fe67fSCaroline Tice 
435405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
436405fe67fSCaroline Tice     m_arguments.push_back(arg);
4372837b766SJim Ingham 
438715c2365SGreg Clayton     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
439b9c1b51eSKate Stone     m_option_group.Append(&m_option_format,
440b9c1b51eSKate Stone                           OptionGroupFormat::OPTION_GROUP_FORMAT |
441b9c1b51eSKate Stone                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
442b9c1b51eSKate Stone                           LLDB_OPT_SET_1);
4432837b766SJim Ingham     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
4442837b766SJim Ingham     m_option_group.Finalize();
4456d56d2ceSJim Ingham   }
4466d56d2ceSJim Ingham 
447c8ecc2a9SEugene Zelenko   ~CommandObjectFrameVariable() override = default;
4486d56d2ceSJim Ingham 
449b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
450f21feadcSGreg Clayton 
451ae34ed2cSRaphael Isemann   void
452ae34ed2cSRaphael Isemann   HandleArgumentCompletion(CompletionRequest &request,
4532443bbd4SRaphael Isemann                            OptionElementVector &opt_element_vector) override {
454f21feadcSGreg Clayton     // Arguments are the standard source file completer.
455b9c1b51eSKate Stone     CommandCompletions::InvokeCommonCompletionCallbacks(
456b9c1b51eSKate Stone         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
457a2e76c0bSRaphael Isemann         request, nullptr);
458f21feadcSGreg Clayton   }
4596d56d2ceSJim Ingham 
4605a988416SJim Ingham protected:
46173418dfeSEnrico Granata   llvm::StringRef GetScopeString(VariableSP var_sp) {
46273418dfeSEnrico Granata     if (!var_sp)
46373418dfeSEnrico Granata       return llvm::StringRef::withNullAsEmpty(nullptr);
46473418dfeSEnrico Granata 
46573418dfeSEnrico Granata     switch (var_sp->GetScope()) {
46673418dfeSEnrico Granata     case eValueTypeVariableGlobal:
46773418dfeSEnrico Granata       return "GLOBAL: ";
46873418dfeSEnrico Granata     case eValueTypeVariableStatic:
46973418dfeSEnrico Granata       return "STATIC: ";
47073418dfeSEnrico Granata     case eValueTypeVariableArgument:
47173418dfeSEnrico Granata       return "ARG: ";
47273418dfeSEnrico Granata     case eValueTypeVariableLocal:
47373418dfeSEnrico Granata       return "LOCAL: ";
47473418dfeSEnrico Granata     case eValueTypeVariableThreadLocal:
47573418dfeSEnrico Granata       return "THREAD: ";
47673418dfeSEnrico Granata     default:
47773418dfeSEnrico Granata       break;
47873418dfeSEnrico Granata     }
47973418dfeSEnrico Granata 
48073418dfeSEnrico Granata     return llvm::StringRef::withNullAsEmpty(nullptr);
48173418dfeSEnrico Granata   }
48273418dfeSEnrico Granata 
483b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
48405097246SAdrian Prantl     // No need to check "frame" for validity as eCommandRequiresFrame ensures
48505097246SAdrian Prantl     // it is valid
486b57e4a1bSJason Molenda     StackFrame *frame = m_exe_ctx.GetFramePtr();
4871e49e5e7SJohnny Chen 
488a134cc1bSGreg Clayton     Stream &s = result.GetOutputStream();
4896d56d2ceSJim Ingham 
490b9c1b51eSKate Stone     // Be careful about the stack frame, if any summary formatter runs code, it
49105097246SAdrian Prantl     // might clear the StackFrameList for the thread.  So hold onto a shared
49205097246SAdrian Prantl     // pointer to the frame so it stays alive.
493650543f9SJim Ingham 
494b9c1b51eSKate Stone     VariableList *variable_list =
495b9c1b51eSKate Stone         frame->GetVariableList(m_option_variable.show_globals);
496a134cc1bSGreg Clayton 
4976d56d2ceSJim Ingham     VariableSP var_sp;
4986d56d2ceSJim Ingham     ValueObjectSP valobj_sp;
49978a685aaSJim Ingham 
500061858ceSEnrico Granata     TypeSummaryImplSP summary_format_sp;
50117b11749SEnrico Granata     if (!m_option_variable.summary.IsCurrentValueEmpty())
502b9c1b51eSKate Stone       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
503b9c1b51eSKate Stone           ConstString(m_option_variable.summary.GetCurrentValue()),
504b9c1b51eSKate Stone           summary_format_sp);
50517b11749SEnrico Granata     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
506796ac80bSJonas Devlieghere       summary_format_sp = std::make_shared<StringSummaryFormat>(
507b9c1b51eSKate Stone           TypeSummaryImpl::Flags(),
508796ac80bSJonas Devlieghere           m_option_variable.summary_string.GetCurrentValue());
509f9fa6ee5SEnrico Granata 
510b9c1b51eSKate Stone     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
511b9c1b51eSKate Stone         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
512b9c1b51eSKate Stone         summary_format_sp));
513379447a7SEnrico Granata 
514b9c1b51eSKate Stone     const SymbolContext &sym_ctx =
515b9c1b51eSKate Stone         frame->GetSymbolContext(eSymbolContextFunction);
5166754e04fSEnrico Granata     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
5176754e04fSEnrico Granata       m_option_variable.show_globals = true;
5186754e04fSEnrico Granata 
519b9c1b51eSKate Stone     if (variable_list) {
5201deb7962SGreg Clayton       const Format format = m_option_format.GetFormat();
5210c489f58SEnrico Granata       options.SetFormat(format);
5221deb7962SGreg Clayton 
52311eb9c64SZachary Turner       if (!command.empty()) {
52446747022SGreg Clayton         VariableList regex_var_list;
52546747022SGreg Clayton 
52605097246SAdrian Prantl         // If we have any args to the variable command, we will make variable
52705097246SAdrian Prantl         // objects from them...
528f965cc86SZachary Turner         for (auto &entry : command) {
529b9c1b51eSKate Stone           if (m_option_variable.use_regex) {
530c7bece56SGreg Clayton             const size_t regex_start_index = regex_var_list.GetSize();
5310d9a201eSRaphael Isemann             llvm::StringRef name_str = entry.ref();
53295eae423SZachary Turner             RegularExpression regex(name_str);
533f9d90bc5SJan Kratochvil             if (regex.IsValid()) {
53446747022SGreg Clayton               size_t num_matches = 0;
535b9c1b51eSKate Stone               const size_t num_new_regex_vars =
536b9c1b51eSKate Stone                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
53778a685aaSJim Ingham                                                          num_matches);
538b9c1b51eSKate Stone               if (num_new_regex_vars > 0) {
539b9c1b51eSKate Stone                 for (size_t regex_idx = regex_start_index,
540b9c1b51eSKate Stone                             end_index = regex_var_list.GetSize();
541b9c1b51eSKate Stone                      regex_idx < end_index; ++regex_idx) {
54246747022SGreg Clayton                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
543b9c1b51eSKate Stone                   if (var_sp) {
544b9c1b51eSKate Stone                     valobj_sp = frame->GetValueObjectForFrameVariable(
545b9c1b51eSKate Stone                         var_sp, m_varobj_options.use_dynamic);
546b9c1b51eSKate Stone                     if (valobj_sp) {
54773418dfeSEnrico Granata                       std::string scope_string;
54873418dfeSEnrico Granata                       if (m_option_variable.show_scope)
54973418dfeSEnrico Granata                         scope_string = GetScopeString(var_sp).str();
55073418dfeSEnrico Granata 
55173418dfeSEnrico Granata                       if (!scope_string.empty())
552771ef6d4SMalcolm Parsons                         s.PutCString(scope_string);
55373418dfeSEnrico Granata 
554b9c1b51eSKate Stone                       if (m_option_variable.show_decl &&
555b9c1b51eSKate Stone                           var_sp->GetDeclaration().GetFile()) {
55645ba8543SGreg Clayton                         bool show_fullpaths = false;
55745ba8543SGreg Clayton                         bool show_module = true;
558b9c1b51eSKate Stone                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
559b9c1b51eSKate Stone                                                     show_module))
56046747022SGreg Clayton                           s.PutCString(": ");
56146747022SGreg Clayton                       }
5624d93b8cdSEnrico Granata                       valobj_sp->Dump(result.GetOutputStream(), options);
56346747022SGreg Clayton                     }
56446747022SGreg Clayton                   }
56546747022SGreg Clayton                 }
566b9c1b51eSKate Stone               } else if (num_matches == 0) {
567b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: no variables matched "
568b9c1b51eSKate Stone                                                "the regular expression '%s'.\n",
569f965cc86SZachary Turner                                                entry.c_str());
57046747022SGreg Clayton               }
571b9c1b51eSKate Stone             } else {
5723af3f1e8SJonas Devlieghere               if (llvm::Error err = regex.GetError())
5733af3f1e8SJonas Devlieghere                 result.GetErrorStream().Printf(
5743af3f1e8SJonas Devlieghere                     "error: %s\n", llvm::toString(std::move(err)).c_str());
57546747022SGreg Clayton               else
576b9c1b51eSKate Stone                 result.GetErrorStream().Printf(
577b9c1b51eSKate Stone                     "error: unknown regex error when compiling '%s'\n",
578f965cc86SZachary Turner                     entry.c_str());
57946747022SGreg Clayton             }
580b9c1b51eSKate Stone           } else // No regex, either exact variable names or variable
581b9c1b51eSKate Stone                  // expressions.
58246747022SGreg Clayton           {
58397206d57SZachary Turner             Status error;
584b9c1b51eSKate Stone             uint32_t expr_path_options =
585b9c1b51eSKate Stone                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
58646252398SEnrico Granata                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
58746252398SEnrico Granata                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
5882837b766SJim Ingham             lldb::VariableSP var_sp;
589b9c1b51eSKate Stone             valobj_sp = frame->GetValueForVariableExpressionPath(
5900d9a201eSRaphael Isemann                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
591b9c1b51eSKate Stone                 var_sp, error);
592b9c1b51eSKate Stone             if (valobj_sp) {
59373418dfeSEnrico Granata               std::string scope_string;
59473418dfeSEnrico Granata               if (m_option_variable.show_scope)
59573418dfeSEnrico Granata                 scope_string = GetScopeString(var_sp).str();
59673418dfeSEnrico Granata 
59773418dfeSEnrico Granata               if (!scope_string.empty())
598771ef6d4SMalcolm Parsons                 s.PutCString(scope_string);
599b9c1b51eSKate Stone               if (m_option_variable.show_decl && var_sp &&
600b9c1b51eSKate Stone                   var_sp->GetDeclaration().GetFile()) {
601a134cc1bSGreg Clayton                 var_sp->GetDeclaration().DumpStopContext(&s, false);
602a134cc1bSGreg Clayton                 s.PutCString(": ");
603a134cc1bSGreg Clayton               }
6040c489f58SEnrico Granata 
6050c489f58SEnrico Granata               options.SetFormat(format);
606b9c1b51eSKate Stone               options.SetVariableFormatDisplayLanguage(
607b9c1b51eSKate Stone                   valobj_sp->GetPreferredDisplayLanguage());
608887062aeSJohnny Chen 
609887062aeSJohnny Chen               Stream &output_stream = result.GetOutputStream();
610f965cc86SZachary Turner               options.SetRootValueObjectName(
611f965cc86SZachary Turner                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
6124d93b8cdSEnrico Granata               valobj_sp->Dump(output_stream, options);
613b9c1b51eSKate Stone             } else {
614c8ecc2a9SEugene Zelenko               const char *error_cstr = error.AsCString(nullptr);
61554979cddSGreg Clayton               if (error_cstr)
61654979cddSGreg Clayton                 result.GetErrorStream().Printf("error: %s\n", error_cstr);
61754979cddSGreg Clayton               else
618b9c1b51eSKate Stone                 result.GetErrorStream().Printf("error: unable to find any "
619b9c1b51eSKate Stone                                                "variable expression path that "
620b9c1b51eSKate Stone                                                "matches '%s'.\n",
621f965cc86SZachary Turner                                                entry.c_str());
6226d56d2ceSJim Ingham             }
6236d56d2ceSJim Ingham           }
6246d56d2ceSJim Ingham         }
625b9c1b51eSKate Stone       } else // No command arg specified.  Use variable_list, instead.
6266d56d2ceSJim Ingham       {
627c7bece56SGreg Clayton         const size_t num_variables = variable_list->GetSize();
628b9c1b51eSKate Stone         if (num_variables > 0) {
629b9c1b51eSKate Stone           for (size_t i = 0; i < num_variables; i++) {
6301a65ae11SGreg Clayton             var_sp = variable_list->GetVariableAtIndex(i);
631f955efc0SSylvestre Ledru             switch (var_sp->GetScope()) {
632eb236735SJim Ingham             case eValueTypeVariableGlobal:
633eb236735SJim Ingham               if (!m_option_variable.show_globals)
634eb236735SJim Ingham                 continue;
635eb236735SJim Ingham               break;
636eb236735SJim Ingham             case eValueTypeVariableStatic:
637eb236735SJim Ingham               if (!m_option_variable.show_globals)
638eb236735SJim Ingham                 continue;
639eb236735SJim Ingham               break;
640eb236735SJim Ingham             case eValueTypeVariableArgument:
641eb236735SJim Ingham               if (!m_option_variable.show_args)
642eb236735SJim Ingham                 continue;
643eb236735SJim Ingham               break;
644eb236735SJim Ingham             case eValueTypeVariableLocal:
645eb236735SJim Ingham               if (!m_option_variable.show_locals)
646eb236735SJim Ingham                 continue;
647eb236735SJim Ingham               break;
648eb236735SJim Ingham             default:
649eb236735SJim Ingham               continue;
650eb236735SJim Ingham               break;
651eb236735SJim Ingham             }
652560558ebSEnrico Granata             std::string scope_string;
653eb236735SJim Ingham             if (m_option_variable.show_scope)
65473418dfeSEnrico Granata               scope_string = GetScopeString(var_sp).str();
6556d56d2ceSJim Ingham 
65605097246SAdrian Prantl             // Use the variable object code to make sure we are using the same
65705097246SAdrian Prantl             // APIs as the public API will be using...
658b9c1b51eSKate Stone             valobj_sp = frame->GetValueObjectForFrameVariable(
659b9c1b51eSKate Stone                 var_sp, m_varobj_options.use_dynamic);
660b9c1b51eSKate Stone             if (valobj_sp) {
66105097246SAdrian Prantl               // When dumping all variables, don't print any variables that are
66205097246SAdrian Prantl               // not in scope to avoid extra unneeded output
663b9c1b51eSKate Stone               if (valobj_sp->IsInScope()) {
664b9c1b51eSKate Stone                 if (!valobj_sp->GetTargetSP()
665b9c1b51eSKate Stone                          ->GetDisplayRuntimeSupportValues() &&
666c8ecc2a9SEugene Zelenko                     valobj_sp->IsRuntimeSupportValue())
667560558ebSEnrico Granata                   continue;
668560558ebSEnrico Granata 
669560558ebSEnrico Granata                 if (!scope_string.empty())
670771ef6d4SMalcolm Parsons                   s.PutCString(scope_string);
671560558ebSEnrico Granata 
672b9c1b51eSKate Stone                 if (m_option_variable.show_decl &&
673b9c1b51eSKate Stone                     var_sp->GetDeclaration().GetFile()) {
674a134cc1bSGreg Clayton                   var_sp->GetDeclaration().DumpStopContext(&s, false);
675a134cc1bSGreg Clayton                   s.PutCString(": ");
676a134cc1bSGreg Clayton                 }
6770c489f58SEnrico Granata 
6780c489f58SEnrico Granata                 options.SetFormat(format);
679b9c1b51eSKate Stone                 options.SetVariableFormatDisplayLanguage(
680b9c1b51eSKate Stone                     valobj_sp->GetPreferredDisplayLanguage());
681f965cc86SZachary Turner                 options.SetRootValueObjectName(
682f965cc86SZachary Turner                     var_sp ? var_sp->GetName().AsCString() : nullptr);
6834d93b8cdSEnrico Granata                 valobj_sp->Dump(result.GetOutputStream(), options);
684a134cc1bSGreg Clayton               }
685a134cc1bSGreg Clayton             }
6866d56d2ceSJim Ingham           }
6876d56d2ceSJim Ingham         }
6886d56d2ceSJim Ingham       }
6896d56d2ceSJim Ingham       result.SetStatus(eReturnStatusSuccessFinishResult);
6906d56d2ceSJim Ingham     }
69161a80ba6SEnrico Granata 
69241ae8e74SKuba Mracek     if (m_option_variable.show_recognized_args) {
69341ae8e74SKuba Mracek       auto recognized_frame = frame->GetRecognizedFrame();
69441ae8e74SKuba Mracek       if (recognized_frame) {
69541ae8e74SKuba Mracek         ValueObjectListSP recognized_arg_list =
69641ae8e74SKuba Mracek             recognized_frame->GetRecognizedArguments();
69741ae8e74SKuba Mracek         if (recognized_arg_list) {
69841ae8e74SKuba Mracek           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
69941ae8e74SKuba Mracek             options.SetFormat(m_option_format.GetFormat());
70041ae8e74SKuba Mracek             options.SetVariableFormatDisplayLanguage(
70141ae8e74SKuba Mracek                 rec_value_sp->GetPreferredDisplayLanguage());
70241ae8e74SKuba Mracek             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
70341ae8e74SKuba Mracek             rec_value_sp->Dump(result.GetOutputStream(), options);
70441ae8e74SKuba Mracek           }
70541ae8e74SKuba Mracek         }
70641ae8e74SKuba Mracek       }
70741ae8e74SKuba Mracek     }
70841ae8e74SKuba Mracek 
709b9c1b51eSKate Stone     if (m_interpreter.TruncationWarningNecessary()) {
71061a80ba6SEnrico Granata       result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
71161a80ba6SEnrico Granata                                       m_cmd_name.c_str());
71261a80ba6SEnrico Granata       m_interpreter.TruncationWarningGiven();
71361a80ba6SEnrico Granata     }
71461a80ba6SEnrico Granata 
71524fff242SDavide Italiano     // Increment statistics.
71624fff242SDavide Italiano     bool res = result.Succeeded();
717cb2380c9SRaphael Isemann     Target &target = GetSelectedOrDummyTarget();
71824fff242SDavide Italiano     if (res)
719cb2380c9SRaphael Isemann       target.IncrementStats(StatisticKind::FrameVarSuccess);
72024fff242SDavide Italiano     else
721cb2380c9SRaphael Isemann       target.IncrementStats(StatisticKind::FrameVarFailure);
72224fff242SDavide Italiano     return res;
7236d56d2ceSJim Ingham   }
7246d56d2ceSJim Ingham 
7252837b766SJim Ingham   OptionGroupOptions m_option_group;
726715c2365SGreg Clayton   OptionGroupVariable m_option_variable;
7271deb7962SGreg Clayton   OptionGroupFormat m_option_format;
7282837b766SJim Ingham   OptionGroupValueObjectDisplay m_varobj_options;
7296d56d2ceSJim Ingham };
7306d56d2ceSJim Ingham 
73141ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer
73241ae8e74SKuba Mracek 
733ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_recognizer_add
734ec67e734SRaphael Isemann #include "CommandOptions.inc"
73541ae8e74SKuba Mracek 
73641ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
73741ae8e74SKuba Mracek private:
73841ae8e74SKuba Mracek   class CommandOptions : public Options {
73941ae8e74SKuba Mracek   public:
74041ae8e74SKuba Mracek     CommandOptions() : Options() {}
74141ae8e74SKuba Mracek     ~CommandOptions() override = default;
74241ae8e74SKuba Mracek 
74341ae8e74SKuba Mracek     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
74441ae8e74SKuba Mracek                           ExecutionContext *execution_context) override {
74541ae8e74SKuba Mracek       Status error;
74641ae8e74SKuba Mracek       const int short_option = m_getopt_table[option_idx].val;
74741ae8e74SKuba Mracek 
74841ae8e74SKuba Mracek       switch (short_option) {
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;
77341ae8e74SKuba Mracek     }
77441ae8e74SKuba Mracek 
77541ae8e74SKuba Mracek     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
77641ae8e74SKuba Mracek       return llvm::makeArrayRef(g_frame_recognizer_add_options);
77741ae8e74SKuba Mracek     }
77841ae8e74SKuba Mracek 
77941ae8e74SKuba Mracek     // Instance variables to hold the values for command options.
78041ae8e74SKuba Mracek     std::string m_class_name;
78141ae8e74SKuba Mracek     std::string m_module;
782db31e2e1SMed Ismail Bennani     std::vector<std::string> m_symbols;
78341ae8e74SKuba Mracek     bool m_regex;
78441ae8e74SKuba Mracek   };
78541ae8e74SKuba Mracek 
78641ae8e74SKuba Mracek   CommandOptions m_options;
78741ae8e74SKuba Mracek 
78841ae8e74SKuba Mracek   Options *GetOptions() override { return &m_options; }
78941ae8e74SKuba Mracek 
79041ae8e74SKuba Mracek protected:
79141ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override;
79241ae8e74SKuba Mracek 
79341ae8e74SKuba Mracek public:
79441ae8e74SKuba Mracek   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
79541ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer add",
79641ae8e74SKuba Mracek                             "Add a new frame recognizer.", nullptr),
79741ae8e74SKuba Mracek         m_options() {
79841ae8e74SKuba Mracek     SetHelpLong(R"(
79941ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on
80041ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source
80141ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments
80241ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments.
80341ae8e74SKuba Mracek 
80441ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class
80541ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a
80641ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type
80741ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize.
80841ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that
80941ae8e74SKuba Mracek represent the recognized arguments.
81041ae8e74SKuba Mracek 
81141ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc
81241ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows:
81341ae8e74SKuba Mracek 
81441ae8e74SKuba Mracek   class LibcFdRecognizer(object):
81541ae8e74SKuba Mracek     def get_recognized_arguments(self, frame):
81641ae8e74SKuba Mracek       if frame.name in ["read", "write", "close"]:
81741ae8e74SKuba Mracek         fd = frame.EvaluateExpression("$arg1").unsigned
81841ae8e74SKuba Mracek         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
81941ae8e74SKuba Mracek         return [value]
82041ae8e74SKuba Mracek       return []
82141ae8e74SKuba Mracek 
82241ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script
82341ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'.
82441ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is
82541ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
82641ae8e74SKuba Mracek in other modules:
82741ae8e74SKuba Mracek 
82841ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py
82941ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
83041ae8e74SKuba Mracek 
83141ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we
83241ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable':
83341ae8e74SKuba Mracek 
83441ae8e74SKuba Mracek (lldb) b read
83541ae8e74SKuba Mracek (lldb) r
83641ae8e74SKuba Mracek Process 1234 stopped
83741ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
83841ae8e74SKuba Mracek     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
83941ae8e74SKuba Mracek (lldb) frame variable
84041ae8e74SKuba Mracek (int) fd = 3
84141ae8e74SKuba Mracek 
84241ae8e74SKuba Mracek     )");
84341ae8e74SKuba Mracek   }
84441ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerAdd() override = default;
84541ae8e74SKuba Mracek };
84641ae8e74SKuba Mracek 
84741ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
84841ae8e74SKuba Mracek                                                 CommandReturnObject &result) {
8494e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
85041ae8e74SKuba Mracek   if (m_options.m_class_name.empty()) {
85141ae8e74SKuba Mracek     result.AppendErrorWithFormat(
85241ae8e74SKuba Mracek         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
85341ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
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     result.SetStatus(eReturnStatusFailed);
86141ae8e74SKuba Mracek     return false;
86241ae8e74SKuba Mracek   }
86341ae8e74SKuba Mracek 
864db31e2e1SMed Ismail Bennani   if (m_options.m_symbols.empty()) {
865db31e2e1SMed Ismail Bennani     result.AppendErrorWithFormat(
866db31e2e1SMed Ismail Bennani         "%s needs at least one symbol name (-n argument).\n",
867db31e2e1SMed Ismail Bennani         m_cmd_name.c_str());
868db31e2e1SMed Ismail Bennani     result.SetStatus(eReturnStatusFailed);
869db31e2e1SMed Ismail Bennani     return false;
870db31e2e1SMed Ismail Bennani   }
871db31e2e1SMed Ismail Bennani 
872db31e2e1SMed Ismail Bennani   if (m_options.m_regex && m_options.m_symbols.size() > 1) {
873db31e2e1SMed Ismail Bennani     result.AppendErrorWithFormat(
874db31e2e1SMed Ismail Bennani         "%s needs only one symbol regular expression (-n argument).\n",
87541ae8e74SKuba Mracek         m_cmd_name.c_str());
87641ae8e74SKuba Mracek     result.SetStatus(eReturnStatusFailed);
87741ae8e74SKuba Mracek     return false;
87841ae8e74SKuba Mracek   }
87941ae8e74SKuba Mracek 
8802b29b432SJonas Devlieghere   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
88141ae8e74SKuba Mracek 
88241ae8e74SKuba Mracek   if (interpreter &&
88341ae8e74SKuba Mracek       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
884a925974bSAdrian Prantl     result.AppendWarning("The provided class does not exist - please define it "
88541ae8e74SKuba Mracek                          "before attempting to use this frame recognizer");
88641ae8e74SKuba Mracek   }
88741ae8e74SKuba Mracek 
88841ae8e74SKuba Mracek   StackFrameRecognizerSP recognizer_sp =
88941ae8e74SKuba Mracek       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
89041ae8e74SKuba Mracek           interpreter, m_options.m_class_name.c_str()));
89141ae8e74SKuba Mracek   if (m_options.m_regex) {
89241ae8e74SKuba Mracek     auto module =
89341ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_module));
89441ae8e74SKuba Mracek     auto func =
895db31e2e1SMed Ismail Bennani         RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
8961b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
8971b7c9eaeSRaphael Isemann         recognizer_sp, module, func);
89841ae8e74SKuba Mracek   } else {
89941ae8e74SKuba Mracek     auto module = ConstString(m_options.m_module);
900db31e2e1SMed Ismail Bennani     std::vector<ConstString> symbols(m_options.m_symbols.begin(),
901db31e2e1SMed Ismail Bennani                                      m_options.m_symbols.end());
9021b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
9031b7c9eaeSRaphael Isemann         recognizer_sp, module, symbols);
90441ae8e74SKuba Mracek   }
905f80d2655SKuba Mracek #endif
90641ae8e74SKuba Mracek 
90741ae8e74SKuba Mracek   result.SetStatus(eReturnStatusSuccessFinishNoResult);
90841ae8e74SKuba Mracek   return result.Succeeded();
90941ae8e74SKuba Mracek }
91041ae8e74SKuba Mracek 
91141ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
91241ae8e74SKuba Mracek public:
91341ae8e74SKuba Mracek   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
91441ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer clear",
91541ae8e74SKuba Mracek                             "Delete all frame recognizers.", nullptr) {}
91641ae8e74SKuba Mracek 
91741ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerClear() override = default;
91841ae8e74SKuba Mracek 
91941ae8e74SKuba Mracek protected:
92041ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
9211b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget()
9221b7c9eaeSRaphael Isemann         .GetFrameRecognizerManager()
9231b7c9eaeSRaphael Isemann         .RemoveAllRecognizers();
92441ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
92541ae8e74SKuba Mracek     return result.Succeeded();
92641ae8e74SKuba Mracek   }
92741ae8e74SKuba Mracek };
92841ae8e74SKuba Mracek 
92941ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
93041ae8e74SKuba Mracek public:
93141ae8e74SKuba Mracek   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
93241ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer delete",
93341ae8e74SKuba Mracek                             "Delete an existing frame recognizer.", nullptr) {}
93441ae8e74SKuba Mracek 
93541ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerDelete() override = default;
93641ae8e74SKuba Mracek 
937c37d25f0SGongyu Deng   void
938c37d25f0SGongyu Deng   HandleArgumentCompletion(CompletionRequest &request,
939c37d25f0SGongyu Deng                            OptionElementVector &opt_element_vector) override {
940c37d25f0SGongyu Deng     if (request.GetCursorIndex() != 0)
941c37d25f0SGongyu Deng       return;
942c37d25f0SGongyu Deng 
9431b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
944c37d25f0SGongyu Deng         [&request](uint32_t rid, std::string rname, std::string module,
945c37d25f0SGongyu Deng                    llvm::ArrayRef<lldb_private::ConstString> symbols,
946c37d25f0SGongyu Deng                    bool regexp) {
947c37d25f0SGongyu Deng           StreamString strm;
948c37d25f0SGongyu Deng           if (rname.empty())
949c37d25f0SGongyu Deng             rname = "(internal)";
950c37d25f0SGongyu Deng 
951c37d25f0SGongyu Deng           strm << rname;
952c37d25f0SGongyu Deng           if (!module.empty())
953c37d25f0SGongyu Deng             strm << ", module " << module;
954c37d25f0SGongyu Deng           if (!symbols.empty())
955c37d25f0SGongyu Deng             for (auto &symbol : symbols)
956c37d25f0SGongyu Deng               strm << ", symbol " << symbol;
957c37d25f0SGongyu Deng           if (regexp)
958c37d25f0SGongyu Deng             strm << " (regexp)";
959c37d25f0SGongyu Deng 
960c37d25f0SGongyu Deng           request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
961c37d25f0SGongyu Deng         });
962c37d25f0SGongyu Deng   }
963c37d25f0SGongyu Deng 
96441ae8e74SKuba Mracek protected:
96541ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
96641ae8e74SKuba Mracek     if (command.GetArgumentCount() == 0) {
96741ae8e74SKuba Mracek       if (!m_interpreter.Confirm(
96841ae8e74SKuba Mracek               "About to delete all frame recognizers, do you want to do that?",
96941ae8e74SKuba Mracek               true)) {
97041ae8e74SKuba Mracek         result.AppendMessage("Operation cancelled...");
97141ae8e74SKuba Mracek         result.SetStatus(eReturnStatusFailed);
97241ae8e74SKuba Mracek         return false;
97341ae8e74SKuba Mracek       }
97441ae8e74SKuba Mracek 
9751b7c9eaeSRaphael Isemann       GetSelectedOrDummyTarget()
9761b7c9eaeSRaphael Isemann           .GetFrameRecognizerManager()
9771b7c9eaeSRaphael Isemann           .RemoveAllRecognizers();
97841ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
97941ae8e74SKuba Mracek       return result.Succeeded();
98041ae8e74SKuba Mracek     }
98141ae8e74SKuba Mracek 
98241ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
98341ae8e74SKuba Mracek       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
98441ae8e74SKuba Mracek                                    m_cmd_name.c_str());
98541ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
98641ae8e74SKuba Mracek       return false;
98741ae8e74SKuba Mracek     }
98841ae8e74SKuba Mracek 
9899010cef2SRaphael Isemann     uint32_t recognizer_id;
9909010cef2SRaphael Isemann     if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
9919010cef2SRaphael Isemann       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
9929010cef2SRaphael Isemann                                    command.GetArgumentAtIndex(0));
9939010cef2SRaphael Isemann       result.SetStatus(eReturnStatusFailed);
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       result.SetStatus(eReturnStatusFailed);
10035477fbc2SRaphael Isemann       return false;
10045477fbc2SRaphael Isemann     }
100541ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
100641ae8e74SKuba Mracek     return result.Succeeded();
100741ae8e74SKuba Mracek   }
100841ae8e74SKuba Mracek };
100941ae8e74SKuba Mracek 
101041ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed {
101141ae8e74SKuba Mracek public:
101241ae8e74SKuba Mracek   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
101341ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer list",
101441ae8e74SKuba Mracek                             "Show a list of active frame recognizers.",
101541ae8e74SKuba Mracek                             nullptr) {}
101641ae8e74SKuba Mracek 
101741ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerList() override = default;
101841ae8e74SKuba Mracek 
101941ae8e74SKuba Mracek protected:
102041ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
102141ae8e74SKuba Mracek     bool any_printed = false;
10221b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
1023db31e2e1SMed Ismail Bennani         [&result, &any_printed](
1024db31e2e1SMed Ismail Bennani             uint32_t recognizer_id, std::string name, std::string module,
1025db31e2e1SMed Ismail Bennani             llvm::ArrayRef<ConstString> symbols, bool regexp) {
1026cb0c4ee3SMed Ismail Bennani           Stream &stream = result.GetOutputStream();
1027cb0c4ee3SMed Ismail Bennani 
1028cb0c4ee3SMed Ismail Bennani           if (name.empty())
1029a925974bSAdrian Prantl             name = "(internal)";
1030cb0c4ee3SMed Ismail Bennani 
1031cb0c4ee3SMed Ismail Bennani           stream << std::to_string(recognizer_id) << ": " << name;
1032cb0c4ee3SMed Ismail Bennani           if (!module.empty())
1033cb0c4ee3SMed Ismail Bennani             stream << ", module " << module;
1034db31e2e1SMed Ismail Bennani           if (!symbols.empty())
1035db31e2e1SMed Ismail Bennani             for (auto &symbol : symbols)
1036db31e2e1SMed Ismail Bennani               stream << ", symbol " << symbol;
1037cb0c4ee3SMed Ismail Bennani           if (regexp)
1038cb0c4ee3SMed Ismail Bennani             stream << " (regexp)";
1039cb0c4ee3SMed Ismail Bennani 
1040cb0c4ee3SMed Ismail Bennani           stream.EOL();
1041cb0c4ee3SMed Ismail Bennani           stream.Flush();
1042cb0c4ee3SMed Ismail Bennani 
104341ae8e74SKuba Mracek           any_printed = true;
104441ae8e74SKuba Mracek         });
104541ae8e74SKuba Mracek 
104641ae8e74SKuba Mracek     if (any_printed)
104741ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
104841ae8e74SKuba Mracek     else {
104941ae8e74SKuba Mracek       result.GetOutputStream().PutCString("no matching results found.\n");
105041ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishNoResult);
105141ae8e74SKuba Mracek     }
105241ae8e74SKuba Mracek     return result.Succeeded();
105341ae8e74SKuba Mracek   }
105441ae8e74SKuba Mracek };
105541ae8e74SKuba Mracek 
105641ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
105741ae8e74SKuba Mracek public:
105841ae8e74SKuba Mracek   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
105941ae8e74SKuba Mracek       : CommandObjectParsed(
106041ae8e74SKuba Mracek             interpreter, "frame recognizer info",
106141ae8e74SKuba Mracek             "Show which frame recognizer is applied a stack frame (if any).",
106241ae8e74SKuba Mracek             nullptr) {
106341ae8e74SKuba Mracek     CommandArgumentEntry arg;
106441ae8e74SKuba Mracek     CommandArgumentData index_arg;
106541ae8e74SKuba Mracek 
106641ae8e74SKuba Mracek     // Define the first (and only) variant of this arg.
106741ae8e74SKuba Mracek     index_arg.arg_type = eArgTypeFrameIndex;
106841ae8e74SKuba Mracek     index_arg.arg_repetition = eArgRepeatPlain;
106941ae8e74SKuba Mracek 
107041ae8e74SKuba Mracek     // There is only one variant this argument could be; put it into the
107141ae8e74SKuba Mracek     // argument entry.
107241ae8e74SKuba Mracek     arg.push_back(index_arg);
107341ae8e74SKuba Mracek 
107441ae8e74SKuba Mracek     // Push the data for the first argument into the m_arguments vector.
107541ae8e74SKuba Mracek     m_arguments.push_back(arg);
107641ae8e74SKuba Mracek   }
107741ae8e74SKuba Mracek 
107841ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerInfo() override = default;
107941ae8e74SKuba Mracek 
108041ae8e74SKuba Mracek protected:
108141ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
10829010cef2SRaphael Isemann     const char *frame_index_str = command.GetArgumentAtIndex(0);
10839010cef2SRaphael Isemann     uint32_t frame_index;
10849010cef2SRaphael Isemann     if (!llvm::to_integer(frame_index_str, frame_index)) {
10859010cef2SRaphael Isemann       result.AppendErrorWithFormat("'%s' is not a valid frame index.",
10869010cef2SRaphael Isemann                                    frame_index_str);
10879010cef2SRaphael Isemann       result.SetStatus(eReturnStatusFailed);
10889010cef2SRaphael Isemann       return false;
10899010cef2SRaphael Isemann     }
10909010cef2SRaphael Isemann 
109141ae8e74SKuba Mracek     Process *process = m_exe_ctx.GetProcessPtr();
109241ae8e74SKuba Mracek     if (process == nullptr) {
109341ae8e74SKuba Mracek       result.AppendError("no process");
109441ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
109541ae8e74SKuba Mracek       return false;
109641ae8e74SKuba Mracek     }
109741ae8e74SKuba Mracek     Thread *thread = m_exe_ctx.GetThreadPtr();
109841ae8e74SKuba Mracek     if (thread == nullptr) {
109941ae8e74SKuba Mracek       result.AppendError("no thread");
110041ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
110141ae8e74SKuba Mracek       return false;
110241ae8e74SKuba Mracek     }
110341ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
110441ae8e74SKuba Mracek       result.AppendErrorWithFormat(
110541ae8e74SKuba Mracek           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
110641ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
110741ae8e74SKuba Mracek       return false;
110841ae8e74SKuba Mracek     }
110941ae8e74SKuba Mracek 
111041ae8e74SKuba Mracek     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
111141ae8e74SKuba Mracek     if (!frame_sp) {
111241ae8e74SKuba Mracek       result.AppendErrorWithFormat("no frame with index %u", frame_index);
111341ae8e74SKuba Mracek       result.SetStatus(eReturnStatusFailed);
111441ae8e74SKuba Mracek       return false;
111541ae8e74SKuba Mracek     }
111641ae8e74SKuba Mracek 
11171b7c9eaeSRaphael Isemann     auto recognizer = GetSelectedOrDummyTarget()
11181b7c9eaeSRaphael Isemann                           .GetFrameRecognizerManager()
11191b7c9eaeSRaphael Isemann                           .GetRecognizerForFrame(frame_sp);
112041ae8e74SKuba Mracek 
112141ae8e74SKuba Mracek     Stream &output_stream = result.GetOutputStream();
112241ae8e74SKuba Mracek     output_stream.Printf("frame %d ", frame_index);
112341ae8e74SKuba Mracek     if (recognizer) {
112441ae8e74SKuba Mracek       output_stream << "is recognized by ";
112541ae8e74SKuba Mracek       output_stream << recognizer->GetName();
112641ae8e74SKuba Mracek     } else {
112741ae8e74SKuba Mracek       output_stream << "not recognized by any recognizer";
112841ae8e74SKuba Mracek     }
112941ae8e74SKuba Mracek     output_stream.EOL();
113041ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
113141ae8e74SKuba Mracek     return result.Succeeded();
113241ae8e74SKuba Mracek   }
113341ae8e74SKuba Mracek };
113441ae8e74SKuba Mracek 
113541ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword {
113641ae8e74SKuba Mracek public:
113741ae8e74SKuba Mracek   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
113841ae8e74SKuba Mracek       : CommandObjectMultiword(
113941ae8e74SKuba Mracek             interpreter, "frame recognizer",
114041ae8e74SKuba Mracek             "Commands for editing and viewing frame recognizers.",
114141ae8e74SKuba Mracek             "frame recognizer [<sub-command-options>] ") {
1142a925974bSAdrian Prantl     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1143a925974bSAdrian Prantl                               interpreter)));
114441ae8e74SKuba Mracek     LoadSubCommand(
114541ae8e74SKuba Mracek         "clear",
114641ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
114741ae8e74SKuba Mracek     LoadSubCommand(
114841ae8e74SKuba Mracek         "delete",
114941ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1150a925974bSAdrian Prantl     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1151a925974bSAdrian Prantl                                interpreter)));
1152a925974bSAdrian Prantl     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1153a925974bSAdrian Prantl                                interpreter)));
115441ae8e74SKuba Mracek   }
115541ae8e74SKuba Mracek 
115641ae8e74SKuba Mracek   ~CommandObjectFrameRecognizer() override = default;
115741ae8e74SKuba Mracek };
115841ae8e74SKuba Mracek 
115930fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
116030fdc8d8SChris Lattner 
116130fdc8d8SChris Lattner // CommandObjectMultiwordFrame
116230fdc8d8SChris Lattner 
1163b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1164b9c1b51eSKate Stone     CommandInterpreter &interpreter)
1165a925974bSAdrian Prantl     : CommandObjectMultiword(interpreter, "frame",
1166a925974bSAdrian Prantl                              "Commands for selecting and "
1167b9c1b51eSKate Stone                              "examing the current "
1168b9c1b51eSKate Stone                              "thread's stack frames.",
1169b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
1170b9c1b51eSKate Stone   LoadSubCommand("diagnose",
1171b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1172b9c1b51eSKate Stone   LoadSubCommand("info",
1173b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1174b9c1b51eSKate Stone   LoadSubCommand("select",
1175b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1176b9c1b51eSKate Stone   LoadSubCommand("variable",
1177b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
11784e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
1179a925974bSAdrian Prantl   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1180a925974bSAdrian Prantl                                    interpreter)));
118141ae8e74SKuba Mracek #endif
118230fdc8d8SChris Lattner }
118330fdc8d8SChris Lattner 
1184c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1185