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"
167ced9fffSJonas Devlieghere #include "lldb/Interpreter/CommandOptionArgumentTable.h"
1730fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h"
1854c496daSRoman Podoliaka #include "lldb/Interpreter/OptionArgParser.h"
191deb7962SGreg Clayton #include "lldb/Interpreter/OptionGroupFormat.h"
202837b766SJim Ingham #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
21715c2365SGreg Clayton #include "lldb/Interpreter/OptionGroupVariable.h"
22b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h"
236754e04fSEnrico Granata #include "lldb/Symbol/Function.h"
246d56d2ceSJim Ingham #include "lldb/Symbol/SymbolContext.h"
256d56d2ceSJim Ingham #include "lldb/Symbol/Variable.h"
266d56d2ceSJim Ingham #include "lldb/Symbol/VariableList.h"
27b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h"
2841ae8e74SKuba Mracek #include "lldb/Target/StackFrameRecognizer.h"
294740a734SSean Callanan #include "lldb/Target/StopInfo.h"
306d56d2ceSJim Ingham #include "lldb/Target/Target.h"
31b9c1b51eSKate Stone #include "lldb/Target/Thread.h"
32145d95c9SPavel Labath #include "lldb/Utility/Args.h"
3330fdc8d8SChris Lattner 
34796ac80bSJonas Devlieghere #include <memory>
35796ac80bSJonas Devlieghere #include <string>
36796ac80bSJonas Devlieghere 
3730fdc8d8SChris Lattner using namespace lldb;
3830fdc8d8SChris Lattner using namespace lldb_private;
3930fdc8d8SChris Lattner 
404740a734SSean Callanan #pragma mark CommandObjectFrameDiagnose
414740a734SSean Callanan 
424740a734SSean Callanan // CommandObjectFrameInfo
434740a734SSean Callanan 
444740a734SSean Callanan // CommandObjectFrameDiagnose
454740a734SSean Callanan 
46ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_diag
47ec67e734SRaphael Isemann #include "CommandOptions.inc"
481f0f5b5bSZachary Turner 
49b9c1b51eSKate Stone class CommandObjectFrameDiagnose : public CommandObjectParsed {
504740a734SSean Callanan public:
51b9c1b51eSKate Stone   class CommandOptions : public Options {
524740a734SSean Callanan   public:
CommandOptions()53abb0ed44SKazu Hirata     CommandOptions() { OptionParsingStarting(nullptr); }
544740a734SSean Callanan 
554740a734SSean Callanan     ~CommandOptions() override = default;
564740a734SSean Callanan 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)5797206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
58b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
5997206d57SZachary Turner       Status error;
604740a734SSean Callanan       const int short_option = m_getopt_table[option_idx].val;
61b9c1b51eSKate Stone       switch (short_option) {
624740a734SSean Callanan       case 'r':
634740a734SSean Callanan         reg = ConstString(option_arg);
644740a734SSean Callanan         break;
654740a734SSean Callanan 
66b9c1b51eSKate Stone       case 'a': {
67fe11483bSZachary Turner         address.emplace();
68fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *address)) {
694740a734SSean Callanan           address.reset();
70b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid address argument '%s'",
71fe11483bSZachary Turner                                          option_arg.str().c_str());
724740a734SSean Callanan         }
73b9c1b51eSKate Stone       } break;
744740a734SSean Callanan 
75b9c1b51eSKate Stone       case 'o': {
76fe11483bSZachary Turner         offset.emplace();
77fe11483bSZachary Turner         if (option_arg.getAsInteger(0, *offset)) {
784740a734SSean Callanan           offset.reset();
79b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid offset argument '%s'",
80fe11483bSZachary Turner                                          option_arg.str().c_str());
814740a734SSean Callanan         }
82b9c1b51eSKate Stone       } break;
834740a734SSean Callanan 
844740a734SSean Callanan       default:
8536162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
864740a734SSean Callanan       }
874740a734SSean Callanan 
884740a734SSean Callanan       return error;
894740a734SSean Callanan     }
904740a734SSean Callanan 
OptionParsingStarting(ExecutionContext * execution_context)91b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
924740a734SSean Callanan       address.reset();
934740a734SSean Callanan       reg.reset();
944740a734SSean Callanan       offset.reset();
954740a734SSean Callanan     }
964740a734SSean Callanan 
GetDefinitions()971f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
9870602439SZachary Turner       return llvm::makeArrayRef(g_frame_diag_options);
991f0f5b5bSZachary Turner     }
1004740a734SSean Callanan 
1014740a734SSean Callanan     // Options.
1024740a734SSean Callanan     llvm::Optional<lldb::addr_t> address;
1034740a734SSean Callanan     llvm::Optional<ConstString> reg;
1044740a734SSean Callanan     llvm::Optional<int64_t> offset;
1054740a734SSean Callanan   };
1064740a734SSean Callanan 
CommandObjectFrameDiagnose(CommandInterpreter & interpreter)1074740a734SSean Callanan   CommandObjectFrameDiagnose(CommandInterpreter &interpreter)
1084740a734SSean Callanan       : CommandObjectParsed(interpreter, "frame diagnose",
109722a2fb7SDave Lee                             "Try to determine what path the current stop "
110b9c1b51eSKate Stone                             "location used to get to a register or address",
111b9c1b51eSKate Stone                             nullptr,
112b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
113b9c1b51eSKate Stone                                 eCommandProcessMustBeLaunched |
114abb0ed44SKazu Hirata                                 eCommandProcessMustBePaused) {
1154740a734SSean Callanan     CommandArgumentEntry arg;
1164740a734SSean Callanan     CommandArgumentData index_arg;
1174740a734SSean Callanan 
1184740a734SSean Callanan     // Define the first (and only) variant of this arg.
1194740a734SSean Callanan     index_arg.arg_type = eArgTypeFrameIndex;
1204740a734SSean Callanan     index_arg.arg_repetition = eArgRepeatOptional;
1214740a734SSean Callanan 
122b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
123b9c1b51eSKate Stone     // argument entry.
1244740a734SSean Callanan     arg.push_back(index_arg);
1254740a734SSean Callanan 
1264740a734SSean Callanan     // Push the data for the first argument into the m_arguments vector.
1274740a734SSean Callanan     m_arguments.push_back(arg);
1284740a734SSean Callanan   }
1294740a734SSean Callanan 
1304740a734SSean Callanan   ~CommandObjectFrameDiagnose() override = default;
1314740a734SSean Callanan 
GetOptions()132b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
1334740a734SSean Callanan 
1344740a734SSean Callanan protected:
DoExecute(Args & command,CommandReturnObject & result)135b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1364740a734SSean Callanan     Thread *thread = m_exe_ctx.GetThreadPtr();
1374740a734SSean Callanan     StackFrameSP frame_sp = thread->GetSelectedFrame();
1384740a734SSean Callanan 
1394740a734SSean Callanan     ValueObjectSP valobj_sp;
1404740a734SSean Callanan 
14196d1b4ddSKazu Hirata     if (m_options.address) {
14296d1b4ddSKazu Hirata       if (m_options.reg || m_options.offset) {
143b9c1b51eSKate Stone         result.AppendError(
144b9c1b51eSKate Stone             "`frame diagnose --address` is incompatible with other arguments.");
1454740a734SSean Callanan         return false;
1464740a734SSean Callanan       }
147*5cff5142SKazu Hirata       valobj_sp = frame_sp->GuessValueForAddress(m_options.address.value());
14896d1b4ddSKazu Hirata     } else if (m_options.reg) {
149b9c1b51eSKate Stone       valobj_sp = frame_sp->GuessValueForRegisterAndOffset(
150*5cff5142SKazu Hirata           m_options.reg.value(), m_options.offset.value_or(0));
151b9c1b51eSKate Stone     } else {
1524740a734SSean Callanan       StopInfoSP stop_info_sp = thread->GetStopInfo();
153b9c1b51eSKate Stone       if (!stop_info_sp) {
1544740a734SSean Callanan         result.AppendError("No arguments provided, and no stop info.");
1554740a734SSean Callanan         return false;
1564740a734SSean Callanan       }
1574740a734SSean Callanan 
1584740a734SSean Callanan       valobj_sp = StopInfo::GetCrashingDereference(stop_info_sp);
1594740a734SSean Callanan     }
1604740a734SSean Callanan 
161b9c1b51eSKate Stone     if (!valobj_sp) {
1624740a734SSean Callanan       result.AppendError("No diagnosis available.");
1634740a734SSean Callanan       return false;
1644740a734SSean Callanan     }
1654740a734SSean Callanan 
166a925974bSAdrian Prantl     DumpValueObjectOptions::DeclPrintingHelper helper =
167a925974bSAdrian Prantl         [&valobj_sp](ConstString type, ConstString var,
168a925974bSAdrian Prantl                      const DumpValueObjectOptions &opts,
1693bc714b2SZachary Turner                      Stream &stream) -> bool {
170b9c1b51eSKate Stone       const ValueObject::GetExpressionPathFormat format = ValueObject::
171b9c1b51eSKate Stone           GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
1723014efe0SAlex Langford       valobj_sp->GetExpressionPath(stream, format);
1734740a734SSean Callanan       stream.PutCString(" =");
1744740a734SSean Callanan       return true;
1754740a734SSean Callanan     };
1764740a734SSean Callanan 
1774740a734SSean Callanan     DumpValueObjectOptions options;
1784740a734SSean Callanan     options.SetDeclPrintingHelper(helper);
179b9c1b51eSKate Stone     ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(),
180b9c1b51eSKate Stone                                options);
1814740a734SSean Callanan     printer.PrintValueObject();
1824740a734SSean Callanan 
1834740a734SSean Callanan     return true;
1844740a734SSean Callanan   }
1854740a734SSean Callanan 
1864740a734SSean Callanan   CommandOptions m_options;
1874740a734SSean Callanan };
1884740a734SSean Callanan 
18930fdc8d8SChris Lattner #pragma mark CommandObjectFrameInfo
19030fdc8d8SChris Lattner 
19130fdc8d8SChris Lattner // CommandObjectFrameInfo
19230fdc8d8SChris Lattner 
193b9c1b51eSKate Stone class CommandObjectFrameInfo : public CommandObjectParsed {
19430fdc8d8SChris Lattner public:
CommandObjectFrameInfo(CommandInterpreter & interpreter)1957428a18cSKate Stone   CommandObjectFrameInfo(CommandInterpreter &interpreter)
196a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame info",
197a925974bSAdrian Prantl                             "List information about the current "
198b9c1b51eSKate Stone                             "stack frame in the current thread.",
199b9c1b51eSKate Stone                             "frame info",
200b9c1b51eSKate Stone                             eCommandRequiresFrame | eCommandTryTargetAPILock |
201a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
202a925974bSAdrian Prantl                                 eCommandProcessMustBePaused) {}
20330fdc8d8SChris Lattner 
204c8ecc2a9SEugene Zelenko   ~CommandObjectFrameInfo() override = default;
20530fdc8d8SChris Lattner 
2065a988416SJim Ingham protected:
DoExecute(Args & command,CommandReturnObject & result)207b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
208f9fc609fSGreg Clayton     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
20930fdc8d8SChris Lattner     result.SetStatus(eReturnStatusSuccessFinishResult);
21030fdc8d8SChris Lattner     return result.Succeeded();
21130fdc8d8SChris Lattner   }
21230fdc8d8SChris Lattner };
21330fdc8d8SChris Lattner 
21430fdc8d8SChris Lattner #pragma mark CommandObjectFrameSelect
21530fdc8d8SChris Lattner 
21630fdc8d8SChris Lattner // CommandObjectFrameSelect
21730fdc8d8SChris Lattner 
218ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_select
219ec67e734SRaphael Isemann #include "CommandOptions.inc"
2201f0f5b5bSZachary Turner 
221b9c1b51eSKate Stone class CommandObjectFrameSelect : public CommandObjectParsed {
22230fdc8d8SChris Lattner public:
223b9c1b51eSKate Stone   class CommandOptions : public Options {
224864174e1SGreg Clayton   public:
CommandOptions()225abb0ed44SKazu Hirata     CommandOptions() { OptionParsingStarting(nullptr); }
226864174e1SGreg Clayton 
227c8ecc2a9SEugene Zelenko     ~CommandOptions() override = default;
228864174e1SGreg Clayton 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)22997206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
230b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
23197206d57SZachary Turner       Status error;
2323bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
233b9c1b51eSKate Stone       switch (short_option) {
234dab6f074SRaphael Isemann       case 'r': {
235dab6f074SRaphael Isemann         int32_t offset = 0;
236dab6f074SRaphael Isemann         if (option_arg.getAsInteger(0, offset) || offset == INT32_MIN) {
237b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid frame offset argument '%s'",
238fe11483bSZachary Turner                                          option_arg.str().c_str());
239dab6f074SRaphael Isemann         } else
240dab6f074SRaphael Isemann           relative_frame_offset = offset;
2415a039d55SRaphael Isemann         break;
242dab6f074SRaphael Isemann       }
243864174e1SGreg Clayton 
244864174e1SGreg Clayton       default:
24536162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
246864174e1SGreg Clayton       }
247864174e1SGreg Clayton 
248864174e1SGreg Clayton       return error;
249864174e1SGreg Clayton     }
250864174e1SGreg Clayton 
OptionParsingStarting(ExecutionContext * execution_context)2515a039d55SRaphael Isemann     void OptionParsingStarting(ExecutionContext *execution_context) override {
252dab6f074SRaphael Isemann       relative_frame_offset.reset();
2535a039d55SRaphael Isemann     }
254864174e1SGreg Clayton 
GetDefinitions()2551f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
25670602439SZachary Turner       return llvm::makeArrayRef(g_frame_select_options);
2571f0f5b5bSZachary Turner     }
258864174e1SGreg Clayton 
259dab6f074SRaphael Isemann     llvm::Optional<int32_t> relative_frame_offset;
260864174e1SGreg Clayton   };
261864174e1SGreg Clayton 
CommandObjectFrameSelect(CommandInterpreter & interpreter)2627428a18cSKate Stone   CommandObjectFrameSelect(CommandInterpreter &interpreter)
263a925974bSAdrian Prantl       : CommandObjectParsed(interpreter, "frame select",
264a925974bSAdrian Prantl                             "Select the current stack frame by "
265b9c1b51eSKate Stone                             "index from within the current thread "
266b9c1b51eSKate Stone                             "(see 'thread backtrace'.)",
267b9c1b51eSKate Stone                             nullptr,
268b9c1b51eSKate Stone                             eCommandRequiresThread | eCommandTryTargetAPILock |
269a925974bSAdrian Prantl                                 eCommandProcessMustBeLaunched |
270abb0ed44SKazu Hirata                                 eCommandProcessMustBePaused) {
271405fe67fSCaroline Tice     CommandArgumentEntry arg;
272405fe67fSCaroline Tice     CommandArgumentData index_arg;
273405fe67fSCaroline Tice 
274405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
275405fe67fSCaroline Tice     index_arg.arg_type = eArgTypeFrameIndex;
276864174e1SGreg Clayton     index_arg.arg_repetition = eArgRepeatOptional;
277405fe67fSCaroline Tice 
278b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
279b9c1b51eSKate Stone     // argument entry.
280405fe67fSCaroline Tice     arg.push_back(index_arg);
281405fe67fSCaroline Tice 
282405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
283405fe67fSCaroline Tice     m_arguments.push_back(arg);
28430fdc8d8SChris Lattner   }
28530fdc8d8SChris Lattner 
286c8ecc2a9SEugene Zelenko   ~CommandObjectFrameSelect() override = default;
28730fdc8d8SChris Lattner 
28880eb4228SGongyu Deng   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)28980eb4228SGongyu Deng   HandleArgumentCompletion(CompletionRequest &request,
29080eb4228SGongyu Deng                            OptionElementVector &opt_element_vector) override {
29166fa73faSGongyu Deng     if (request.GetCursorIndex() != 0)
29280eb4228SGongyu Deng       return;
29380eb4228SGongyu Deng 
29466fa73faSGongyu Deng     CommandCompletions::InvokeCommonCompletionCallbacks(
29566fa73faSGongyu Deng         GetCommandInterpreter(), CommandCompletions::eFrameIndexCompletion,
29666fa73faSGongyu Deng         request, nullptr);
29780eb4228SGongyu Deng   }
29880eb4228SGongyu Deng 
GetOptions()299b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
300864174e1SGreg Clayton 
3015a988416SJim Ingham protected:
DoExecute(Args & command,CommandReturnObject & result)302b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
303b9c1b51eSKate Stone     // No need to check "thread" for validity as eCommandRequiresThread ensures
304b9c1b51eSKate Stone     // it is valid
305f9fc609fSGreg Clayton     Thread *thread = m_exe_ctx.GetThreadPtr();
306f9fc609fSGreg Clayton 
307864174e1SGreg Clayton     uint32_t frame_idx = UINT32_MAX;
3085413bf1bSKazu Hirata     if (m_options.relative_frame_offset) {
309864174e1SGreg Clayton       // The one and only argument is a signed relative frame index
310c14ee32dSGreg Clayton       frame_idx = thread->GetSelectedFrameIndex();
311864174e1SGreg Clayton       if (frame_idx == UINT32_MAX)
312864174e1SGreg Clayton         frame_idx = 0;
313864174e1SGreg Clayton 
314dab6f074SRaphael Isemann       if (*m_options.relative_frame_offset < 0) {
315dab6f074SRaphael Isemann         if (static_cast<int32_t>(frame_idx) >=
316dab6f074SRaphael Isemann             -*m_options.relative_frame_offset)
317dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
318b9c1b51eSKate Stone         else {
319b9c1b51eSKate Stone           if (frame_idx == 0) {
32005097246SAdrian Prantl             // If you are already at the bottom of the stack, then just warn
32105097246SAdrian Prantl             // and don't reset the frame.
3227428a18cSKate Stone             result.AppendError("Already at the bottom of the stack.");
323213b4546SJim Ingham             return false;
324b9c1b51eSKate Stone           } else
325864174e1SGreg Clayton             frame_idx = 0;
326864174e1SGreg Clayton         }
327dab6f074SRaphael Isemann       } else if (*m_options.relative_frame_offset > 0) {
328b9c1b51eSKate Stone         // I don't want "up 20" where "20" takes you past the top of the stack
329b9c1b51eSKate Stone         // to produce
330b9c1b51eSKate Stone         // an error, but rather to just go to the top.  So I have to count the
331b9c1b51eSKate Stone         // stack here...
332b0c72a5fSJim Ingham         const uint32_t num_frames = thread->GetStackFrameCount();
333b9c1b51eSKate Stone         if (static_cast<int32_t>(num_frames - frame_idx) >
334dab6f074SRaphael Isemann             *m_options.relative_frame_offset)
335dab6f074SRaphael Isemann           frame_idx += *m_options.relative_frame_offset;
336b9c1b51eSKate Stone         else {
337b9c1b51eSKate Stone           if (frame_idx == num_frames - 1) {
338b9c1b51eSKate Stone             // If we are already at the top of the stack, just warn and don't
339b9c1b51eSKate Stone             // reset the frame.
3407428a18cSKate Stone             result.AppendError("Already at the top of the stack.");
341213b4546SJim Ingham             return false;
342b9c1b51eSKate Stone           } else
343864174e1SGreg Clayton             frame_idx = num_frames - 1;
344864174e1SGreg Clayton         }
345864174e1SGreg Clayton       }
346b9c1b51eSKate Stone     } else {
347f965cc86SZachary Turner       if (command.GetArgumentCount() > 1) {
348f965cc86SZachary Turner         result.AppendErrorWithFormat(
349f965cc86SZachary Turner             "too many arguments; expected frame-index, saw '%s'.\n",
350867e7d17SZachary Turner             command[0].c_str());
351f965cc86SZachary Turner         m_options.GenerateOptionUsage(
352e473e79cSDavid Spickett             result.GetErrorStream(), *this,
353f965cc86SZachary Turner             GetCommandInterpreter().GetDebugger().GetTerminalWidth());
354f965cc86SZachary Turner         return false;
355f965cc86SZachary Turner       }
356f965cc86SZachary Turner 
357b9c1b51eSKate Stone       if (command.GetArgumentCount() == 1) {
3580d9a201eSRaphael Isemann         if (command[0].ref().getAsInteger(0, frame_idx)) {
359b9c1b51eSKate Stone           result.AppendErrorWithFormat("invalid frame index argument '%s'.",
360f965cc86SZachary Turner                                        command[0].c_str());
361afbb0af8SJim Ingham           return false;
362afbb0af8SJim Ingham         }
363b9c1b51eSKate Stone       } else if (command.GetArgumentCount() == 0) {
36482d4a2b9SJason Molenda         frame_idx = thread->GetSelectedFrameIndex();
365b9c1b51eSKate Stone         if (frame_idx == UINT32_MAX) {
36682d4a2b9SJason Molenda           frame_idx = 0;
36782d4a2b9SJason Molenda         }
368864174e1SGreg Clayton       }
369864174e1SGreg Clayton     }
37030fdc8d8SChris Lattner 
371b9c1b51eSKate Stone     bool success = thread->SetSelectedFrameByIndexNoisily(
372b9c1b51eSKate Stone         frame_idx, result.GetOutputStream());
373b9c1b51eSKate Stone     if (success) {
374f9fc609fSGreg Clayton       m_exe_ctx.SetFrameSP(thread->GetSelectedFrame());
37530fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
376b9c1b51eSKate Stone     } else {
377b9c1b51eSKate Stone       result.AppendErrorWithFormat("Frame index (%u) out of range.\n",
378b9c1b51eSKate Stone                                    frame_idx);
37993208b86SJim Ingham     }
38093208b86SJim Ingham 
38193208b86SJim Ingham     return result.Succeeded();
38230fdc8d8SChris Lattner   }
383864174e1SGreg Clayton 
384864174e1SGreg Clayton   CommandOptions m_options;
385864174e1SGreg Clayton };
386864174e1SGreg Clayton 
3876d56d2ceSJim Ingham #pragma mark CommandObjectFrameVariable
3886d56d2ceSJim Ingham // List images with associated information
389b9c1b51eSKate Stone class CommandObjectFrameVariable : public CommandObjectParsed {
3906d56d2ceSJim Ingham public:
CommandObjectFrameVariable(CommandInterpreter & interpreter)3917428a18cSKate Stone   CommandObjectFrameVariable(CommandInterpreter &interpreter)
3927428a18cSKate Stone       : CommandObjectParsed(
393b9c1b51eSKate Stone             interpreter, "frame variable",
394b9c1b51eSKate Stone             "Show variables for the current stack frame. Defaults to all "
3957428a18cSKate Stone             "arguments and local variables in scope. Names of argument, "
396ef6817f9SDave Lee             "local, file static and file global variables can be specified.",
397a925974bSAdrian Prantl             nullptr,
398a925974bSAdrian Prantl             eCommandRequiresFrame | eCommandTryTargetAPILock |
399a925974bSAdrian Prantl                 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
400a925974bSAdrian Prantl                 eCommandRequiresProcess),
401b9c1b51eSKate Stone         m_option_variable(
402b9c1b51eSKate Stone             true), // Include the frame specific options by passing "true"
403abb0ed44SKazu Hirata         m_option_format(eFormatDefault) {
404ef6817f9SDave Lee     SetHelpLong(R"(
405ef6817f9SDave Lee Children of aggregate variables can be specified such as 'var->child.x'.  In
406ef6817f9SDave Lee 'frame variable', the operators -> and [] do not invoke operator overloads if
407ef6817f9SDave Lee they exist, but directly access the specified element.  If you want to trigger
408ef6817f9SDave Lee operator overloads use the expression command to print the variable instead.
409ef6817f9SDave Lee 
410ef6817f9SDave Lee It is worth noting that except for overloaded operators, when printing local
411ef6817f9SDave Lee variables 'expr local_var' and 'frame var local_var' produce the same results.
412ef6817f9SDave Lee However, 'frame variable' is more efficient, since it uses debug information and
413ef6817f9SDave Lee memory reads directly, rather than parsing and evaluating an expression, which
414ef6817f9SDave Lee may even involve JITing and running code in the target program.)");
415ef6817f9SDave Lee 
416405fe67fSCaroline Tice     CommandArgumentEntry arg;
417405fe67fSCaroline Tice     CommandArgumentData var_name_arg;
418405fe67fSCaroline Tice 
419405fe67fSCaroline Tice     // Define the first (and only) variant of this arg.
420405fe67fSCaroline Tice     var_name_arg.arg_type = eArgTypeVarName;
421405fe67fSCaroline Tice     var_name_arg.arg_repetition = eArgRepeatStar;
422405fe67fSCaroline Tice 
423b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
424b9c1b51eSKate Stone     // argument entry.
425405fe67fSCaroline Tice     arg.push_back(var_name_arg);
426405fe67fSCaroline Tice 
427405fe67fSCaroline Tice     // Push the data for the first argument into the m_arguments vector.
428405fe67fSCaroline Tice     m_arguments.push_back(arg);
4292837b766SJim Ingham 
430715c2365SGreg Clayton     m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
431b9c1b51eSKate Stone     m_option_group.Append(&m_option_format,
432b9c1b51eSKate Stone                           OptionGroupFormat::OPTION_GROUP_FORMAT |
433b9c1b51eSKate Stone                               OptionGroupFormat::OPTION_GROUP_GDB_FMT,
434b9c1b51eSKate Stone                           LLDB_OPT_SET_1);
4352837b766SJim Ingham     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
4362837b766SJim Ingham     m_option_group.Finalize();
4376d56d2ceSJim Ingham   }
4386d56d2ceSJim Ingham 
439c8ecc2a9SEugene Zelenko   ~CommandObjectFrameVariable() override = default;
4406d56d2ceSJim Ingham 
GetOptions()441b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
442f21feadcSGreg Clayton 
443ae34ed2cSRaphael Isemann   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)444ae34ed2cSRaphael Isemann   HandleArgumentCompletion(CompletionRequest &request,
4452443bbd4SRaphael Isemann                            OptionElementVector &opt_element_vector) override {
446f21feadcSGreg Clayton     // Arguments are the standard source file completer.
447b9c1b51eSKate Stone     CommandCompletions::InvokeCommonCompletionCallbacks(
448b9c1b51eSKate Stone         GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion,
449a2e76c0bSRaphael Isemann         request, nullptr);
450f21feadcSGreg Clayton   }
4516d56d2ceSJim Ingham 
4525a988416SJim Ingham protected:
GetScopeString(VariableSP var_sp)45373418dfeSEnrico Granata   llvm::StringRef GetScopeString(VariableSP var_sp) {
45473418dfeSEnrico Granata     if (!var_sp)
455bbea3610SRaphael Isemann       return llvm::StringRef();
45673418dfeSEnrico Granata 
45773418dfeSEnrico Granata     switch (var_sp->GetScope()) {
45873418dfeSEnrico Granata     case eValueTypeVariableGlobal:
45973418dfeSEnrico Granata       return "GLOBAL: ";
46073418dfeSEnrico Granata     case eValueTypeVariableStatic:
46173418dfeSEnrico Granata       return "STATIC: ";
46273418dfeSEnrico Granata     case eValueTypeVariableArgument:
46373418dfeSEnrico Granata       return "ARG: ";
46473418dfeSEnrico Granata     case eValueTypeVariableLocal:
46573418dfeSEnrico Granata       return "LOCAL: ";
46673418dfeSEnrico Granata     case eValueTypeVariableThreadLocal:
46773418dfeSEnrico Granata       return "THREAD: ";
46873418dfeSEnrico Granata     default:
46973418dfeSEnrico Granata       break;
47073418dfeSEnrico Granata     }
47173418dfeSEnrico Granata 
472bbea3610SRaphael Isemann     return llvm::StringRef();
47373418dfeSEnrico Granata   }
47473418dfeSEnrico Granata 
DoExecute(Args & command,CommandReturnObject & result)475b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
47605097246SAdrian Prantl     // No need to check "frame" for validity as eCommandRequiresFrame ensures
47705097246SAdrian Prantl     // it is valid
478b57e4a1bSJason Molenda     StackFrame *frame = m_exe_ctx.GetFramePtr();
4791e49e5e7SJohnny Chen 
480a134cc1bSGreg Clayton     Stream &s = result.GetOutputStream();
4816d56d2ceSJim Ingham 
482b9c1b51eSKate Stone     // Be careful about the stack frame, if any summary formatter runs code, it
48305097246SAdrian Prantl     // might clear the StackFrameList for the thread.  So hold onto a shared
48405097246SAdrian Prantl     // pointer to the frame so it stays alive.
485650543f9SJim Ingham 
486b9c1b51eSKate Stone     VariableList *variable_list =
487b9c1b51eSKate Stone         frame->GetVariableList(m_option_variable.show_globals);
488a134cc1bSGreg Clayton 
4896d56d2ceSJim Ingham     VariableSP var_sp;
4906d56d2ceSJim Ingham     ValueObjectSP valobj_sp;
49178a685aaSJim Ingham 
492061858ceSEnrico Granata     TypeSummaryImplSP summary_format_sp;
49317b11749SEnrico Granata     if (!m_option_variable.summary.IsCurrentValueEmpty())
494b9c1b51eSKate Stone       DataVisualization::NamedSummaryFormats::GetSummaryFormat(
495b9c1b51eSKate Stone           ConstString(m_option_variable.summary.GetCurrentValue()),
496b9c1b51eSKate Stone           summary_format_sp);
49717b11749SEnrico Granata     else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
498796ac80bSJonas Devlieghere       summary_format_sp = std::make_shared<StringSummaryFormat>(
499b9c1b51eSKate Stone           TypeSummaryImpl::Flags(),
500796ac80bSJonas Devlieghere           m_option_variable.summary_string.GetCurrentValue());
501f9fa6ee5SEnrico Granata 
502b9c1b51eSKate Stone     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
503b9c1b51eSKate Stone         eLanguageRuntimeDescriptionDisplayVerbosityFull, eFormatDefault,
504b9c1b51eSKate Stone         summary_format_sp));
505379447a7SEnrico Granata 
506b9c1b51eSKate Stone     const SymbolContext &sym_ctx =
507b9c1b51eSKate Stone         frame->GetSymbolContext(eSymbolContextFunction);
5086754e04fSEnrico Granata     if (sym_ctx.function && sym_ctx.function->IsTopLevelFunction())
5096754e04fSEnrico Granata       m_option_variable.show_globals = true;
5106754e04fSEnrico Granata 
511b9c1b51eSKate Stone     if (variable_list) {
5121deb7962SGreg Clayton       const Format format = m_option_format.GetFormat();
5130c489f58SEnrico Granata       options.SetFormat(format);
5141deb7962SGreg Clayton 
51511eb9c64SZachary Turner       if (!command.empty()) {
51646747022SGreg Clayton         VariableList regex_var_list;
51746747022SGreg Clayton 
51805097246SAdrian Prantl         // If we have any args to the variable command, we will make variable
51905097246SAdrian Prantl         // objects from them...
520f965cc86SZachary Turner         for (auto &entry : command) {
521b9c1b51eSKate Stone           if (m_option_variable.use_regex) {
522c7bece56SGreg Clayton             const size_t regex_start_index = regex_var_list.GetSize();
5230d9a201eSRaphael Isemann             llvm::StringRef name_str = entry.ref();
52495eae423SZachary Turner             RegularExpression regex(name_str);
525f9d90bc5SJan Kratochvil             if (regex.IsValid()) {
52646747022SGreg Clayton               size_t num_matches = 0;
527b9c1b51eSKate Stone               const size_t num_new_regex_vars =
528b9c1b51eSKate Stone                   variable_list->AppendVariablesIfUnique(regex, regex_var_list,
52978a685aaSJim Ingham                                                          num_matches);
530b9c1b51eSKate Stone               if (num_new_regex_vars > 0) {
531b9c1b51eSKate Stone                 for (size_t regex_idx = regex_start_index,
532b9c1b51eSKate Stone                             end_index = regex_var_list.GetSize();
533b9c1b51eSKate Stone                      regex_idx < end_index; ++regex_idx) {
53446747022SGreg Clayton                   var_sp = regex_var_list.GetVariableAtIndex(regex_idx);
535b9c1b51eSKate Stone                   if (var_sp) {
536b9c1b51eSKate Stone                     valobj_sp = frame->GetValueObjectForFrameVariable(
537b9c1b51eSKate Stone                         var_sp, m_varobj_options.use_dynamic);
538b9c1b51eSKate Stone                     if (valobj_sp) {
53973418dfeSEnrico Granata                       std::string scope_string;
54073418dfeSEnrico Granata                       if (m_option_variable.show_scope)
54173418dfeSEnrico Granata                         scope_string = GetScopeString(var_sp).str();
54273418dfeSEnrico Granata 
54373418dfeSEnrico Granata                       if (!scope_string.empty())
544771ef6d4SMalcolm Parsons                         s.PutCString(scope_string);
54573418dfeSEnrico Granata 
546b9c1b51eSKate Stone                       if (m_option_variable.show_decl &&
547b9c1b51eSKate Stone                           var_sp->GetDeclaration().GetFile()) {
54845ba8543SGreg Clayton                         bool show_fullpaths = false;
54945ba8543SGreg Clayton                         bool show_module = true;
550b9c1b51eSKate Stone                         if (var_sp->DumpDeclaration(&s, show_fullpaths,
551b9c1b51eSKate Stone                                                     show_module))
55246747022SGreg Clayton                           s.PutCString(": ");
55346747022SGreg Clayton                       }
5544d93b8cdSEnrico Granata                       valobj_sp->Dump(result.GetOutputStream(), options);
55546747022SGreg Clayton                     }
55646747022SGreg Clayton                   }
55746747022SGreg Clayton                 }
558b9c1b51eSKate Stone               } else if (num_matches == 0) {
559696f9706SDave Lee                 result.AppendErrorWithFormat(
560696f9706SDave Lee                     "no variables matched the regular expression '%s'.",
561f965cc86SZachary Turner                     entry.c_str());
56246747022SGreg Clayton               }
563b9c1b51eSKate Stone             } else {
5643af3f1e8SJonas Devlieghere               if (llvm::Error err = regex.GetError())
565696f9706SDave Lee                 result.AppendError(llvm::toString(std::move(err)));
56646747022SGreg Clayton               else
567696f9706SDave Lee                 result.AppendErrorWithFormat(
568696f9706SDave Lee                     "unknown regex error when compiling '%s'", entry.c_str());
56946747022SGreg Clayton             }
570b9c1b51eSKate Stone           } else // No regex, either exact variable names or variable
571b9c1b51eSKate Stone                  // expressions.
57246747022SGreg Clayton           {
57397206d57SZachary Turner             Status error;
574b9c1b51eSKate Stone             uint32_t expr_path_options =
575b9c1b51eSKate Stone                 StackFrame::eExpressionPathOptionCheckPtrVsMember |
57646252398SEnrico Granata                 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess |
57746252398SEnrico Granata                 StackFrame::eExpressionPathOptionsInspectAnonymousUnions;
5782837b766SJim Ingham             lldb::VariableSP var_sp;
579b9c1b51eSKate Stone             valobj_sp = frame->GetValueForVariableExpressionPath(
5800d9a201eSRaphael Isemann                 entry.ref(), m_varobj_options.use_dynamic, expr_path_options,
581b9c1b51eSKate Stone                 var_sp, error);
582b9c1b51eSKate Stone             if (valobj_sp) {
58373418dfeSEnrico Granata               std::string scope_string;
58473418dfeSEnrico Granata               if (m_option_variable.show_scope)
58573418dfeSEnrico Granata                 scope_string = GetScopeString(var_sp).str();
58673418dfeSEnrico Granata 
58773418dfeSEnrico Granata               if (!scope_string.empty())
588771ef6d4SMalcolm Parsons                 s.PutCString(scope_string);
589b9c1b51eSKate Stone               if (m_option_variable.show_decl && var_sp &&
590b9c1b51eSKate Stone                   var_sp->GetDeclaration().GetFile()) {
591a134cc1bSGreg Clayton                 var_sp->GetDeclaration().DumpStopContext(&s, false);
592a134cc1bSGreg Clayton                 s.PutCString(": ");
593a134cc1bSGreg Clayton               }
5940c489f58SEnrico Granata 
5950c489f58SEnrico Granata               options.SetFormat(format);
596b9c1b51eSKate Stone               options.SetVariableFormatDisplayLanguage(
597b9c1b51eSKate Stone                   valobj_sp->GetPreferredDisplayLanguage());
598887062aeSJohnny Chen 
599887062aeSJohnny Chen               Stream &output_stream = result.GetOutputStream();
600f965cc86SZachary Turner               options.SetRootValueObjectName(
601f965cc86SZachary Turner                   valobj_sp->GetParent() ? entry.c_str() : nullptr);
6024d93b8cdSEnrico Granata               valobj_sp->Dump(output_stream, options);
603b9c1b51eSKate Stone             } else {
604696f9706SDave Lee               if (auto error_cstr = error.AsCString(nullptr))
605696f9706SDave Lee                 result.AppendError(error_cstr);
60654979cddSGreg Clayton               else
607696f9706SDave Lee                 result.AppendErrorWithFormat(
608696f9706SDave Lee                     "unable to find any variable expression path that matches "
609696f9706SDave Lee                     "'%s'.",
610f965cc86SZachary Turner                     entry.c_str());
6116d56d2ceSJim Ingham             }
6126d56d2ceSJim Ingham           }
6136d56d2ceSJim Ingham         }
614b9c1b51eSKate Stone       } else // No command arg specified.  Use variable_list, instead.
6156d56d2ceSJim Ingham       {
616c7bece56SGreg Clayton         const size_t num_variables = variable_list->GetSize();
617b9c1b51eSKate Stone         if (num_variables > 0) {
618b9c1b51eSKate Stone           for (size_t i = 0; i < num_variables; i++) {
6191a65ae11SGreg Clayton             var_sp = variable_list->GetVariableAtIndex(i);
620f955efc0SSylvestre Ledru             switch (var_sp->GetScope()) {
621eb236735SJim Ingham             case eValueTypeVariableGlobal:
622eb236735SJim Ingham               if (!m_option_variable.show_globals)
623eb236735SJim Ingham                 continue;
624eb236735SJim Ingham               break;
625eb236735SJim Ingham             case eValueTypeVariableStatic:
626eb236735SJim Ingham               if (!m_option_variable.show_globals)
627eb236735SJim Ingham                 continue;
628eb236735SJim Ingham               break;
629eb236735SJim Ingham             case eValueTypeVariableArgument:
630eb236735SJim Ingham               if (!m_option_variable.show_args)
631eb236735SJim Ingham                 continue;
632eb236735SJim Ingham               break;
633eb236735SJim Ingham             case eValueTypeVariableLocal:
634eb236735SJim Ingham               if (!m_option_variable.show_locals)
635eb236735SJim Ingham                 continue;
636eb236735SJim Ingham               break;
637eb236735SJim Ingham             default:
638eb236735SJim Ingham               continue;
639eb236735SJim Ingham               break;
640eb236735SJim Ingham             }
641560558ebSEnrico Granata             std::string scope_string;
642eb236735SJim Ingham             if (m_option_variable.show_scope)
64373418dfeSEnrico Granata               scope_string = GetScopeString(var_sp).str();
6446d56d2ceSJim Ingham 
64505097246SAdrian Prantl             // Use the variable object code to make sure we are using the same
64605097246SAdrian Prantl             // APIs as the public API will be using...
647b9c1b51eSKate Stone             valobj_sp = frame->GetValueObjectForFrameVariable(
648b9c1b51eSKate Stone                 var_sp, m_varobj_options.use_dynamic);
649b9c1b51eSKate Stone             if (valobj_sp) {
65005097246SAdrian Prantl               // When dumping all variables, don't print any variables that are
65105097246SAdrian Prantl               // not in scope to avoid extra unneeded output
652b9c1b51eSKate Stone               if (valobj_sp->IsInScope()) {
653b9c1b51eSKate Stone                 if (!valobj_sp->GetTargetSP()
654b9c1b51eSKate Stone                          ->GetDisplayRuntimeSupportValues() &&
655c8ecc2a9SEugene Zelenko                     valobj_sp->IsRuntimeSupportValue())
656560558ebSEnrico Granata                   continue;
657560558ebSEnrico Granata 
658560558ebSEnrico Granata                 if (!scope_string.empty())
659771ef6d4SMalcolm Parsons                   s.PutCString(scope_string);
660560558ebSEnrico Granata 
661b9c1b51eSKate Stone                 if (m_option_variable.show_decl &&
662b9c1b51eSKate Stone                     var_sp->GetDeclaration().GetFile()) {
663a134cc1bSGreg Clayton                   var_sp->GetDeclaration().DumpStopContext(&s, false);
664a134cc1bSGreg Clayton                   s.PutCString(": ");
665a134cc1bSGreg Clayton                 }
6660c489f58SEnrico Granata 
6670c489f58SEnrico Granata                 options.SetFormat(format);
668b9c1b51eSKate Stone                 options.SetVariableFormatDisplayLanguage(
669b9c1b51eSKate Stone                     valobj_sp->GetPreferredDisplayLanguage());
670f965cc86SZachary Turner                 options.SetRootValueObjectName(
671f965cc86SZachary Turner                     var_sp ? var_sp->GetName().AsCString() : nullptr);
6724d93b8cdSEnrico Granata                 valobj_sp->Dump(result.GetOutputStream(), options);
673a134cc1bSGreg Clayton               }
674a134cc1bSGreg Clayton             }
6756d56d2ceSJim Ingham           }
6766d56d2ceSJim Ingham         }
6776d56d2ceSJim Ingham       }
678696f9706SDave Lee       if (result.GetStatus() != eReturnStatusFailed)
6796d56d2ceSJim Ingham         result.SetStatus(eReturnStatusSuccessFinishResult);
6806d56d2ceSJim Ingham     }
68161a80ba6SEnrico Granata 
68241ae8e74SKuba Mracek     if (m_option_variable.show_recognized_args) {
68341ae8e74SKuba Mracek       auto recognized_frame = frame->GetRecognizedFrame();
68441ae8e74SKuba Mracek       if (recognized_frame) {
68541ae8e74SKuba Mracek         ValueObjectListSP recognized_arg_list =
68641ae8e74SKuba Mracek             recognized_frame->GetRecognizedArguments();
68741ae8e74SKuba Mracek         if (recognized_arg_list) {
68841ae8e74SKuba Mracek           for (auto &rec_value_sp : recognized_arg_list->GetObjects()) {
68941ae8e74SKuba Mracek             options.SetFormat(m_option_format.GetFormat());
69041ae8e74SKuba Mracek             options.SetVariableFormatDisplayLanguage(
69141ae8e74SKuba Mracek                 rec_value_sp->GetPreferredDisplayLanguage());
69241ae8e74SKuba Mracek             options.SetRootValueObjectName(rec_value_sp->GetName().AsCString());
69341ae8e74SKuba Mracek             rec_value_sp->Dump(result.GetOutputStream(), options);
69441ae8e74SKuba Mracek           }
69541ae8e74SKuba Mracek         }
69641ae8e74SKuba Mracek       }
69741ae8e74SKuba Mracek     }
69841ae8e74SKuba Mracek 
6992f9fc576SDave Lee     m_interpreter.PrintWarningsIfNecessary(result.GetOutputStream(),
7002f9fc576SDave Lee                                            m_cmd_name);
70161a80ba6SEnrico Granata 
70224fff242SDavide Italiano     // Increment statistics.
70324fff242SDavide Italiano     bool res = result.Succeeded();
704d7b33853SGreg Clayton     TargetStats &target_stats = GetSelectedOrDummyTarget().GetStatistics();
70524fff242SDavide Italiano     if (res)
706d7b33853SGreg Clayton       target_stats.GetFrameVariableStats().NotifySuccess();
70724fff242SDavide Italiano     else
708d7b33853SGreg Clayton       target_stats.GetFrameVariableStats().NotifyFailure();
70924fff242SDavide Italiano     return res;
7106d56d2ceSJim Ingham   }
7116d56d2ceSJim Ingham 
7122837b766SJim Ingham   OptionGroupOptions m_option_group;
713715c2365SGreg Clayton   OptionGroupVariable m_option_variable;
7141deb7962SGreg Clayton   OptionGroupFormat m_option_format;
7152837b766SJim Ingham   OptionGroupValueObjectDisplay m_varobj_options;
7166d56d2ceSJim Ingham };
7176d56d2ceSJim Ingham 
71841ae8e74SKuba Mracek #pragma mark CommandObjectFrameRecognizer
71941ae8e74SKuba Mracek 
720ec67e734SRaphael Isemann #define LLDB_OPTIONS_frame_recognizer_add
721ec67e734SRaphael Isemann #include "CommandOptions.inc"
72241ae8e74SKuba Mracek 
72341ae8e74SKuba Mracek class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
72441ae8e74SKuba Mracek private:
72541ae8e74SKuba Mracek   class CommandOptions : public Options {
72641ae8e74SKuba Mracek   public:
72724f9a2f5SShafik Yaghmour     CommandOptions() = default;
72841ae8e74SKuba Mracek     ~CommandOptions() override = default;
72941ae8e74SKuba Mracek 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)73041ae8e74SKuba Mracek     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
73141ae8e74SKuba Mracek                           ExecutionContext *execution_context) override {
73241ae8e74SKuba Mracek       Status error;
73341ae8e74SKuba Mracek       const int short_option = m_getopt_table[option_idx].val;
73441ae8e74SKuba Mracek 
73541ae8e74SKuba Mracek       switch (short_option) {
73654c496daSRoman Podoliaka       case 'f': {
73754c496daSRoman Podoliaka         bool value, success;
73854c496daSRoman Podoliaka         value = OptionArgParser::ToBoolean(option_arg, true, &success);
73954c496daSRoman Podoliaka         if (success) {
74054c496daSRoman Podoliaka           m_first_instruction_only = value;
74154c496daSRoman Podoliaka         } else {
74254c496daSRoman Podoliaka           error.SetErrorStringWithFormat(
74354c496daSRoman Podoliaka               "invalid boolean value '%s' passed for -f option",
74454c496daSRoman Podoliaka               option_arg.str().c_str());
74554c496daSRoman Podoliaka         }
74654c496daSRoman Podoliaka       } break;
74741ae8e74SKuba Mracek       case 'l':
74841ae8e74SKuba Mracek         m_class_name = std::string(option_arg);
74941ae8e74SKuba Mracek         break;
75041ae8e74SKuba Mracek       case 's':
75141ae8e74SKuba Mracek         m_module = std::string(option_arg);
75241ae8e74SKuba Mracek         break;
75341ae8e74SKuba Mracek       case 'n':
754db31e2e1SMed Ismail Bennani         m_symbols.push_back(std::string(option_arg));
75541ae8e74SKuba Mracek         break;
75641ae8e74SKuba Mracek       case 'x':
75741ae8e74SKuba Mracek         m_regex = true;
75841ae8e74SKuba Mracek         break;
75941ae8e74SKuba Mracek       default:
76036162014SRaphael Isemann         llvm_unreachable("Unimplemented option");
76141ae8e74SKuba Mracek       }
76241ae8e74SKuba Mracek 
76341ae8e74SKuba Mracek       return error;
76441ae8e74SKuba Mracek     }
76541ae8e74SKuba Mracek 
OptionParsingStarting(ExecutionContext * execution_context)76641ae8e74SKuba Mracek     void OptionParsingStarting(ExecutionContext *execution_context) override {
76741ae8e74SKuba Mracek       m_module = "";
768db31e2e1SMed Ismail Bennani       m_symbols.clear();
76941ae8e74SKuba Mracek       m_class_name = "";
77041ae8e74SKuba Mracek       m_regex = false;
77154c496daSRoman Podoliaka       m_first_instruction_only = true;
77241ae8e74SKuba Mracek     }
77341ae8e74SKuba Mracek 
GetDefinitions()77441ae8e74SKuba Mracek     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
77541ae8e74SKuba Mracek       return llvm::makeArrayRef(g_frame_recognizer_add_options);
77641ae8e74SKuba Mracek     }
77741ae8e74SKuba Mracek 
77841ae8e74SKuba Mracek     // Instance variables to hold the values for command options.
77941ae8e74SKuba Mracek     std::string m_class_name;
78041ae8e74SKuba Mracek     std::string m_module;
781db31e2e1SMed Ismail Bennani     std::vector<std::string> m_symbols;
78241ae8e74SKuba Mracek     bool m_regex;
78354c496daSRoman Podoliaka     bool m_first_instruction_only;
78441ae8e74SKuba Mracek   };
78541ae8e74SKuba Mracek 
78641ae8e74SKuba Mracek   CommandOptions m_options;
78741ae8e74SKuba Mracek 
GetOptions()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:
CommandObjectFrameRecognizerAdd(CommandInterpreter & interpreter)79441ae8e74SKuba Mracek   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
79541ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer add",
796abb0ed44SKazu Hirata                             "Add a new frame recognizer.", nullptr) {
79741ae8e74SKuba Mracek     SetHelpLong(R"(
79841ae8e74SKuba Mracek Frame recognizers allow for retrieving information about special frames based on
79941ae8e74SKuba Mracek ABI, arguments or other special properties of that frame, even without source
80041ae8e74SKuba Mracek code or debug info. Currently, one use case is to extract function arguments
80141ae8e74SKuba Mracek that would otherwise be unaccesible, or augment existing arguments.
80241ae8e74SKuba Mracek 
80341ae8e74SKuba Mracek Adding a custom frame recognizer is possible by implementing a Python class
80441ae8e74SKuba Mracek and using the 'frame recognizer add' command. The Python class should have a
80541ae8e74SKuba Mracek 'get_recognized_arguments' method and it will receive an argument of type
80641ae8e74SKuba Mracek lldb.SBFrame representing the current frame that we are trying to recognize.
80741ae8e74SKuba Mracek The method should return a (possibly empty) list of lldb.SBValue objects that
80841ae8e74SKuba Mracek represent the recognized arguments.
80941ae8e74SKuba Mracek 
81041ae8e74SKuba Mracek An example of a recognizer that retrieves the file descriptor values from libc
81141ae8e74SKuba Mracek functions 'read', 'write' and 'close' follows:
81241ae8e74SKuba Mracek 
81341ae8e74SKuba Mracek   class LibcFdRecognizer(object):
81441ae8e74SKuba Mracek     def get_recognized_arguments(self, frame):
81541ae8e74SKuba Mracek       if frame.name in ["read", "write", "close"]:
81641ae8e74SKuba Mracek         fd = frame.EvaluateExpression("$arg1").unsigned
81741ae8e74SKuba Mracek         value = lldb.target.CreateValueFromExpression("fd", "(int)%d" % fd)
81841ae8e74SKuba Mracek         return [value]
81941ae8e74SKuba Mracek       return []
82041ae8e74SKuba Mracek 
82141ae8e74SKuba Mracek The file containing this implementation can be imported via 'command script
82241ae8e74SKuba Mracek import' and then we can register this recognizer with 'frame recognizer add'.
82341ae8e74SKuba Mracek It's important to restrict the recognizer to the libc library (which is
82441ae8e74SKuba Mracek libsystem_kernel.dylib on macOS) to avoid matching functions with the same name
82541ae8e74SKuba Mracek in other modules:
82641ae8e74SKuba Mracek 
82741ae8e74SKuba Mracek (lldb) command script import .../fd_recognizer.py
82841ae8e74SKuba Mracek (lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
82941ae8e74SKuba Mracek 
83041ae8e74SKuba Mracek When the program is stopped at the beginning of the 'read' function in libc, we
83141ae8e74SKuba Mracek can view the recognizer arguments in 'frame variable':
83241ae8e74SKuba Mracek 
83341ae8e74SKuba Mracek (lldb) b read
83441ae8e74SKuba Mracek (lldb) r
83541ae8e74SKuba Mracek Process 1234 stopped
83641ae8e74SKuba Mracek * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
83741ae8e74SKuba Mracek     frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
83841ae8e74SKuba Mracek (lldb) frame variable
83941ae8e74SKuba Mracek (int) fd = 3
84041ae8e74SKuba Mracek 
84141ae8e74SKuba Mracek     )");
84241ae8e74SKuba Mracek   }
84341ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerAdd() override = default;
84441ae8e74SKuba Mracek };
84541ae8e74SKuba Mracek 
DoExecute(Args & command,CommandReturnObject & result)84641ae8e74SKuba Mracek bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
84741ae8e74SKuba Mracek                                                 CommandReturnObject &result) {
8484e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
84941ae8e74SKuba Mracek   if (m_options.m_class_name.empty()) {
85041ae8e74SKuba Mracek     result.AppendErrorWithFormat(
85141ae8e74SKuba Mracek         "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str());
85241ae8e74SKuba Mracek     return false;
85341ae8e74SKuba Mracek   }
85441ae8e74SKuba Mracek 
85541ae8e74SKuba Mracek   if (m_options.m_module.empty()) {
85641ae8e74SKuba Mracek     result.AppendErrorWithFormat("%s needs a module name (-s argument).\n",
85741ae8e74SKuba Mracek                                  m_cmd_name.c_str());
85841ae8e74SKuba Mracek     return false;
85941ae8e74SKuba Mracek   }
86041ae8e74SKuba Mracek 
861db31e2e1SMed Ismail Bennani   if (m_options.m_symbols.empty()) {
862db31e2e1SMed Ismail Bennani     result.AppendErrorWithFormat(
863db31e2e1SMed Ismail Bennani         "%s needs at least one symbol name (-n argument).\n",
864db31e2e1SMed Ismail Bennani         m_cmd_name.c_str());
865db31e2e1SMed Ismail Bennani     return false;
866db31e2e1SMed Ismail Bennani   }
867db31e2e1SMed Ismail Bennani 
868db31e2e1SMed Ismail Bennani   if (m_options.m_regex && m_options.m_symbols.size() > 1) {
869db31e2e1SMed Ismail Bennani     result.AppendErrorWithFormat(
870db31e2e1SMed Ismail Bennani         "%s needs only one symbol regular expression (-n argument).\n",
87141ae8e74SKuba Mracek         m_cmd_name.c_str());
87241ae8e74SKuba Mracek     return false;
87341ae8e74SKuba Mracek   }
87441ae8e74SKuba Mracek 
8752b29b432SJonas Devlieghere   ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
87641ae8e74SKuba Mracek 
87741ae8e74SKuba Mracek   if (interpreter &&
87841ae8e74SKuba Mracek       !interpreter->CheckObjectExists(m_options.m_class_name.c_str())) {
879a925974bSAdrian Prantl     result.AppendWarning("The provided class does not exist - please define it "
88041ae8e74SKuba Mracek                          "before attempting to use this frame recognizer");
88141ae8e74SKuba Mracek   }
88241ae8e74SKuba Mracek 
88341ae8e74SKuba Mracek   StackFrameRecognizerSP recognizer_sp =
88441ae8e74SKuba Mracek       StackFrameRecognizerSP(new ScriptedStackFrameRecognizer(
88541ae8e74SKuba Mracek           interpreter, m_options.m_class_name.c_str()));
88641ae8e74SKuba Mracek   if (m_options.m_regex) {
88741ae8e74SKuba Mracek     auto module =
88841ae8e74SKuba Mracek         RegularExpressionSP(new RegularExpression(m_options.m_module));
88941ae8e74SKuba Mracek     auto func =
890db31e2e1SMed Ismail Bennani         RegularExpressionSP(new RegularExpression(m_options.m_symbols.front()));
8911b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
89254c496daSRoman Podoliaka         recognizer_sp, module, func, m_options.m_first_instruction_only);
89341ae8e74SKuba Mracek   } else {
89441ae8e74SKuba Mracek     auto module = ConstString(m_options.m_module);
895db31e2e1SMed Ismail Bennani     std::vector<ConstString> symbols(m_options.m_symbols.begin(),
896db31e2e1SMed Ismail Bennani                                      m_options.m_symbols.end());
8971b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer(
89854c496daSRoman Podoliaka         recognizer_sp, module, symbols, m_options.m_first_instruction_only);
89941ae8e74SKuba Mracek   }
900f80d2655SKuba Mracek #endif
90141ae8e74SKuba Mracek 
90241ae8e74SKuba Mracek   result.SetStatus(eReturnStatusSuccessFinishNoResult);
90341ae8e74SKuba Mracek   return result.Succeeded();
90441ae8e74SKuba Mracek }
90541ae8e74SKuba Mracek 
90641ae8e74SKuba Mracek class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
90741ae8e74SKuba Mracek public:
CommandObjectFrameRecognizerClear(CommandInterpreter & interpreter)90841ae8e74SKuba Mracek   CommandObjectFrameRecognizerClear(CommandInterpreter &interpreter)
90941ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer clear",
91041ae8e74SKuba Mracek                             "Delete all frame recognizers.", nullptr) {}
91141ae8e74SKuba Mracek 
91241ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerClear() override = default;
91341ae8e74SKuba Mracek 
91441ae8e74SKuba Mracek protected:
DoExecute(Args & command,CommandReturnObject & result)91541ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
9161b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget()
9171b7c9eaeSRaphael Isemann         .GetFrameRecognizerManager()
9181b7c9eaeSRaphael Isemann         .RemoveAllRecognizers();
91941ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
92041ae8e74SKuba Mracek     return result.Succeeded();
92141ae8e74SKuba Mracek   }
92241ae8e74SKuba Mracek };
92341ae8e74SKuba Mracek 
92441ae8e74SKuba Mracek class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
92541ae8e74SKuba Mracek public:
CommandObjectFrameRecognizerDelete(CommandInterpreter & interpreter)92641ae8e74SKuba Mracek   CommandObjectFrameRecognizerDelete(CommandInterpreter &interpreter)
92741ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer delete",
928c1b07d61SJim Ingham                             "Delete an existing frame recognizer by id.",
929c1b07d61SJim Ingham                             nullptr) {
930c1b07d61SJim Ingham     CommandArgumentData thread_arg{eArgTypeRecognizerID, eArgRepeatPlain};
931c1b07d61SJim Ingham     m_arguments.push_back({thread_arg});
932c1b07d61SJim Ingham   }
93341ae8e74SKuba Mracek 
93441ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerDelete() override = default;
93541ae8e74SKuba Mracek 
936c37d25f0SGongyu Deng   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)937c37d25f0SGongyu Deng   HandleArgumentCompletion(CompletionRequest &request,
938c37d25f0SGongyu Deng                            OptionElementVector &opt_element_vector) override {
939c37d25f0SGongyu Deng     if (request.GetCursorIndex() != 0)
940c37d25f0SGongyu Deng       return;
941c37d25f0SGongyu Deng 
9421b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
943c37d25f0SGongyu Deng         [&request](uint32_t rid, std::string rname, std::string module,
944c37d25f0SGongyu Deng                    llvm::ArrayRef<lldb_private::ConstString> symbols,
945c37d25f0SGongyu Deng                    bool regexp) {
946c37d25f0SGongyu Deng           StreamString strm;
947c37d25f0SGongyu Deng           if (rname.empty())
948c37d25f0SGongyu Deng             rname = "(internal)";
949c37d25f0SGongyu Deng 
950c37d25f0SGongyu Deng           strm << rname;
951c37d25f0SGongyu Deng           if (!module.empty())
952c37d25f0SGongyu Deng             strm << ", module " << module;
953c37d25f0SGongyu Deng           if (!symbols.empty())
954c37d25f0SGongyu Deng             for (auto &symbol : symbols)
955c37d25f0SGongyu Deng               strm << ", symbol " << symbol;
956c37d25f0SGongyu Deng           if (regexp)
957c37d25f0SGongyu Deng             strm << " (regexp)";
958c37d25f0SGongyu Deng 
959c37d25f0SGongyu Deng           request.TryCompleteCurrentArg(std::to_string(rid), strm.GetString());
960c37d25f0SGongyu Deng         });
961c37d25f0SGongyu Deng   }
962c37d25f0SGongyu Deng 
96341ae8e74SKuba Mracek protected:
DoExecute(Args & command,CommandReturnObject & result)96441ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
96541ae8e74SKuba Mracek     if (command.GetArgumentCount() == 0) {
96641ae8e74SKuba Mracek       if (!m_interpreter.Confirm(
96741ae8e74SKuba Mracek               "About to delete all frame recognizers, do you want to do that?",
96841ae8e74SKuba Mracek               true)) {
96941ae8e74SKuba Mracek         result.AppendMessage("Operation cancelled...");
97041ae8e74SKuba Mracek         return false;
97141ae8e74SKuba Mracek       }
97241ae8e74SKuba Mracek 
9731b7c9eaeSRaphael Isemann       GetSelectedOrDummyTarget()
9741b7c9eaeSRaphael Isemann           .GetFrameRecognizerManager()
9751b7c9eaeSRaphael Isemann           .RemoveAllRecognizers();
97641ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
97741ae8e74SKuba Mracek       return result.Succeeded();
97841ae8e74SKuba Mracek     }
97941ae8e74SKuba Mracek 
98041ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
98141ae8e74SKuba Mracek       result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n",
98241ae8e74SKuba Mracek                                    m_cmd_name.c_str());
98341ae8e74SKuba Mracek       return false;
98441ae8e74SKuba Mracek     }
98541ae8e74SKuba Mracek 
9869010cef2SRaphael Isemann     uint32_t recognizer_id;
9879010cef2SRaphael Isemann     if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) {
9889010cef2SRaphael Isemann       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
9899010cef2SRaphael Isemann                                    command.GetArgumentAtIndex(0));
9909010cef2SRaphael Isemann       return false;
9919010cef2SRaphael Isemann     }
99241ae8e74SKuba Mracek 
9935477fbc2SRaphael Isemann     if (!GetSelectedOrDummyTarget()
9941b7c9eaeSRaphael Isemann              .GetFrameRecognizerManager()
9955477fbc2SRaphael Isemann              .RemoveRecognizerWithID(recognizer_id)) {
9965477fbc2SRaphael Isemann       result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n",
9975477fbc2SRaphael Isemann                                    command.GetArgumentAtIndex(0));
9985477fbc2SRaphael Isemann       return false;
9995477fbc2SRaphael Isemann     }
100041ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
100141ae8e74SKuba Mracek     return result.Succeeded();
100241ae8e74SKuba Mracek   }
100341ae8e74SKuba Mracek };
100441ae8e74SKuba Mracek 
100541ae8e74SKuba Mracek class CommandObjectFrameRecognizerList : public CommandObjectParsed {
100641ae8e74SKuba Mracek public:
CommandObjectFrameRecognizerList(CommandInterpreter & interpreter)100741ae8e74SKuba Mracek   CommandObjectFrameRecognizerList(CommandInterpreter &interpreter)
100841ae8e74SKuba Mracek       : CommandObjectParsed(interpreter, "frame recognizer list",
100941ae8e74SKuba Mracek                             "Show a list of active frame recognizers.",
101041ae8e74SKuba Mracek                             nullptr) {}
101141ae8e74SKuba Mracek 
101241ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerList() override = default;
101341ae8e74SKuba Mracek 
101441ae8e74SKuba Mracek protected:
DoExecute(Args & command,CommandReturnObject & result)101541ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
101641ae8e74SKuba Mracek     bool any_printed = false;
10171b7c9eaeSRaphael Isemann     GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach(
1018db31e2e1SMed Ismail Bennani         [&result, &any_printed](
1019db31e2e1SMed Ismail Bennani             uint32_t recognizer_id, std::string name, std::string module,
1020db31e2e1SMed Ismail Bennani             llvm::ArrayRef<ConstString> symbols, bool regexp) {
1021cb0c4ee3SMed Ismail Bennani           Stream &stream = result.GetOutputStream();
1022cb0c4ee3SMed Ismail Bennani 
1023cb0c4ee3SMed Ismail Bennani           if (name.empty())
1024a925974bSAdrian Prantl             name = "(internal)";
1025cb0c4ee3SMed Ismail Bennani 
1026cb0c4ee3SMed Ismail Bennani           stream << std::to_string(recognizer_id) << ": " << name;
1027cb0c4ee3SMed Ismail Bennani           if (!module.empty())
1028cb0c4ee3SMed Ismail Bennani             stream << ", module " << module;
1029db31e2e1SMed Ismail Bennani           if (!symbols.empty())
1030db31e2e1SMed Ismail Bennani             for (auto &symbol : symbols)
1031db31e2e1SMed Ismail Bennani               stream << ", symbol " << symbol;
1032cb0c4ee3SMed Ismail Bennani           if (regexp)
1033cb0c4ee3SMed Ismail Bennani             stream << " (regexp)";
1034cb0c4ee3SMed Ismail Bennani 
1035cb0c4ee3SMed Ismail Bennani           stream.EOL();
1036cb0c4ee3SMed Ismail Bennani           stream.Flush();
1037cb0c4ee3SMed Ismail Bennani 
103841ae8e74SKuba Mracek           any_printed = true;
103941ae8e74SKuba Mracek         });
104041ae8e74SKuba Mracek 
104141ae8e74SKuba Mracek     if (any_printed)
104241ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishResult);
104341ae8e74SKuba Mracek     else {
104441ae8e74SKuba Mracek       result.GetOutputStream().PutCString("no matching results found.\n");
104541ae8e74SKuba Mracek       result.SetStatus(eReturnStatusSuccessFinishNoResult);
104641ae8e74SKuba Mracek     }
104741ae8e74SKuba Mracek     return result.Succeeded();
104841ae8e74SKuba Mracek   }
104941ae8e74SKuba Mracek };
105041ae8e74SKuba Mracek 
105141ae8e74SKuba Mracek class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
105241ae8e74SKuba Mracek public:
CommandObjectFrameRecognizerInfo(CommandInterpreter & interpreter)105341ae8e74SKuba Mracek   CommandObjectFrameRecognizerInfo(CommandInterpreter &interpreter)
105441ae8e74SKuba Mracek       : CommandObjectParsed(
105541ae8e74SKuba Mracek             interpreter, "frame recognizer info",
105641ae8e74SKuba Mracek             "Show which frame recognizer is applied a stack frame (if any).",
105741ae8e74SKuba Mracek             nullptr) {
105841ae8e74SKuba Mracek     CommandArgumentEntry arg;
105941ae8e74SKuba Mracek     CommandArgumentData index_arg;
106041ae8e74SKuba Mracek 
106141ae8e74SKuba Mracek     // Define the first (and only) variant of this arg.
106241ae8e74SKuba Mracek     index_arg.arg_type = eArgTypeFrameIndex;
106341ae8e74SKuba Mracek     index_arg.arg_repetition = eArgRepeatPlain;
106441ae8e74SKuba Mracek 
106541ae8e74SKuba Mracek     // There is only one variant this argument could be; put it into the
106641ae8e74SKuba Mracek     // argument entry.
106741ae8e74SKuba Mracek     arg.push_back(index_arg);
106841ae8e74SKuba Mracek 
106941ae8e74SKuba Mracek     // Push the data for the first argument into the m_arguments vector.
107041ae8e74SKuba Mracek     m_arguments.push_back(arg);
107141ae8e74SKuba Mracek   }
107241ae8e74SKuba Mracek 
107341ae8e74SKuba Mracek   ~CommandObjectFrameRecognizerInfo() override = default;
107441ae8e74SKuba Mracek 
107541ae8e74SKuba Mracek protected:
DoExecute(Args & command,CommandReturnObject & result)107641ae8e74SKuba Mracek   bool DoExecute(Args &command, CommandReturnObject &result) override {
10779010cef2SRaphael Isemann     const char *frame_index_str = command.GetArgumentAtIndex(0);
10789010cef2SRaphael Isemann     uint32_t frame_index;
10799010cef2SRaphael Isemann     if (!llvm::to_integer(frame_index_str, frame_index)) {
10809010cef2SRaphael Isemann       result.AppendErrorWithFormat("'%s' is not a valid frame index.",
10819010cef2SRaphael Isemann                                    frame_index_str);
10829010cef2SRaphael Isemann       return false;
10839010cef2SRaphael Isemann     }
10849010cef2SRaphael Isemann 
108541ae8e74SKuba Mracek     Process *process = m_exe_ctx.GetProcessPtr();
108641ae8e74SKuba Mracek     if (process == nullptr) {
108741ae8e74SKuba Mracek       result.AppendError("no process");
108841ae8e74SKuba Mracek       return false;
108941ae8e74SKuba Mracek     }
109041ae8e74SKuba Mracek     Thread *thread = m_exe_ctx.GetThreadPtr();
109141ae8e74SKuba Mracek     if (thread == nullptr) {
109241ae8e74SKuba Mracek       result.AppendError("no thread");
109341ae8e74SKuba Mracek       return false;
109441ae8e74SKuba Mracek     }
109541ae8e74SKuba Mracek     if (command.GetArgumentCount() != 1) {
109641ae8e74SKuba Mracek       result.AppendErrorWithFormat(
109741ae8e74SKuba Mracek           "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str());
109841ae8e74SKuba Mracek       return false;
109941ae8e74SKuba Mracek     }
110041ae8e74SKuba Mracek 
110141ae8e74SKuba Mracek     StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index);
110241ae8e74SKuba Mracek     if (!frame_sp) {
110341ae8e74SKuba Mracek       result.AppendErrorWithFormat("no frame with index %u", frame_index);
110441ae8e74SKuba Mracek       return false;
110541ae8e74SKuba Mracek     }
110641ae8e74SKuba Mracek 
11071b7c9eaeSRaphael Isemann     auto recognizer = GetSelectedOrDummyTarget()
11081b7c9eaeSRaphael Isemann                           .GetFrameRecognizerManager()
11091b7c9eaeSRaphael Isemann                           .GetRecognizerForFrame(frame_sp);
111041ae8e74SKuba Mracek 
111141ae8e74SKuba Mracek     Stream &output_stream = result.GetOutputStream();
111241ae8e74SKuba Mracek     output_stream.Printf("frame %d ", frame_index);
111341ae8e74SKuba Mracek     if (recognizer) {
111441ae8e74SKuba Mracek       output_stream << "is recognized by ";
111541ae8e74SKuba Mracek       output_stream << recognizer->GetName();
111641ae8e74SKuba Mracek     } else {
111741ae8e74SKuba Mracek       output_stream << "not recognized by any recognizer";
111841ae8e74SKuba Mracek     }
111941ae8e74SKuba Mracek     output_stream.EOL();
112041ae8e74SKuba Mracek     result.SetStatus(eReturnStatusSuccessFinishResult);
112141ae8e74SKuba Mracek     return result.Succeeded();
112241ae8e74SKuba Mracek   }
112341ae8e74SKuba Mracek };
112441ae8e74SKuba Mracek 
112541ae8e74SKuba Mracek class CommandObjectFrameRecognizer : public CommandObjectMultiword {
112641ae8e74SKuba Mracek public:
CommandObjectFrameRecognizer(CommandInterpreter & interpreter)112741ae8e74SKuba Mracek   CommandObjectFrameRecognizer(CommandInterpreter &interpreter)
112841ae8e74SKuba Mracek       : CommandObjectMultiword(
112941ae8e74SKuba Mracek             interpreter, "frame recognizer",
113041ae8e74SKuba Mracek             "Commands for editing and viewing frame recognizers.",
113141ae8e74SKuba Mracek             "frame recognizer [<sub-command-options>] ") {
1132a925974bSAdrian Prantl     LoadSubCommand("add", CommandObjectSP(new CommandObjectFrameRecognizerAdd(
1133a925974bSAdrian Prantl                               interpreter)));
113441ae8e74SKuba Mracek     LoadSubCommand(
113541ae8e74SKuba Mracek         "clear",
113641ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerClear(interpreter)));
113741ae8e74SKuba Mracek     LoadSubCommand(
113841ae8e74SKuba Mracek         "delete",
113941ae8e74SKuba Mracek         CommandObjectSP(new CommandObjectFrameRecognizerDelete(interpreter)));
1140a925974bSAdrian Prantl     LoadSubCommand("list", CommandObjectSP(new CommandObjectFrameRecognizerList(
1141a925974bSAdrian Prantl                                interpreter)));
1142a925974bSAdrian Prantl     LoadSubCommand("info", CommandObjectSP(new CommandObjectFrameRecognizerInfo(
1143a925974bSAdrian Prantl                                interpreter)));
114441ae8e74SKuba Mracek   }
114541ae8e74SKuba Mracek 
114641ae8e74SKuba Mracek   ~CommandObjectFrameRecognizer() override = default;
114741ae8e74SKuba Mracek };
114841ae8e74SKuba Mracek 
114930fdc8d8SChris Lattner #pragma mark CommandObjectMultiwordFrame
115030fdc8d8SChris Lattner 
115130fdc8d8SChris Lattner // CommandObjectMultiwordFrame
115230fdc8d8SChris Lattner 
CommandObjectMultiwordFrame(CommandInterpreter & interpreter)1153b9c1b51eSKate Stone CommandObjectMultiwordFrame::CommandObjectMultiwordFrame(
1154b9c1b51eSKate Stone     CommandInterpreter &interpreter)
1155a925974bSAdrian Prantl     : CommandObjectMultiword(interpreter, "frame",
1156a925974bSAdrian Prantl                              "Commands for selecting and "
1157b9c1b51eSKate Stone                              "examing the current "
1158b9c1b51eSKate Stone                              "thread's stack frames.",
1159b9c1b51eSKate Stone                              "frame <subcommand> [<subcommand-options>]") {
1160b9c1b51eSKate Stone   LoadSubCommand("diagnose",
1161b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameDiagnose(interpreter)));
1162b9c1b51eSKate Stone   LoadSubCommand("info",
1163b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameInfo(interpreter)));
1164b9c1b51eSKate Stone   LoadSubCommand("select",
1165b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameSelect(interpreter)));
1166b9c1b51eSKate Stone   LoadSubCommand("variable",
1167b9c1b51eSKate Stone                  CommandObjectSP(new CommandObjectFrameVariable(interpreter)));
11684e26cf2cSJonas Devlieghere #if LLDB_ENABLE_PYTHON
1169a925974bSAdrian Prantl   LoadSubCommand("recognizer", CommandObjectSP(new CommandObjectFrameRecognizer(
1170a925974bSAdrian Prantl                                    interpreter)));
117141ae8e74SKuba Mracek #endif
117230fdc8d8SChris Lattner }
117330fdc8d8SChris Lattner 
1174c8ecc2a9SEugene Zelenko CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame() = default;
1175