15ffd83dbSDimitry Andric //===-- CommandObjectWatchpointCommand.cpp --------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include <vector>
10*0b57cec5SDimitry Andric 
11*0b57cec5SDimitry Andric #include "CommandObjectWatchpoint.h"
12*0b57cec5SDimitry Andric #include "CommandObjectWatchpointCommand.h"
13*0b57cec5SDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h"
14*0b57cec5SDimitry Andric #include "lldb/Breakpoint/Watchpoint.h"
15*0b57cec5SDimitry Andric #include "lldb/Core/IOHandler.h"
16*0b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h"
17*0b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
18*0b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
19*0b57cec5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
20*0b57cec5SDimitry Andric #include "lldb/Target/Target.h"
21*0b57cec5SDimitry Andric 
22*0b57cec5SDimitry Andric using namespace lldb;
23*0b57cec5SDimitry Andric using namespace lldb_private;
24*0b57cec5SDimitry Andric 
25*0b57cec5SDimitry Andric // FIXME: "script-type" needs to have its contents determined dynamically, so
269dba64beSDimitry Andric // somebody can add a new scripting language to lldb and have it pickable here
279dba64beSDimitry Andric // without having to change this enumeration by hand and rebuild lldb proper.
28*0b57cec5SDimitry Andric static constexpr OptionEnumValueElement g_script_option_enumeration[] = {
299dba64beSDimitry Andric     {
309dba64beSDimitry Andric         eScriptLanguageNone,
319dba64beSDimitry Andric         "command",
329dba64beSDimitry Andric         "Commands are in the lldb command interpreter language",
339dba64beSDimitry Andric     },
349dba64beSDimitry Andric     {
359dba64beSDimitry Andric         eScriptLanguagePython,
369dba64beSDimitry Andric         "python",
379dba64beSDimitry Andric         "Commands are in the Python language.",
389dba64beSDimitry Andric     },
399dba64beSDimitry Andric     {
40480093f4SDimitry Andric         eScriptLanguageLua,
41480093f4SDimitry Andric         "lua",
425ffd83dbSDimitry Andric         "Commands are in the Lua language.",
43480093f4SDimitry Andric     },
44480093f4SDimitry Andric     {
459dba64beSDimitry Andric         eSortOrderByName,
469dba64beSDimitry Andric         "default-script",
479dba64beSDimitry Andric         "Commands are in the default scripting language.",
489dba64beSDimitry Andric     },
499dba64beSDimitry Andric };
50*0b57cec5SDimitry Andric 
51*0b57cec5SDimitry Andric static constexpr OptionEnumValues ScriptOptionEnum() {
52*0b57cec5SDimitry Andric   return OptionEnumValues(g_script_option_enumeration);
53*0b57cec5SDimitry Andric }
54*0b57cec5SDimitry Andric 
55*0b57cec5SDimitry Andric #define LLDB_OPTIONS_watchpoint_command_add
56*0b57cec5SDimitry Andric #include "CommandOptions.inc"
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric class CommandObjectWatchpointCommandAdd : public CommandObjectParsed,
59*0b57cec5SDimitry Andric                                           public IOHandlerDelegateMultiline {
60*0b57cec5SDimitry Andric public:
61*0b57cec5SDimitry Andric   CommandObjectWatchpointCommandAdd(CommandInterpreter &interpreter)
62*0b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "add",
63*0b57cec5SDimitry Andric                             "Add a set of LLDB commands to a watchpoint, to be "
64*0b57cec5SDimitry Andric                             "executed whenever the watchpoint is hit.",
659dba64beSDimitry Andric                             nullptr, eCommandRequiresTarget),
66*0b57cec5SDimitry Andric         IOHandlerDelegateMultiline("DONE",
67*0b57cec5SDimitry Andric                                    IOHandlerDelegate::Completion::LLDBCommand),
68*0b57cec5SDimitry Andric         m_options() {
69*0b57cec5SDimitry Andric     SetHelpLong(
70*0b57cec5SDimitry Andric         R"(
71*0b57cec5SDimitry Andric General information about entering watchpoint commands
72*0b57cec5SDimitry Andric ------------------------------------------------------
73*0b57cec5SDimitry Andric 
74*0b57cec5SDimitry Andric )"
75*0b57cec5SDimitry Andric         "This command will prompt for commands to be executed when the specified \
76*0b57cec5SDimitry Andric watchpoint is hit.  Each command is typed on its own line following the '> ' \
77*0b57cec5SDimitry Andric prompt until 'DONE' is entered."
78*0b57cec5SDimitry Andric         R"(
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric )"
81*0b57cec5SDimitry Andric         "Syntactic errors may not be detected when initially entered, and many \
82*0b57cec5SDimitry Andric malformed commands can silently fail when executed.  If your watchpoint commands \
83*0b57cec5SDimitry Andric do not appear to be executing, double-check the command syntax."
84*0b57cec5SDimitry Andric         R"(
85*0b57cec5SDimitry Andric 
86*0b57cec5SDimitry Andric )"
87*0b57cec5SDimitry Andric         "Note: You may enter any debugger command exactly as you would at the debugger \
88*0b57cec5SDimitry Andric prompt.  There is no limit to the number of commands supplied, but do NOT enter \
89*0b57cec5SDimitry Andric more than one command per line."
90*0b57cec5SDimitry Andric         R"(
91*0b57cec5SDimitry Andric 
92*0b57cec5SDimitry Andric Special information about PYTHON watchpoint commands
93*0b57cec5SDimitry Andric ----------------------------------------------------
94*0b57cec5SDimitry Andric 
95*0b57cec5SDimitry Andric )"
96*0b57cec5SDimitry Andric         "You may enter either one or more lines of Python, including function \
97*0b57cec5SDimitry Andric definitions or calls to functions that will have been imported by the time \
98*0b57cec5SDimitry Andric the code executes.  Single line watchpoint commands will be interpreted 'as is' \
99*0b57cec5SDimitry Andric when the watchpoint is hit.  Multiple lines of Python will be wrapped in a \
100*0b57cec5SDimitry Andric generated function, and a call to the function will be attached to the watchpoint."
101*0b57cec5SDimitry Andric         R"(
102*0b57cec5SDimitry Andric 
103*0b57cec5SDimitry Andric This auto-generated function is passed in three arguments:
104*0b57cec5SDimitry Andric 
105*0b57cec5SDimitry Andric     frame:  an lldb.SBFrame object for the frame which hit the watchpoint.
106*0b57cec5SDimitry Andric 
107*0b57cec5SDimitry Andric     wp:     the watchpoint that was hit.
108*0b57cec5SDimitry Andric 
109*0b57cec5SDimitry Andric )"
110*0b57cec5SDimitry Andric         "When specifying a python function with the --python-function option, you need \
111*0b57cec5SDimitry Andric to supply the function name prepended by the module name:"
112*0b57cec5SDimitry Andric         R"(
113*0b57cec5SDimitry Andric 
114*0b57cec5SDimitry Andric     --python-function myutils.watchpoint_callback
115*0b57cec5SDimitry Andric 
116*0b57cec5SDimitry Andric The function itself must have the following prototype:
117*0b57cec5SDimitry Andric 
118*0b57cec5SDimitry Andric def watchpoint_callback(frame, wp):
119*0b57cec5SDimitry Andric   # Your code goes here
120*0b57cec5SDimitry Andric 
121*0b57cec5SDimitry Andric )"
122*0b57cec5SDimitry Andric         "The arguments are the same as the arguments passed to generated functions as \
123*0b57cec5SDimitry Andric described above.  Note that the global variable 'lldb.frame' will NOT be updated when \
124*0b57cec5SDimitry Andric this function is called, so be sure to use the 'frame' argument. The 'frame' argument \
125*0b57cec5SDimitry Andric can get you to the thread via frame.GetThread(), the thread can get you to the \
126*0b57cec5SDimitry Andric process via thread.GetProcess(), and the process can get you back to the target \
127*0b57cec5SDimitry Andric via process.GetTarget()."
128*0b57cec5SDimitry Andric         R"(
129*0b57cec5SDimitry Andric 
130*0b57cec5SDimitry Andric )"
131*0b57cec5SDimitry Andric         "Important Note: As Python code gets collected into functions, access to global \
132*0b57cec5SDimitry Andric variables requires explicit scoping using the 'global' keyword.  Be sure to use correct \
133*0b57cec5SDimitry Andric Python syntax, including indentation, when entering Python watchpoint commands."
134*0b57cec5SDimitry Andric         R"(
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric Example Python one-line watchpoint command:
137*0b57cec5SDimitry Andric 
138*0b57cec5SDimitry Andric (lldb) watchpoint command add -s python 1
139*0b57cec5SDimitry Andric Enter your Python command(s). Type 'DONE' to end.
140*0b57cec5SDimitry Andric > print "Hit this watchpoint!"
141*0b57cec5SDimitry Andric > DONE
142*0b57cec5SDimitry Andric 
143*0b57cec5SDimitry Andric As a convenience, this also works for a short Python one-liner:
144*0b57cec5SDimitry Andric 
145*0b57cec5SDimitry Andric (lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()'
146*0b57cec5SDimitry Andric (lldb) run
147*0b57cec5SDimitry Andric Launching '.../a.out'  (x86_64)
148*0b57cec5SDimitry Andric (lldb) Fri Sep 10 12:17:45 2010
149*0b57cec5SDimitry Andric Process 21778 Stopped
150*0b57cec5SDimitry Andric * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread
151*0b57cec5SDimitry Andric   36
152*0b57cec5SDimitry Andric   37   	int c(int val)
153*0b57cec5SDimitry Andric   38   	{
154*0b57cec5SDimitry Andric   39 ->	    return val + 3;
155*0b57cec5SDimitry Andric   40   	}
156*0b57cec5SDimitry Andric   41
157*0b57cec5SDimitry Andric   42   	int main (int argc, char const *argv[])
158*0b57cec5SDimitry Andric 
159*0b57cec5SDimitry Andric Example multiple line Python watchpoint command, using function definition:
160*0b57cec5SDimitry Andric 
161*0b57cec5SDimitry Andric (lldb) watchpoint command add -s python 1
162*0b57cec5SDimitry Andric Enter your Python command(s). Type 'DONE' to end.
163*0b57cec5SDimitry Andric > def watchpoint_output (wp_no):
164*0b57cec5SDimitry Andric >     out_string = "Hit watchpoint number " + repr (wp_no)
165*0b57cec5SDimitry Andric >     print out_string
166*0b57cec5SDimitry Andric >     return True
167*0b57cec5SDimitry Andric > watchpoint_output (1)
168*0b57cec5SDimitry Andric > DONE
169*0b57cec5SDimitry Andric 
170*0b57cec5SDimitry Andric Example multiple line Python watchpoint command, using 'loose' Python:
171*0b57cec5SDimitry Andric 
172*0b57cec5SDimitry Andric (lldb) watchpoint command add -s p 1
173*0b57cec5SDimitry Andric Enter your Python command(s). Type 'DONE' to end.
174*0b57cec5SDimitry Andric > global wp_count
175*0b57cec5SDimitry Andric > wp_count = wp_count + 1
176*0b57cec5SDimitry Andric > print "Hit this watchpoint " + repr(wp_count) + " times!"
177*0b57cec5SDimitry Andric > DONE
178*0b57cec5SDimitry Andric 
179*0b57cec5SDimitry Andric )"
180*0b57cec5SDimitry Andric         "In this case, since there is a reference to a global variable, \
181*0b57cec5SDimitry Andric 'wp_count', you will also need to make sure 'wp_count' exists and is \
182*0b57cec5SDimitry Andric initialized:"
183*0b57cec5SDimitry Andric         R"(
184*0b57cec5SDimitry Andric 
185*0b57cec5SDimitry Andric (lldb) script
186*0b57cec5SDimitry Andric >>> wp_count = 0
187*0b57cec5SDimitry Andric >>> quit()
188*0b57cec5SDimitry Andric 
189*0b57cec5SDimitry Andric )"
190*0b57cec5SDimitry Andric         "Final Note: A warning that no watchpoint command was generated when there \
191*0b57cec5SDimitry Andric are no syntax errors may indicate that a function was declared but never called.");
192*0b57cec5SDimitry Andric 
193*0b57cec5SDimitry Andric     CommandArgumentEntry arg;
194*0b57cec5SDimitry Andric     CommandArgumentData wp_id_arg;
195*0b57cec5SDimitry Andric 
196*0b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
197*0b57cec5SDimitry Andric     wp_id_arg.arg_type = eArgTypeWatchpointID;
198*0b57cec5SDimitry Andric     wp_id_arg.arg_repetition = eArgRepeatPlain;
199*0b57cec5SDimitry Andric 
200*0b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
201*0b57cec5SDimitry Andric     // argument entry.
202*0b57cec5SDimitry Andric     arg.push_back(wp_id_arg);
203*0b57cec5SDimitry Andric 
204*0b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
205*0b57cec5SDimitry Andric     m_arguments.push_back(arg);
206*0b57cec5SDimitry Andric   }
207*0b57cec5SDimitry Andric 
208*0b57cec5SDimitry Andric   ~CommandObjectWatchpointCommandAdd() override = default;
209*0b57cec5SDimitry Andric 
210*0b57cec5SDimitry Andric   Options *GetOptions() override { return &m_options; }
211*0b57cec5SDimitry Andric 
212*0b57cec5SDimitry Andric   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
2139dba64beSDimitry Andric     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
214*0b57cec5SDimitry Andric     if (output_sp && interactive) {
215*0b57cec5SDimitry Andric       output_sp->PutCString(
216*0b57cec5SDimitry Andric           "Enter your debugger command(s).  Type 'DONE' to end.\n");
217*0b57cec5SDimitry Andric       output_sp->Flush();
218*0b57cec5SDimitry Andric     }
219*0b57cec5SDimitry Andric   }
220*0b57cec5SDimitry Andric 
221*0b57cec5SDimitry Andric   void IOHandlerInputComplete(IOHandler &io_handler,
222*0b57cec5SDimitry Andric                               std::string &line) override {
223*0b57cec5SDimitry Andric     io_handler.SetIsDone(true);
224*0b57cec5SDimitry Andric 
225*0b57cec5SDimitry Andric     // The WatchpointOptions object is owned by the watchpoint or watchpoint
226*0b57cec5SDimitry Andric     // location
227*0b57cec5SDimitry Andric     WatchpointOptions *wp_options =
228*0b57cec5SDimitry Andric         (WatchpointOptions *)io_handler.GetUserData();
229*0b57cec5SDimitry Andric     if (wp_options) {
230*0b57cec5SDimitry Andric       std::unique_ptr<WatchpointOptions::CommandData> data_up(
231*0b57cec5SDimitry Andric           new WatchpointOptions::CommandData());
232*0b57cec5SDimitry Andric       if (data_up) {
233*0b57cec5SDimitry Andric         data_up->user_source.SplitIntoLines(line);
234*0b57cec5SDimitry Andric         auto baton_sp = std::make_shared<WatchpointOptions::CommandBaton>(
235*0b57cec5SDimitry Andric             std::move(data_up));
236*0b57cec5SDimitry Andric         wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
237*0b57cec5SDimitry Andric       }
238*0b57cec5SDimitry Andric     }
239*0b57cec5SDimitry Andric   }
240*0b57cec5SDimitry Andric 
241*0b57cec5SDimitry Andric   void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,
242*0b57cec5SDimitry Andric                                                CommandReturnObject &result) {
243*0b57cec5SDimitry Andric     m_interpreter.GetLLDBCommandsFromIOHandler(
244*0b57cec5SDimitry Andric         "> ",        // Prompt
245*0b57cec5SDimitry Andric         *this,       // IOHandlerDelegate
246*0b57cec5SDimitry Andric         wp_options); // Baton for the "io_handler" that will be passed back into
247*0b57cec5SDimitry Andric                      // our IOHandlerDelegate functions
248*0b57cec5SDimitry Andric   }
249*0b57cec5SDimitry Andric 
250*0b57cec5SDimitry Andric   /// Set a one-liner as the callback for the watchpoint.
251*0b57cec5SDimitry Andric   void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
252*0b57cec5SDimitry Andric                                     const char *oneliner) {
253*0b57cec5SDimitry Andric     std::unique_ptr<WatchpointOptions::CommandData> data_up(
254*0b57cec5SDimitry Andric         new WatchpointOptions::CommandData());
255*0b57cec5SDimitry Andric 
256*0b57cec5SDimitry Andric     // It's necessary to set both user_source and script_source to the
257*0b57cec5SDimitry Andric     // oneliner. The former is used to generate callback description (as in
258*0b57cec5SDimitry Andric     // watchpoint command list) while the latter is used for Python to
259*0b57cec5SDimitry Andric     // interpret during the actual callback.
260*0b57cec5SDimitry Andric     data_up->user_source.AppendString(oneliner);
261*0b57cec5SDimitry Andric     data_up->script_source.assign(oneliner);
262*0b57cec5SDimitry Andric     data_up->stop_on_error = m_options.m_stop_on_error;
263*0b57cec5SDimitry Andric 
264*0b57cec5SDimitry Andric     auto baton_sp =
265*0b57cec5SDimitry Andric         std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_up));
266*0b57cec5SDimitry Andric     wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
267*0b57cec5SDimitry Andric   }
268*0b57cec5SDimitry Andric 
269*0b57cec5SDimitry Andric   static bool
270*0b57cec5SDimitry Andric   WatchpointOptionsCallbackFunction(void *baton,
271*0b57cec5SDimitry Andric                                     StoppointCallbackContext *context,
272*0b57cec5SDimitry Andric                                     lldb::user_id_t watch_id) {
273*0b57cec5SDimitry Andric     bool ret_value = true;
274*0b57cec5SDimitry Andric     if (baton == nullptr)
275*0b57cec5SDimitry Andric       return true;
276*0b57cec5SDimitry Andric 
277*0b57cec5SDimitry Andric     WatchpointOptions::CommandData *data =
278*0b57cec5SDimitry Andric         (WatchpointOptions::CommandData *)baton;
279*0b57cec5SDimitry Andric     StringList &commands = data->user_source;
280*0b57cec5SDimitry Andric 
281*0b57cec5SDimitry Andric     if (commands.GetSize() > 0) {
282*0b57cec5SDimitry Andric       ExecutionContext exe_ctx(context->exe_ctx_ref);
283*0b57cec5SDimitry Andric       Target *target = exe_ctx.GetTargetPtr();
284*0b57cec5SDimitry Andric       if (target) {
285*0b57cec5SDimitry Andric         Debugger &debugger = target->GetDebugger();
2865ffd83dbSDimitry Andric         CommandReturnObject result(debugger.GetUseColor());
2875ffd83dbSDimitry Andric 
288*0b57cec5SDimitry Andric         // Rig up the results secondary output stream to the debugger's, so the
289*0b57cec5SDimitry Andric         // output will come out synchronously if the debugger is set up that
290*0b57cec5SDimitry Andric         // way.
291*0b57cec5SDimitry Andric         StreamSP output_stream(debugger.GetAsyncOutputStream());
292*0b57cec5SDimitry Andric         StreamSP error_stream(debugger.GetAsyncErrorStream());
293*0b57cec5SDimitry Andric         result.SetImmediateOutputStream(output_stream);
294*0b57cec5SDimitry Andric         result.SetImmediateErrorStream(error_stream);
295*0b57cec5SDimitry Andric 
296*0b57cec5SDimitry Andric         CommandInterpreterRunOptions options;
297*0b57cec5SDimitry Andric         options.SetStopOnContinue(true);
298*0b57cec5SDimitry Andric         options.SetStopOnError(data->stop_on_error);
299*0b57cec5SDimitry Andric         options.SetEchoCommands(false);
300*0b57cec5SDimitry Andric         options.SetPrintResults(true);
301*0b57cec5SDimitry Andric         options.SetPrintErrors(true);
302*0b57cec5SDimitry Andric         options.SetAddToHistory(false);
303*0b57cec5SDimitry Andric 
304*0b57cec5SDimitry Andric         debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx,
305*0b57cec5SDimitry Andric                                                         options, result);
306*0b57cec5SDimitry Andric         result.GetImmediateOutputStream()->Flush();
307*0b57cec5SDimitry Andric         result.GetImmediateErrorStream()->Flush();
308*0b57cec5SDimitry Andric       }
309*0b57cec5SDimitry Andric     }
310*0b57cec5SDimitry Andric     return ret_value;
311*0b57cec5SDimitry Andric   }
312*0b57cec5SDimitry Andric 
313*0b57cec5SDimitry Andric   class CommandOptions : public Options {
314*0b57cec5SDimitry Andric   public:
315*0b57cec5SDimitry Andric     CommandOptions()
316*0b57cec5SDimitry Andric         : Options(), m_use_commands(false), m_use_script_language(false),
317*0b57cec5SDimitry Andric           m_script_language(eScriptLanguageNone), m_use_one_liner(false),
318*0b57cec5SDimitry Andric           m_one_liner(), m_function_name() {}
319*0b57cec5SDimitry Andric 
320*0b57cec5SDimitry Andric     ~CommandOptions() override = default;
321*0b57cec5SDimitry Andric 
322*0b57cec5SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
323*0b57cec5SDimitry Andric                           ExecutionContext *execution_context) override {
324*0b57cec5SDimitry Andric       Status error;
325*0b57cec5SDimitry Andric       const int short_option = m_getopt_table[option_idx].val;
326*0b57cec5SDimitry Andric 
327*0b57cec5SDimitry Andric       switch (short_option) {
328*0b57cec5SDimitry Andric       case 'o':
329*0b57cec5SDimitry Andric         m_use_one_liner = true;
3305ffd83dbSDimitry Andric         m_one_liner = std::string(option_arg);
331*0b57cec5SDimitry Andric         break;
332*0b57cec5SDimitry Andric 
333*0b57cec5SDimitry Andric       case 's':
334*0b57cec5SDimitry Andric         m_script_language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum(
335*0b57cec5SDimitry Andric             option_arg, GetDefinitions()[option_idx].enum_values,
336*0b57cec5SDimitry Andric             eScriptLanguageNone, error);
337*0b57cec5SDimitry Andric 
338480093f4SDimitry Andric         switch (m_script_language) {
339480093f4SDimitry Andric         case eScriptLanguagePython:
340480093f4SDimitry Andric         case eScriptLanguageLua:
341480093f4SDimitry Andric           m_use_script_language = true;
342480093f4SDimitry Andric           break;
343480093f4SDimitry Andric         case eScriptLanguageNone:
344480093f4SDimitry Andric         case eScriptLanguageUnknown:
345480093f4SDimitry Andric           m_use_script_language = false;
346480093f4SDimitry Andric           break;
347480093f4SDimitry Andric         }
348*0b57cec5SDimitry Andric         break;
349*0b57cec5SDimitry Andric 
350*0b57cec5SDimitry Andric       case 'e': {
351*0b57cec5SDimitry Andric         bool success = false;
352*0b57cec5SDimitry Andric         m_stop_on_error =
353*0b57cec5SDimitry Andric             OptionArgParser::ToBoolean(option_arg, false, &success);
354*0b57cec5SDimitry Andric         if (!success)
355*0b57cec5SDimitry Andric           error.SetErrorStringWithFormat(
356*0b57cec5SDimitry Andric               "invalid value for stop-on-error: \"%s\"",
357*0b57cec5SDimitry Andric               option_arg.str().c_str());
358*0b57cec5SDimitry Andric       } break;
359*0b57cec5SDimitry Andric 
360*0b57cec5SDimitry Andric       case 'F':
361*0b57cec5SDimitry Andric         m_use_one_liner = false;
3625ffd83dbSDimitry Andric         m_function_name.assign(std::string(option_arg));
363*0b57cec5SDimitry Andric         break;
364*0b57cec5SDimitry Andric 
365*0b57cec5SDimitry Andric       default:
3669dba64beSDimitry Andric         llvm_unreachable("Unimplemented option");
367*0b57cec5SDimitry Andric       }
368*0b57cec5SDimitry Andric       return error;
369*0b57cec5SDimitry Andric     }
370*0b57cec5SDimitry Andric 
371*0b57cec5SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
372*0b57cec5SDimitry Andric       m_use_commands = true;
373*0b57cec5SDimitry Andric       m_use_script_language = false;
374*0b57cec5SDimitry Andric       m_script_language = eScriptLanguageNone;
375*0b57cec5SDimitry Andric 
376*0b57cec5SDimitry Andric       m_use_one_liner = false;
377*0b57cec5SDimitry Andric       m_stop_on_error = true;
378*0b57cec5SDimitry Andric       m_one_liner.clear();
379*0b57cec5SDimitry Andric       m_function_name.clear();
380*0b57cec5SDimitry Andric     }
381*0b57cec5SDimitry Andric 
382*0b57cec5SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
383*0b57cec5SDimitry Andric       return llvm::makeArrayRef(g_watchpoint_command_add_options);
384*0b57cec5SDimitry Andric     }
385*0b57cec5SDimitry Andric 
386*0b57cec5SDimitry Andric     // Instance variables to hold the values for command options.
387*0b57cec5SDimitry Andric 
388*0b57cec5SDimitry Andric     bool m_use_commands;
389*0b57cec5SDimitry Andric     bool m_use_script_language;
390*0b57cec5SDimitry Andric     lldb::ScriptLanguage m_script_language;
391*0b57cec5SDimitry Andric 
392*0b57cec5SDimitry Andric     // Instance variables to hold the values for one_liner options.
393*0b57cec5SDimitry Andric     bool m_use_one_liner;
394*0b57cec5SDimitry Andric     std::string m_one_liner;
395*0b57cec5SDimitry Andric     bool m_stop_on_error;
396*0b57cec5SDimitry Andric     std::string m_function_name;
397*0b57cec5SDimitry Andric   };
398*0b57cec5SDimitry Andric 
399*0b57cec5SDimitry Andric protected:
400*0b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
4019dba64beSDimitry Andric     Target *target = &GetSelectedTarget();
402*0b57cec5SDimitry Andric 
403*0b57cec5SDimitry Andric     const WatchpointList &watchpoints = target->GetWatchpointList();
404*0b57cec5SDimitry Andric     size_t num_watchpoints = watchpoints.GetSize();
405*0b57cec5SDimitry Andric 
406*0b57cec5SDimitry Andric     if (num_watchpoints == 0) {
407*0b57cec5SDimitry Andric       result.AppendError("No watchpoints exist to have commands added");
408*0b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
409*0b57cec5SDimitry Andric       return false;
410*0b57cec5SDimitry Andric     }
411*0b57cec5SDimitry Andric 
412480093f4SDimitry Andric     if (!m_options.m_function_name.empty()) {
413480093f4SDimitry Andric       if (!m_options.m_use_script_language) {
414480093f4SDimitry Andric         m_options.m_script_language = GetDebugger().GetScriptLanguage();
415480093f4SDimitry Andric         m_options.m_use_script_language = true;
416480093f4SDimitry Andric       }
417*0b57cec5SDimitry Andric     }
418*0b57cec5SDimitry Andric 
419*0b57cec5SDimitry Andric     std::vector<uint32_t> valid_wp_ids;
420*0b57cec5SDimitry Andric     if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
421*0b57cec5SDimitry Andric                                                                valid_wp_ids)) {
422*0b57cec5SDimitry Andric       result.AppendError("Invalid watchpoints specification.");
423*0b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
424*0b57cec5SDimitry Andric       return false;
425*0b57cec5SDimitry Andric     }
426*0b57cec5SDimitry Andric 
427*0b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
428*0b57cec5SDimitry Andric     const size_t count = valid_wp_ids.size();
429*0b57cec5SDimitry Andric     for (size_t i = 0; i < count; ++i) {
430*0b57cec5SDimitry Andric       uint32_t cur_wp_id = valid_wp_ids.at(i);
431*0b57cec5SDimitry Andric       if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
432*0b57cec5SDimitry Andric         Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
433*0b57cec5SDimitry Andric         // Sanity check wp first.
434*0b57cec5SDimitry Andric         if (wp == nullptr)
435*0b57cec5SDimitry Andric           continue;
436*0b57cec5SDimitry Andric 
437*0b57cec5SDimitry Andric         WatchpointOptions *wp_options = wp->GetOptions();
438*0b57cec5SDimitry Andric         // Skip this watchpoint if wp_options is not good.
439*0b57cec5SDimitry Andric         if (wp_options == nullptr)
440*0b57cec5SDimitry Andric           continue;
441*0b57cec5SDimitry Andric 
442*0b57cec5SDimitry Andric         // If we are using script language, get the script interpreter in order
443*0b57cec5SDimitry Andric         // to set or collect command callback.  Otherwise, call the methods
444*0b57cec5SDimitry Andric         // associated with this object.
445*0b57cec5SDimitry Andric         if (m_options.m_use_script_language) {
446480093f4SDimitry Andric           ScriptInterpreter *script_interp = GetDebugger().GetScriptInterpreter(
447480093f4SDimitry Andric               /*can_create=*/true, m_options.m_script_language);
448*0b57cec5SDimitry Andric           // Special handling for one-liner specified inline.
449*0b57cec5SDimitry Andric           if (m_options.m_use_one_liner) {
450480093f4SDimitry Andric             script_interp->SetWatchpointCommandCallback(
451*0b57cec5SDimitry Andric                 wp_options, m_options.m_one_liner.c_str());
452*0b57cec5SDimitry Andric           }
453*0b57cec5SDimitry Andric           // Special handling for using a Python function by name instead of
454*0b57cec5SDimitry Andric           // extending the watchpoint callback data structures, we just
455*0b57cec5SDimitry Andric           // automatize what the user would do manually: make their watchpoint
456*0b57cec5SDimitry Andric           // command be a function call
457*0b57cec5SDimitry Andric           else if (!m_options.m_function_name.empty()) {
458*0b57cec5SDimitry Andric             std::string oneliner(m_options.m_function_name);
459*0b57cec5SDimitry Andric             oneliner += "(frame, wp, internal_dict)";
460480093f4SDimitry Andric             script_interp->SetWatchpointCommandCallback(
461*0b57cec5SDimitry Andric                 wp_options, oneliner.c_str());
462*0b57cec5SDimitry Andric           } else {
463480093f4SDimitry Andric             script_interp->CollectDataForWatchpointCommandCallback(wp_options,
464480093f4SDimitry Andric                                                                    result);
465*0b57cec5SDimitry Andric           }
466*0b57cec5SDimitry Andric         } else {
467*0b57cec5SDimitry Andric           // Special handling for one-liner specified inline.
468*0b57cec5SDimitry Andric           if (m_options.m_use_one_liner)
469*0b57cec5SDimitry Andric             SetWatchpointCommandCallback(wp_options,
470*0b57cec5SDimitry Andric                                          m_options.m_one_liner.c_str());
471*0b57cec5SDimitry Andric           else
472*0b57cec5SDimitry Andric             CollectDataForWatchpointCommandCallback(wp_options, result);
473*0b57cec5SDimitry Andric         }
474*0b57cec5SDimitry Andric       }
475*0b57cec5SDimitry Andric     }
476*0b57cec5SDimitry Andric 
477*0b57cec5SDimitry Andric     return result.Succeeded();
478*0b57cec5SDimitry Andric   }
479*0b57cec5SDimitry Andric 
480*0b57cec5SDimitry Andric private:
481*0b57cec5SDimitry Andric   CommandOptions m_options;
482*0b57cec5SDimitry Andric };
483*0b57cec5SDimitry Andric 
484*0b57cec5SDimitry Andric // CommandObjectWatchpointCommandDelete
485*0b57cec5SDimitry Andric 
486*0b57cec5SDimitry Andric class CommandObjectWatchpointCommandDelete : public CommandObjectParsed {
487*0b57cec5SDimitry Andric public:
488*0b57cec5SDimitry Andric   CommandObjectWatchpointCommandDelete(CommandInterpreter &interpreter)
489*0b57cec5SDimitry Andric       : CommandObjectParsed(interpreter, "delete",
490*0b57cec5SDimitry Andric                             "Delete the set of commands from a watchpoint.",
4919dba64beSDimitry Andric                             nullptr, eCommandRequiresTarget) {
492*0b57cec5SDimitry Andric     CommandArgumentEntry arg;
493*0b57cec5SDimitry Andric     CommandArgumentData wp_id_arg;
494*0b57cec5SDimitry Andric 
495*0b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
496*0b57cec5SDimitry Andric     wp_id_arg.arg_type = eArgTypeWatchpointID;
497*0b57cec5SDimitry Andric     wp_id_arg.arg_repetition = eArgRepeatPlain;
498*0b57cec5SDimitry Andric 
499*0b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
500*0b57cec5SDimitry Andric     // argument entry.
501*0b57cec5SDimitry Andric     arg.push_back(wp_id_arg);
502*0b57cec5SDimitry Andric 
503*0b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
504*0b57cec5SDimitry Andric     m_arguments.push_back(arg);
505*0b57cec5SDimitry Andric   }
506*0b57cec5SDimitry Andric 
507*0b57cec5SDimitry Andric   ~CommandObjectWatchpointCommandDelete() override = default;
508*0b57cec5SDimitry Andric 
509*0b57cec5SDimitry Andric protected:
510*0b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
5119dba64beSDimitry Andric     Target *target = &GetSelectedTarget();
512*0b57cec5SDimitry Andric 
513*0b57cec5SDimitry Andric     const WatchpointList &watchpoints = target->GetWatchpointList();
514*0b57cec5SDimitry Andric     size_t num_watchpoints = watchpoints.GetSize();
515*0b57cec5SDimitry Andric 
516*0b57cec5SDimitry Andric     if (num_watchpoints == 0) {
517*0b57cec5SDimitry Andric       result.AppendError("No watchpoints exist to have commands deleted");
518*0b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
519*0b57cec5SDimitry Andric       return false;
520*0b57cec5SDimitry Andric     }
521*0b57cec5SDimitry Andric 
522*0b57cec5SDimitry Andric     if (command.GetArgumentCount() == 0) {
523*0b57cec5SDimitry Andric       result.AppendError(
524*0b57cec5SDimitry Andric           "No watchpoint specified from which to delete the commands");
525*0b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
526*0b57cec5SDimitry Andric       return false;
527*0b57cec5SDimitry Andric     }
528*0b57cec5SDimitry Andric 
529*0b57cec5SDimitry Andric     std::vector<uint32_t> valid_wp_ids;
530*0b57cec5SDimitry Andric     if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
531*0b57cec5SDimitry Andric                                                                valid_wp_ids)) {
532*0b57cec5SDimitry Andric       result.AppendError("Invalid watchpoints specification.");
533*0b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
534*0b57cec5SDimitry Andric       return false;
535*0b57cec5SDimitry Andric     }
536*0b57cec5SDimitry Andric 
537*0b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
538*0b57cec5SDimitry Andric     const size_t count = valid_wp_ids.size();
539*0b57cec5SDimitry Andric     for (size_t i = 0; i < count; ++i) {
540*0b57cec5SDimitry Andric       uint32_t cur_wp_id = valid_wp_ids.at(i);
541*0b57cec5SDimitry Andric       if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
542*0b57cec5SDimitry Andric         Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
543*0b57cec5SDimitry Andric         if (wp)
544*0b57cec5SDimitry Andric           wp->ClearCallback();
545*0b57cec5SDimitry Andric       } else {
546*0b57cec5SDimitry Andric         result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
547*0b57cec5SDimitry Andric         result.SetStatus(eReturnStatusFailed);
548*0b57cec5SDimitry Andric         return false;
549*0b57cec5SDimitry Andric       }
550*0b57cec5SDimitry Andric     }
551*0b57cec5SDimitry Andric     return result.Succeeded();
552*0b57cec5SDimitry Andric   }
553*0b57cec5SDimitry Andric };
554*0b57cec5SDimitry Andric 
555*0b57cec5SDimitry Andric // CommandObjectWatchpointCommandList
556*0b57cec5SDimitry Andric 
557*0b57cec5SDimitry Andric class CommandObjectWatchpointCommandList : public CommandObjectParsed {
558*0b57cec5SDimitry Andric public:
559*0b57cec5SDimitry Andric   CommandObjectWatchpointCommandList(CommandInterpreter &interpreter)
5609dba64beSDimitry Andric       : CommandObjectParsed(interpreter, "list",
5619dba64beSDimitry Andric                             "List the script or set of commands to be executed "
5629dba64beSDimitry Andric                             "when the watchpoint is hit.",
5639dba64beSDimitry Andric                             nullptr, eCommandRequiresTarget) {
564*0b57cec5SDimitry Andric     CommandArgumentEntry arg;
565*0b57cec5SDimitry Andric     CommandArgumentData wp_id_arg;
566*0b57cec5SDimitry Andric 
567*0b57cec5SDimitry Andric     // Define the first (and only) variant of this arg.
568*0b57cec5SDimitry Andric     wp_id_arg.arg_type = eArgTypeWatchpointID;
569*0b57cec5SDimitry Andric     wp_id_arg.arg_repetition = eArgRepeatPlain;
570*0b57cec5SDimitry Andric 
571*0b57cec5SDimitry Andric     // There is only one variant this argument could be; put it into the
572*0b57cec5SDimitry Andric     // argument entry.
573*0b57cec5SDimitry Andric     arg.push_back(wp_id_arg);
574*0b57cec5SDimitry Andric 
575*0b57cec5SDimitry Andric     // Push the data for the first argument into the m_arguments vector.
576*0b57cec5SDimitry Andric     m_arguments.push_back(arg);
577*0b57cec5SDimitry Andric   }
578*0b57cec5SDimitry Andric 
579*0b57cec5SDimitry Andric   ~CommandObjectWatchpointCommandList() override = default;
580*0b57cec5SDimitry Andric 
581*0b57cec5SDimitry Andric protected:
582*0b57cec5SDimitry Andric   bool DoExecute(Args &command, CommandReturnObject &result) override {
5839dba64beSDimitry Andric     Target *target = &GetSelectedTarget();
584*0b57cec5SDimitry Andric 
585*0b57cec5SDimitry Andric     const WatchpointList &watchpoints = target->GetWatchpointList();
586*0b57cec5SDimitry Andric     size_t num_watchpoints = watchpoints.GetSize();
587*0b57cec5SDimitry Andric 
588*0b57cec5SDimitry Andric     if (num_watchpoints == 0) {
589*0b57cec5SDimitry Andric       result.AppendError("No watchpoints exist for which to list commands");
590*0b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
591*0b57cec5SDimitry Andric       return false;
592*0b57cec5SDimitry Andric     }
593*0b57cec5SDimitry Andric 
594*0b57cec5SDimitry Andric     if (command.GetArgumentCount() == 0) {
595*0b57cec5SDimitry Andric       result.AppendError(
596*0b57cec5SDimitry Andric           "No watchpoint specified for which to list the commands");
597*0b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
598*0b57cec5SDimitry Andric       return false;
599*0b57cec5SDimitry Andric     }
600*0b57cec5SDimitry Andric 
601*0b57cec5SDimitry Andric     std::vector<uint32_t> valid_wp_ids;
602*0b57cec5SDimitry Andric     if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
603*0b57cec5SDimitry Andric                                                                valid_wp_ids)) {
604*0b57cec5SDimitry Andric       result.AppendError("Invalid watchpoints specification.");
605*0b57cec5SDimitry Andric       result.SetStatus(eReturnStatusFailed);
606*0b57cec5SDimitry Andric       return false;
607*0b57cec5SDimitry Andric     }
608*0b57cec5SDimitry Andric 
609*0b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
610*0b57cec5SDimitry Andric     const size_t count = valid_wp_ids.size();
611*0b57cec5SDimitry Andric     for (size_t i = 0; i < count; ++i) {
612*0b57cec5SDimitry Andric       uint32_t cur_wp_id = valid_wp_ids.at(i);
613*0b57cec5SDimitry Andric       if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
614*0b57cec5SDimitry Andric         Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
615*0b57cec5SDimitry Andric 
616*0b57cec5SDimitry Andric         if (wp) {
617*0b57cec5SDimitry Andric           const WatchpointOptions *wp_options = wp->GetOptions();
618*0b57cec5SDimitry Andric           if (wp_options) {
619*0b57cec5SDimitry Andric             // Get the callback baton associated with the current watchpoint.
620*0b57cec5SDimitry Andric             const Baton *baton = wp_options->GetBaton();
621*0b57cec5SDimitry Andric             if (baton) {
622*0b57cec5SDimitry Andric               result.GetOutputStream().Printf("Watchpoint %u:\n", cur_wp_id);
623480093f4SDimitry Andric               baton->GetDescription(result.GetOutputStream().AsRawOstream(),
624480093f4SDimitry Andric                                     eDescriptionLevelFull,
625480093f4SDimitry Andric                                     result.GetOutputStream().GetIndentLevel() +
626480093f4SDimitry Andric                                         2);
627*0b57cec5SDimitry Andric             } else {
628*0b57cec5SDimitry Andric               result.AppendMessageWithFormat(
629*0b57cec5SDimitry Andric                   "Watchpoint %u does not have an associated command.\n",
630*0b57cec5SDimitry Andric                   cur_wp_id);
631*0b57cec5SDimitry Andric             }
632*0b57cec5SDimitry Andric           }
633*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusSuccessFinishResult);
634*0b57cec5SDimitry Andric         } else {
635*0b57cec5SDimitry Andric           result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
636*0b57cec5SDimitry Andric                                        cur_wp_id);
637*0b57cec5SDimitry Andric           result.SetStatus(eReturnStatusFailed);
638*0b57cec5SDimitry Andric         }
639*0b57cec5SDimitry Andric       }
640*0b57cec5SDimitry Andric     }
641*0b57cec5SDimitry Andric 
642*0b57cec5SDimitry Andric     return result.Succeeded();
643*0b57cec5SDimitry Andric   }
644*0b57cec5SDimitry Andric };
645*0b57cec5SDimitry Andric 
646*0b57cec5SDimitry Andric // CommandObjectWatchpointCommand
647*0b57cec5SDimitry Andric 
648*0b57cec5SDimitry Andric CommandObjectWatchpointCommand::CommandObjectWatchpointCommand(
649*0b57cec5SDimitry Andric     CommandInterpreter &interpreter)
650*0b57cec5SDimitry Andric     : CommandObjectMultiword(
651*0b57cec5SDimitry Andric           interpreter, "command",
652*0b57cec5SDimitry Andric           "Commands for adding, removing and examining LLDB commands "
653*0b57cec5SDimitry Andric           "executed when the watchpoint is hit (watchpoint 'commands').",
654*0b57cec5SDimitry Andric           "command <sub-command> [<sub-command-options>] <watchpoint-id>") {
655*0b57cec5SDimitry Andric   CommandObjectSP add_command_object(
656*0b57cec5SDimitry Andric       new CommandObjectWatchpointCommandAdd(interpreter));
657*0b57cec5SDimitry Andric   CommandObjectSP delete_command_object(
658*0b57cec5SDimitry Andric       new CommandObjectWatchpointCommandDelete(interpreter));
659*0b57cec5SDimitry Andric   CommandObjectSP list_command_object(
660*0b57cec5SDimitry Andric       new CommandObjectWatchpointCommandList(interpreter));
661*0b57cec5SDimitry Andric 
662*0b57cec5SDimitry Andric   add_command_object->SetCommandName("watchpoint command add");
663*0b57cec5SDimitry Andric   delete_command_object->SetCommandName("watchpoint command delete");
664*0b57cec5SDimitry Andric   list_command_object->SetCommandName("watchpoint command list");
665*0b57cec5SDimitry Andric 
666*0b57cec5SDimitry Andric   LoadSubCommand("add", add_command_object);
667*0b57cec5SDimitry Andric   LoadSubCommand("delete", delete_command_object);
668*0b57cec5SDimitry Andric   LoadSubCommand("list", list_command_object);
669*0b57cec5SDimitry Andric }
670*0b57cec5SDimitry Andric 
671*0b57cec5SDimitry Andric CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand() = default;
672