1e9a5627eSJohnny Chen //===-- CommandObjectWatchpointCommand.cpp ----------------------*- C++ -*-===//
2e9a5627eSJohnny Chen //
3e9a5627eSJohnny Chen //                     The LLVM Compiler Infrastructure
4e9a5627eSJohnny Chen //
5e9a5627eSJohnny Chen // This file is distributed under the University of Illinois Open Source
6e9a5627eSJohnny Chen // License. See LICENSE.TXT for details.
7e9a5627eSJohnny Chen //
8e9a5627eSJohnny Chen //===----------------------------------------------------------------------===//
9e9a5627eSJohnny Chen 
1093a64300SDaniel Malea #include "lldb/lldb-python.h"
1193a64300SDaniel Malea 
12e9a5627eSJohnny Chen // C Includes
13e9a5627eSJohnny Chen // C++ Includes
14e9a5627eSJohnny Chen 
15e9a5627eSJohnny Chen 
16e9a5627eSJohnny Chen #include "CommandObjectWatchpointCommand.h"
17e9a5627eSJohnny Chen #include "CommandObjectWatchpoint.h"
18e9a5627eSJohnny Chen 
19e9a5627eSJohnny Chen #include "lldb/Interpreter/CommandInterpreter.h"
20e9a5627eSJohnny Chen #include "lldb/Interpreter/CommandReturnObject.h"
21e9a5627eSJohnny Chen #include "lldb/Target/Target.h"
22e9a5627eSJohnny Chen #include "lldb/Target/Thread.h"
23e9a5627eSJohnny Chen #include "lldb/Breakpoint/Watchpoint.h"
24e9a5627eSJohnny Chen #include "lldb/Breakpoint/StoppointCallbackContext.h"
25e9a5627eSJohnny Chen #include "lldb/Core/State.h"
26e9a5627eSJohnny Chen 
27e9a5627eSJohnny Chen #include <vector>
28e9a5627eSJohnny Chen 
29e9a5627eSJohnny Chen using namespace lldb;
30e9a5627eSJohnny Chen using namespace lldb_private;
31e9a5627eSJohnny Chen 
32e9a5627eSJohnny Chen //-------------------------------------------------------------------------
33e9a5627eSJohnny Chen // CommandObjectWatchpointCommandAdd
34e9a5627eSJohnny Chen //-------------------------------------------------------------------------
35e9a5627eSJohnny Chen 
36e9a5627eSJohnny Chen 
37e9a5627eSJohnny Chen class CommandObjectWatchpointCommandAdd : public CommandObjectParsed
38e9a5627eSJohnny Chen {
39e9a5627eSJohnny Chen public:
40e9a5627eSJohnny Chen 
41e9a5627eSJohnny Chen     CommandObjectWatchpointCommandAdd (CommandInterpreter &interpreter) :
42e9a5627eSJohnny Chen         CommandObjectParsed (interpreter,
43e9a5627eSJohnny Chen                              "add",
44e9a5627eSJohnny Chen                              "Add a set of commands to a watchpoint, to be executed whenever the watchpoint is hit.",
45e9a5627eSJohnny Chen                              NULL),
46e9a5627eSJohnny Chen         m_options (interpreter)
47e9a5627eSJohnny Chen     {
48e9a5627eSJohnny Chen         SetHelpLong (
49e9a5627eSJohnny Chen "\nGeneral information about entering watchpoint commands \n\
50e9a5627eSJohnny Chen ------------------------------------------------------ \n\
51e9a5627eSJohnny Chen  \n\
52e9a5627eSJohnny Chen This command will cause you to be prompted to enter the command or set \n\
53e9a5627eSJohnny Chen of commands you wish to be executed when the specified watchpoint is \n\
54e9a5627eSJohnny Chen hit.  You will be told to enter your command(s), and will see a '> ' \n\
55e9a5627eSJohnny Chen prompt. Because you can enter one or many commands to be executed when \n\
56e9a5627eSJohnny Chen a watchpoint is hit, you will continue to be prompted after each \n\
57e9a5627eSJohnny Chen new-line that you enter, until you enter the word 'DONE', which will \n\
58e9a5627eSJohnny Chen cause the commands you have entered to be stored with the watchpoint \n\
59e9a5627eSJohnny Chen and executed when the watchpoint is hit. \n\
60e9a5627eSJohnny Chen  \n\
61e9a5627eSJohnny Chen Syntax checking is not necessarily done when watchpoint commands are \n\
62e9a5627eSJohnny Chen entered.  An improperly written watchpoint command will attempt to get \n\
63e9a5627eSJohnny Chen executed when the watchpoint gets hit, and usually silently fail.  If \n\
64e9a5627eSJohnny Chen your watchpoint command does not appear to be getting executed, go \n\
65e9a5627eSJohnny Chen back and check your syntax. \n\
66e9a5627eSJohnny Chen  \n\
67e9a5627eSJohnny Chen  \n\
68e9a5627eSJohnny Chen Special information about PYTHON watchpoint commands                            \n\
69e9a5627eSJohnny Chen ----------------------------------------------------                            \n\
70e9a5627eSJohnny Chen                                                                                 \n\
71e9a5627eSJohnny Chen You may enter either one line of Python or multiple lines of Python             \n\
72e9a5627eSJohnny Chen (including defining whole functions, if desired).  If you enter a               \n\
73e9a5627eSJohnny Chen single line of Python, that will be passed to the Python interpreter            \n\
74e9a5627eSJohnny Chen 'as is' when the watchpoint gets hit.  If you enter function                    \n\
75e9a5627eSJohnny Chen definitions, they will be passed to the Python interpreter as soon as           \n\
76e9a5627eSJohnny Chen you finish entering the watchpoint command, and they can be called              \n\
77e9a5627eSJohnny Chen later (don't forget to add calls to them, if you want them called when          \n\
78e9a5627eSJohnny Chen the watchpoint is hit).  If you enter multiple lines of Python that             \n\
79e9a5627eSJohnny Chen are not function definitions, they will be collected into a new,                \n\
80e9a5627eSJohnny Chen automatically generated Python function, and a call to the newly                \n\
81e9a5627eSJohnny Chen generated function will be attached to the watchpoint.                          \n\
82e9a5627eSJohnny Chen                                                                                 \n\
83e9a5627eSJohnny Chen This auto-generated function is passed in two arguments:                        \n\
84e9a5627eSJohnny Chen                                                                                 \n\
85e9a5627eSJohnny Chen     frame:  an SBFrame object representing the frame which hit the watchpoint.  \n\
86e9a5627eSJohnny Chen             From the frame you can get back to the thread and process.          \n\
87e9a5627eSJohnny Chen     wp:     the watchpoint that was hit.                                        \n\
88e9a5627eSJohnny Chen                                                                                 \n\
89e9a5627eSJohnny Chen Important Note: Because loose Python code gets collected into functions,        \n\
90e9a5627eSJohnny Chen if you want to access global variables in the 'loose' code, you need to         \n\
91e9a5627eSJohnny Chen specify that they are global, using the 'global' keyword.  Be sure to           \n\
92e9a5627eSJohnny Chen use correct Python syntax, including indentation, when entering Python          \n\
93e9a5627eSJohnny Chen watchpoint commands.                                                            \n\
94e9a5627eSJohnny Chen                                                                                 \n\
95e9a5627eSJohnny Chen As a third option, you can pass the name of an already existing Python function \n\
96e9a5627eSJohnny Chen and that function will be attached to the watchpoint. It will get passed the    \n\
97e9a5627eSJohnny Chen frame and wp_loc arguments mentioned above.                                     \n\
98e9a5627eSJohnny Chen                                                                                 \n\
99e9a5627eSJohnny Chen Example Python one-line watchpoint command: \n\
100e9a5627eSJohnny Chen  \n\
101e9a5627eSJohnny Chen (lldb) watchpoint command add -s python 1 \n\
102e9a5627eSJohnny Chen Enter your Python command(s). Type 'DONE' to end. \n\
103e9a5627eSJohnny Chen > print \"Hit this watchpoint!\" \n\
104e9a5627eSJohnny Chen > DONE \n\
105e9a5627eSJohnny Chen  \n\
106e9a5627eSJohnny Chen As a convenience, this also works for a short Python one-liner: \n\
107e9a5627eSJohnny Chen (lldb) watchpoint command add -s python 1 -o \"import time; print time.asctime()\" \n\
108e9a5627eSJohnny Chen (lldb) run \n\
109e9a5627eSJohnny Chen Launching '.../a.out'  (x86_64) \n\
110e9a5627eSJohnny Chen (lldb) Fri Sep 10 12:17:45 2010 \n\
111e9a5627eSJohnny Chen Process 21778 Stopped \n\
112e9a5627eSJohnny Chen * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread \n\
113e9a5627eSJohnny Chen   36   	\n\
114e9a5627eSJohnny Chen   37   	int c(int val)\n\
115e9a5627eSJohnny Chen   38   	{\n\
116e9a5627eSJohnny Chen   39 ->	    return val + 3;\n\
117e9a5627eSJohnny Chen   40   	}\n\
118e9a5627eSJohnny Chen   41   	\n\
119e9a5627eSJohnny Chen   42   	int main (int argc, char const *argv[])\n\
120e9a5627eSJohnny Chen (lldb) \n\
121e9a5627eSJohnny Chen  \n\
122e9a5627eSJohnny Chen Example multiple line Python watchpoint command, using function definition: \n\
123e9a5627eSJohnny Chen  \n\
124e9a5627eSJohnny Chen (lldb) watchpoint command add -s python 1 \n\
125e9a5627eSJohnny Chen Enter your Python command(s). Type 'DONE' to end. \n\
126e9a5627eSJohnny Chen > def watchpoint_output (wp_no): \n\
127e9a5627eSJohnny Chen >     out_string = \"Hit watchpoint number \" + repr (wp_no) \n\
128e9a5627eSJohnny Chen >     print out_string \n\
129e9a5627eSJohnny Chen >     return True \n\
130e9a5627eSJohnny Chen > watchpoint_output (1) \n\
131e9a5627eSJohnny Chen > DONE \n\
132e9a5627eSJohnny Chen  \n\
133e9a5627eSJohnny Chen  \n\
134e9a5627eSJohnny Chen Example multiple line Python watchpoint command, using 'loose' Python: \n\
135e9a5627eSJohnny Chen  \n\
136e9a5627eSJohnny Chen (lldb) watchpoint command add -s p 1 \n\
137e9a5627eSJohnny Chen Enter your Python command(s). Type 'DONE' to end. \n\
138e9a5627eSJohnny Chen > global wp_count \n\
139e9a5627eSJohnny Chen > wp_count = wp_count + 1 \n\
140e9a5627eSJohnny Chen > print \"Hit this watchpoint \" + repr(wp_count) + \" times!\" \n\
141e9a5627eSJohnny Chen > DONE \n\
142e9a5627eSJohnny Chen  \n\
143e9a5627eSJohnny Chen In this case, since there is a reference to a global variable, \n\
144e9a5627eSJohnny Chen 'wp_count', you will also need to make sure 'wp_count' exists and is \n\
145e9a5627eSJohnny Chen initialized: \n\
146e9a5627eSJohnny Chen  \n\
147e9a5627eSJohnny Chen (lldb) script \n\
148e9a5627eSJohnny Chen >>> wp_count = 0 \n\
149e9a5627eSJohnny Chen >>> quit() \n\
150e9a5627eSJohnny Chen  \n\
151e9a5627eSJohnny Chen (lldb)  \n\
152e9a5627eSJohnny Chen  \n\
153e9a5627eSJohnny Chen  \n\
154e9a5627eSJohnny Chen Final Note:  If you get a warning that no watchpoint command was generated, \n\
155e9a5627eSJohnny Chen but you did not get any syntax errors, you probably forgot to add a call \n\
156e9a5627eSJohnny Chen to your functions. \n\
157e9a5627eSJohnny Chen  \n\
158e9a5627eSJohnny Chen Special information about debugger command watchpoint commands \n\
159e9a5627eSJohnny Chen -------------------------------------------------------------- \n\
160e9a5627eSJohnny Chen  \n\
161e9a5627eSJohnny Chen You may enter any debugger command, exactly as you would at the \n\
162e9a5627eSJohnny Chen debugger prompt.  You may enter as many debugger commands as you like, \n\
163e9a5627eSJohnny Chen but do NOT enter more than one command per line. \n" );
164e9a5627eSJohnny Chen 
165e9a5627eSJohnny Chen         CommandArgumentEntry arg;
166e9a5627eSJohnny Chen         CommandArgumentData wp_id_arg;
167e9a5627eSJohnny Chen 
168e9a5627eSJohnny Chen         // Define the first (and only) variant of this arg.
169e9a5627eSJohnny Chen         wp_id_arg.arg_type = eArgTypeWatchpointID;
170e9a5627eSJohnny Chen         wp_id_arg.arg_repetition = eArgRepeatPlain;
171e9a5627eSJohnny Chen 
172e9a5627eSJohnny Chen         // There is only one variant this argument could be; put it into the argument entry.
173e9a5627eSJohnny Chen         arg.push_back (wp_id_arg);
174e9a5627eSJohnny Chen 
175e9a5627eSJohnny Chen         // Push the data for the first argument into the m_arguments vector.
176e9a5627eSJohnny Chen         m_arguments.push_back (arg);
177e9a5627eSJohnny Chen     }
178e9a5627eSJohnny Chen 
179e9a5627eSJohnny Chen     virtual
180e9a5627eSJohnny Chen     ~CommandObjectWatchpointCommandAdd () {}
181e9a5627eSJohnny Chen 
182e9a5627eSJohnny Chen     virtual Options *
183e9a5627eSJohnny Chen     GetOptions ()
184e9a5627eSJohnny Chen     {
185e9a5627eSJohnny Chen         return &m_options;
186e9a5627eSJohnny Chen     }
187e9a5627eSJohnny Chen 
188e9a5627eSJohnny Chen     void
189e9a5627eSJohnny Chen     CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
190e9a5627eSJohnny Chen                                              CommandReturnObject &result)
191e9a5627eSJohnny Chen     {
192e9a5627eSJohnny Chen         InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
1937b0992d9SGreg Clayton         std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
194e9a5627eSJohnny Chen         if (reader_sp && data_ap.get())
195e9a5627eSJohnny Chen         {
196e9a5627eSJohnny Chen             BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
197e9a5627eSJohnny Chen             wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
198e9a5627eSJohnny Chen 
199e9a5627eSJohnny Chen             Error err (reader_sp->Initialize (CommandObjectWatchpointCommandAdd::GenerateWatchpointCommandCallback,
200e9a5627eSJohnny Chen                                               wp_options,                   // callback_data
201e9a5627eSJohnny Chen                                               eInputReaderGranularityLine,  // token size, to pass to callback function
202e9a5627eSJohnny Chen                                               "DONE",                       // end token
203e9a5627eSJohnny Chen                                               "> ",                         // prompt
204e9a5627eSJohnny Chen                                               true));                       // echo input
205e9a5627eSJohnny Chen             if (err.Success())
206e9a5627eSJohnny Chen             {
207e9a5627eSJohnny Chen                 m_interpreter.GetDebugger().PushInputReader (reader_sp);
208e9a5627eSJohnny Chen                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
209e9a5627eSJohnny Chen             }
210e9a5627eSJohnny Chen             else
211e9a5627eSJohnny Chen             {
212e9a5627eSJohnny Chen                 result.AppendError (err.AsCString());
213e9a5627eSJohnny Chen                 result.SetStatus (eReturnStatusFailed);
214e9a5627eSJohnny Chen             }
215e9a5627eSJohnny Chen         }
216e9a5627eSJohnny Chen         else
217e9a5627eSJohnny Chen         {
218e9a5627eSJohnny Chen             result.AppendError("out of memory");
219e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
220e9a5627eSJohnny Chen         }
221e9a5627eSJohnny Chen 
222e9a5627eSJohnny Chen     }
223e9a5627eSJohnny Chen 
224e9a5627eSJohnny Chen     /// Set a one-liner as the callback for the watchpoint.
225e9a5627eSJohnny Chen     void
226e9a5627eSJohnny Chen     SetWatchpointCommandCallback (WatchpointOptions *wp_options,
227e9a5627eSJohnny Chen                                   const char *oneliner)
228e9a5627eSJohnny Chen     {
2297b0992d9SGreg Clayton         std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
230e9a5627eSJohnny Chen 
231e9a5627eSJohnny Chen         // It's necessary to set both user_source and script_source to the oneliner.
232e9a5627eSJohnny Chen         // The former is used to generate callback description (as in watchpoint command list)
233e9a5627eSJohnny Chen         // while the latter is used for Python to interpret during the actual callback.
234e9a5627eSJohnny Chen         data_ap->user_source.AppendString (oneliner);
235e9a5627eSJohnny Chen         data_ap->script_source.assign (oneliner);
236e9a5627eSJohnny Chen         data_ap->stop_on_error = m_options.m_stop_on_error;
237e9a5627eSJohnny Chen 
238e9a5627eSJohnny Chen         BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
239e9a5627eSJohnny Chen         wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
240e9a5627eSJohnny Chen 
241e9a5627eSJohnny Chen         return;
242e9a5627eSJohnny Chen     }
243e9a5627eSJohnny Chen 
244e9a5627eSJohnny Chen     static size_t
245e9a5627eSJohnny Chen     GenerateWatchpointCommandCallback (void *callback_data,
246e9a5627eSJohnny Chen                                        InputReader &reader,
247e9a5627eSJohnny Chen                                        lldb::InputReaderAction notification,
248e9a5627eSJohnny Chen                                        const char *bytes,
249e9a5627eSJohnny Chen                                        size_t bytes_len)
250e9a5627eSJohnny Chen     {
251e9a5627eSJohnny Chen         StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
252e9a5627eSJohnny Chen         bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
253e9a5627eSJohnny Chen 
254e9a5627eSJohnny Chen         switch (notification)
255e9a5627eSJohnny Chen         {
256e9a5627eSJohnny Chen         case eInputReaderActivate:
257e9a5627eSJohnny Chen             if (!batch_mode)
258e9a5627eSJohnny Chen             {
259e9a5627eSJohnny Chen                 out_stream->Printf ("%s\n", g_reader_instructions);
260e9a5627eSJohnny Chen                 if (reader.GetPrompt())
261e9a5627eSJohnny Chen                     out_stream->Printf ("%s", reader.GetPrompt());
262e9a5627eSJohnny Chen                 out_stream->Flush();
263e9a5627eSJohnny Chen             }
264e9a5627eSJohnny Chen             break;
265e9a5627eSJohnny Chen 
266e9a5627eSJohnny Chen         case eInputReaderDeactivate:
267e9a5627eSJohnny Chen             break;
268e9a5627eSJohnny Chen 
269e9a5627eSJohnny Chen         case eInputReaderReactivate:
270e9a5627eSJohnny Chen             if (reader.GetPrompt() && !batch_mode)
271e9a5627eSJohnny Chen             {
272e9a5627eSJohnny Chen                 out_stream->Printf ("%s", reader.GetPrompt());
273e9a5627eSJohnny Chen                 out_stream->Flush();
274e9a5627eSJohnny Chen             }
275e9a5627eSJohnny Chen             break;
276e9a5627eSJohnny Chen 
277e9a5627eSJohnny Chen         case eInputReaderAsynchronousOutputWritten:
278e9a5627eSJohnny Chen             break;
279e9a5627eSJohnny Chen 
280e9a5627eSJohnny Chen         case eInputReaderGotToken:
281e9a5627eSJohnny Chen             if (bytes && bytes_len && callback_data)
282e9a5627eSJohnny Chen             {
283e9a5627eSJohnny Chen                 WatchpointOptions *wp_options = (WatchpointOptions *) callback_data;
284e9a5627eSJohnny Chen                 if (wp_options)
285e9a5627eSJohnny Chen                 {
286e9a5627eSJohnny Chen                     Baton *wp_options_baton = wp_options->GetBaton();
287e9a5627eSJohnny Chen                     if (wp_options_baton)
288e9a5627eSJohnny Chen                         ((WatchpointOptions::CommandData *)wp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
289e9a5627eSJohnny Chen                 }
290e9a5627eSJohnny Chen             }
291e9a5627eSJohnny Chen             if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
292e9a5627eSJohnny Chen             {
293e9a5627eSJohnny Chen                 out_stream->Printf ("%s", reader.GetPrompt());
294e9a5627eSJohnny Chen                 out_stream->Flush();
295e9a5627eSJohnny Chen             }
296e9a5627eSJohnny Chen             break;
297e9a5627eSJohnny Chen 
298e9a5627eSJohnny Chen         case eInputReaderInterrupt:
299e9a5627eSJohnny Chen             {
300e9a5627eSJohnny Chen                 // Finish, and cancel the watchpoint command.
301e9a5627eSJohnny Chen                 reader.SetIsDone (true);
302e9a5627eSJohnny Chen                 WatchpointOptions *wp_options = (WatchpointOptions *) callback_data;
303e9a5627eSJohnny Chen                 if (wp_options)
304e9a5627eSJohnny Chen                 {
305e9a5627eSJohnny Chen                     Baton *wp_options_baton = wp_options->GetBaton ();
306e9a5627eSJohnny Chen                     if (wp_options_baton)
307e9a5627eSJohnny Chen                     {
308e9a5627eSJohnny Chen                         ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->user_source.Clear();
309e9a5627eSJohnny Chen                         ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->script_source.clear();
310e9a5627eSJohnny Chen                     }
311e9a5627eSJohnny Chen                 }
312e9a5627eSJohnny Chen                 if (!batch_mode)
313e9a5627eSJohnny Chen                 {
314e9a5627eSJohnny Chen                     out_stream->Printf ("Warning: No command attached to watchpoint.\n");
315e9a5627eSJohnny Chen                     out_stream->Flush();
316e9a5627eSJohnny Chen                 }
317e9a5627eSJohnny Chen             }
318e9a5627eSJohnny Chen             break;
319e9a5627eSJohnny Chen 
320e9a5627eSJohnny Chen         case eInputReaderEndOfFile:
321e9a5627eSJohnny Chen             reader.SetIsDone (true);
322e9a5627eSJohnny Chen             break;
323e9a5627eSJohnny Chen 
324e9a5627eSJohnny Chen         case eInputReaderDone:
325e9a5627eSJohnny Chen             break;
326e9a5627eSJohnny Chen         }
327e9a5627eSJohnny Chen 
328e9a5627eSJohnny Chen         return bytes_len;
329e9a5627eSJohnny Chen     }
330e9a5627eSJohnny Chen 
331e9a5627eSJohnny Chen     static bool
332e9a5627eSJohnny Chen     WatchpointOptionsCallbackFunction (void *baton,
333e9a5627eSJohnny Chen                                        StoppointCallbackContext *context,
334e9a5627eSJohnny Chen                                        lldb::user_id_t watch_id)
335e9a5627eSJohnny Chen     {
336e9a5627eSJohnny Chen         bool ret_value = true;
337e9a5627eSJohnny Chen         if (baton == NULL)
338e9a5627eSJohnny Chen             return true;
339e9a5627eSJohnny Chen 
340e9a5627eSJohnny Chen 
341e9a5627eSJohnny Chen         WatchpointOptions::CommandData *data = (WatchpointOptions::CommandData *) baton;
342e9a5627eSJohnny Chen         StringList &commands = data->user_source;
343e9a5627eSJohnny Chen 
344e9a5627eSJohnny Chen         if (commands.GetSize() > 0)
345e9a5627eSJohnny Chen         {
346e9a5627eSJohnny Chen             ExecutionContext exe_ctx (context->exe_ctx_ref);
347e9a5627eSJohnny Chen             Target *target = exe_ctx.GetTargetPtr();
348e9a5627eSJohnny Chen             if (target)
349e9a5627eSJohnny Chen             {
350e9a5627eSJohnny Chen                 CommandReturnObject result;
351e9a5627eSJohnny Chen                 Debugger &debugger = target->GetDebugger();
352e9a5627eSJohnny Chen                 // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
353e9a5627eSJohnny Chen                 // if the debugger is set up that way.
354e9a5627eSJohnny Chen 
355e9a5627eSJohnny Chen                 StreamSP output_stream (debugger.GetAsyncOutputStream());
356e9a5627eSJohnny Chen                 StreamSP error_stream (debugger.GetAsyncErrorStream());
357e9a5627eSJohnny Chen                 result.SetImmediateOutputStream (output_stream);
358e9a5627eSJohnny Chen                 result.SetImmediateErrorStream (error_stream);
359e9a5627eSJohnny Chen 
360e9a5627eSJohnny Chen                 bool stop_on_continue = true;
361e9a5627eSJohnny Chen                 bool echo_commands    = false;
362e9a5627eSJohnny Chen                 bool print_results    = true;
363e9a5627eSJohnny Chen 
364e9a5627eSJohnny Chen                 debugger.GetCommandInterpreter().HandleCommands (commands,
365e9a5627eSJohnny Chen                                                                  &exe_ctx,
366e9a5627eSJohnny Chen                                                                  stop_on_continue,
367e9a5627eSJohnny Chen                                                                  data->stop_on_error,
368e9a5627eSJohnny Chen                                                                  echo_commands,
369e9a5627eSJohnny Chen                                                                  print_results,
370e9a5627eSJohnny Chen                                                                  eLazyBoolNo,
371e9a5627eSJohnny Chen                                                                  result);
372e9a5627eSJohnny Chen                 result.GetImmediateOutputStream()->Flush();
373e9a5627eSJohnny Chen                 result.GetImmediateErrorStream()->Flush();
374e9a5627eSJohnny Chen            }
375e9a5627eSJohnny Chen         }
376e9a5627eSJohnny Chen         return ret_value;
377e9a5627eSJohnny Chen     }
378e9a5627eSJohnny Chen 
379e9a5627eSJohnny Chen     class CommandOptions : public Options
380e9a5627eSJohnny Chen     {
381e9a5627eSJohnny Chen     public:
382e9a5627eSJohnny Chen 
383e9a5627eSJohnny Chen         CommandOptions (CommandInterpreter &interpreter) :
384e9a5627eSJohnny Chen             Options (interpreter),
385e9a5627eSJohnny Chen             m_use_commands (false),
386e9a5627eSJohnny Chen             m_use_script_language (false),
387e9a5627eSJohnny Chen             m_script_language (eScriptLanguageNone),
388e9a5627eSJohnny Chen             m_use_one_liner (false),
389e9a5627eSJohnny Chen             m_one_liner(),
390e9a5627eSJohnny Chen             m_function_name()
391e9a5627eSJohnny Chen         {
392e9a5627eSJohnny Chen         }
393e9a5627eSJohnny Chen 
394e9a5627eSJohnny Chen         virtual
395e9a5627eSJohnny Chen         ~CommandOptions () {}
396e9a5627eSJohnny Chen 
397e9a5627eSJohnny Chen         virtual Error
398e9a5627eSJohnny Chen         SetOptionValue (uint32_t option_idx, const char *option_arg)
399e9a5627eSJohnny Chen         {
400e9a5627eSJohnny Chen             Error error;
4013bcdfc0eSGreg Clayton             const int short_option = m_getopt_table[option_idx].val;
402e9a5627eSJohnny Chen 
403e9a5627eSJohnny Chen             switch (short_option)
404e9a5627eSJohnny Chen             {
405e9a5627eSJohnny Chen             case 'o':
406e9a5627eSJohnny Chen                 m_use_one_liner = true;
407e9a5627eSJohnny Chen                 m_one_liner = option_arg;
408e9a5627eSJohnny Chen                 break;
409e9a5627eSJohnny Chen 
410e9a5627eSJohnny Chen             case 's':
411e9a5627eSJohnny Chen                 m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
412e9a5627eSJohnny Chen                                                                                      g_option_table[option_idx].enum_values,
413e9a5627eSJohnny Chen                                                                                      eScriptLanguageNone,
414e9a5627eSJohnny Chen                                                                                      error);
415e9a5627eSJohnny Chen 
416e9a5627eSJohnny Chen                 if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
417e9a5627eSJohnny Chen                 {
418e9a5627eSJohnny Chen                     m_use_script_language = true;
419e9a5627eSJohnny Chen                 }
420e9a5627eSJohnny Chen                 else
421e9a5627eSJohnny Chen                 {
422e9a5627eSJohnny Chen                     m_use_script_language = false;
423e9a5627eSJohnny Chen                 }
424e9a5627eSJohnny Chen                 break;
425e9a5627eSJohnny Chen 
426e9a5627eSJohnny Chen             case 'e':
427e9a5627eSJohnny Chen                 {
428e9a5627eSJohnny Chen                     bool success = false;
429e9a5627eSJohnny Chen                     m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
430e9a5627eSJohnny Chen                     if (!success)
431e9a5627eSJohnny Chen                         error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
432e9a5627eSJohnny Chen                 }
433e9a5627eSJohnny Chen                 break;
434e9a5627eSJohnny Chen 
435e9a5627eSJohnny Chen             case 'F':
436e9a5627eSJohnny Chen                 {
437e9a5627eSJohnny Chen                     m_use_one_liner = false;
438e9a5627eSJohnny Chen                     m_use_script_language = true;
439e9a5627eSJohnny Chen                     m_function_name.assign(option_arg);
440e9a5627eSJohnny Chen                 }
441e9a5627eSJohnny Chen                 break;
442e9a5627eSJohnny Chen 
443e9a5627eSJohnny Chen             default:
444e9a5627eSJohnny Chen                 break;
445e9a5627eSJohnny Chen             }
446e9a5627eSJohnny Chen             return error;
447e9a5627eSJohnny Chen         }
448e9a5627eSJohnny Chen         void
449e9a5627eSJohnny Chen         OptionParsingStarting ()
450e9a5627eSJohnny Chen         {
451e9a5627eSJohnny Chen             m_use_commands = true;
452e9a5627eSJohnny Chen             m_use_script_language = false;
453e9a5627eSJohnny Chen             m_script_language = eScriptLanguageNone;
454e9a5627eSJohnny Chen 
455e9a5627eSJohnny Chen             m_use_one_liner = false;
456e9a5627eSJohnny Chen             m_stop_on_error = true;
457e9a5627eSJohnny Chen             m_one_liner.clear();
458e9a5627eSJohnny Chen             m_function_name.clear();
459e9a5627eSJohnny Chen         }
460e9a5627eSJohnny Chen 
461e9a5627eSJohnny Chen         const OptionDefinition*
462e9a5627eSJohnny Chen         GetDefinitions ()
463e9a5627eSJohnny Chen         {
464e9a5627eSJohnny Chen             return g_option_table;
465e9a5627eSJohnny Chen         }
466e9a5627eSJohnny Chen 
467e9a5627eSJohnny Chen         // Options table: Required for subclasses of Options.
468e9a5627eSJohnny Chen 
469e9a5627eSJohnny Chen         static OptionDefinition g_option_table[];
470e9a5627eSJohnny Chen 
471e9a5627eSJohnny Chen         // Instance variables to hold the values for command options.
472e9a5627eSJohnny Chen 
473e9a5627eSJohnny Chen         bool m_use_commands;
474e9a5627eSJohnny Chen         bool m_use_script_language;
475e9a5627eSJohnny Chen         lldb::ScriptLanguage m_script_language;
476e9a5627eSJohnny Chen 
477e9a5627eSJohnny Chen         // Instance variables to hold the values for one_liner options.
478e9a5627eSJohnny Chen         bool m_use_one_liner;
479e9a5627eSJohnny Chen         std::string m_one_liner;
480e9a5627eSJohnny Chen         bool m_stop_on_error;
481e9a5627eSJohnny Chen         std::string m_function_name;
482e9a5627eSJohnny Chen     };
483e9a5627eSJohnny Chen 
484e9a5627eSJohnny Chen protected:
485e9a5627eSJohnny Chen     virtual bool
486e9a5627eSJohnny Chen     DoExecute (Args& command, CommandReturnObject &result)
487e9a5627eSJohnny Chen     {
488e9a5627eSJohnny Chen         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
489e9a5627eSJohnny Chen 
490e9a5627eSJohnny Chen         if (target == NULL)
491e9a5627eSJohnny Chen         {
492e9a5627eSJohnny Chen             result.AppendError ("There is not a current executable; there are no watchpoints to which to add commands");
493e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
494e9a5627eSJohnny Chen             return false;
495e9a5627eSJohnny Chen         }
496e9a5627eSJohnny Chen 
497e9a5627eSJohnny Chen         const WatchpointList &watchpoints = target->GetWatchpointList();
498e9a5627eSJohnny Chen         size_t num_watchpoints = watchpoints.GetSize();
499e9a5627eSJohnny Chen 
500e9a5627eSJohnny Chen         if (num_watchpoints == 0)
501e9a5627eSJohnny Chen         {
502e9a5627eSJohnny Chen             result.AppendError ("No watchpoints exist to have commands added");
503e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
504e9a5627eSJohnny Chen             return false;
505e9a5627eSJohnny Chen         }
506e9a5627eSJohnny Chen 
507e9a5627eSJohnny Chen         if (m_options.m_use_script_language == false && m_options.m_function_name.size())
508e9a5627eSJohnny Chen         {
509e9a5627eSJohnny Chen             result.AppendError ("need to enable scripting to have a function run as a watchpoint command");
510e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
511e9a5627eSJohnny Chen             return false;
512e9a5627eSJohnny Chen         }
513e9a5627eSJohnny Chen 
514e9a5627eSJohnny Chen         std::vector<uint32_t> valid_wp_ids;
515e9a5627eSJohnny Chen         if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(command, valid_wp_ids))
516e9a5627eSJohnny Chen         {
517e9a5627eSJohnny Chen             result.AppendError("Invalid watchpoints specification.");
518e9a5627eSJohnny Chen             result.SetStatus(eReturnStatusFailed);
519e9a5627eSJohnny Chen             return false;
520e9a5627eSJohnny Chen         }
521e9a5627eSJohnny Chen 
522e9a5627eSJohnny Chen         result.SetStatus(eReturnStatusSuccessFinishNoResult);
523e9a5627eSJohnny Chen         const size_t count = valid_wp_ids.size();
524e9a5627eSJohnny Chen         for (size_t i = 0; i < count; ++i)
525e9a5627eSJohnny Chen         {
526e9a5627eSJohnny Chen             uint32_t cur_wp_id = valid_wp_ids.at (i);
527e9a5627eSJohnny Chen             if (cur_wp_id != LLDB_INVALID_WATCH_ID)
528e9a5627eSJohnny Chen             {
529e9a5627eSJohnny Chen                 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
530e9a5627eSJohnny Chen                 // Sanity check wp first.
531e9a5627eSJohnny Chen                 if (wp == NULL) continue;
532e9a5627eSJohnny Chen 
533e9a5627eSJohnny Chen                 WatchpointOptions *wp_options = wp->GetOptions();
534e9a5627eSJohnny Chen                 // Skip this watchpoint if wp_options is not good.
535e9a5627eSJohnny Chen                 if (wp_options == NULL) continue;
536e9a5627eSJohnny Chen 
537e9a5627eSJohnny Chen                 // If we are using script language, get the script interpreter
538e9a5627eSJohnny Chen                 // in order to set or collect command callback.  Otherwise, call
539e9a5627eSJohnny Chen                 // the methods associated with this object.
540e9a5627eSJohnny Chen                 if (m_options.m_use_script_language)
541e9a5627eSJohnny Chen                 {
542e9a5627eSJohnny Chen                     // Special handling for one-liner specified inline.
543e9a5627eSJohnny Chen                     if (m_options.m_use_one_liner)
544e9a5627eSJohnny Chen                     {
545e9a5627eSJohnny Chen                         m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
546e9a5627eSJohnny Chen                                                                                             m_options.m_one_liner.c_str());
547e9a5627eSJohnny Chen                     }
548e9a5627eSJohnny Chen                     // Special handling for using a Python function by name
549e9a5627eSJohnny Chen                     // instead of extending the watchpoint callback data structures, we just automatize
550e9a5627eSJohnny Chen                     // what the user would do manually: make their watchpoint command be a function call
551e9a5627eSJohnny Chen                     else if (m_options.m_function_name.size())
552e9a5627eSJohnny Chen                     {
553e9a5627eSJohnny Chen                         std::string oneliner(m_options.m_function_name);
554e9a5627eSJohnny Chen                         oneliner += "(frame, wp, internal_dict)";
555e9a5627eSJohnny Chen                         m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
556e9a5627eSJohnny Chen                                                                                             oneliner.c_str());
557e9a5627eSJohnny Chen                     }
558e9a5627eSJohnny Chen                     else
559e9a5627eSJohnny Chen                     {
560e9a5627eSJohnny Chen                         m_interpreter.GetScriptInterpreter()->CollectDataForWatchpointCommandCallback (wp_options,
561e9a5627eSJohnny Chen                                                                                                        result);
562e9a5627eSJohnny Chen                     }
563e9a5627eSJohnny Chen                 }
564e9a5627eSJohnny Chen                 else
565e9a5627eSJohnny Chen                 {
566e9a5627eSJohnny Chen                     // Special handling for one-liner specified inline.
567e9a5627eSJohnny Chen                     if (m_options.m_use_one_liner)
568e9a5627eSJohnny Chen                         SetWatchpointCommandCallback (wp_options,
569e9a5627eSJohnny Chen                                                       m_options.m_one_liner.c_str());
570e9a5627eSJohnny Chen                     else
571e9a5627eSJohnny Chen                         CollectDataForWatchpointCommandCallback (wp_options,
572e9a5627eSJohnny Chen                                                                  result);
573e9a5627eSJohnny Chen                 }
574e9a5627eSJohnny Chen             }
575e9a5627eSJohnny Chen         }
576e9a5627eSJohnny Chen 
577e9a5627eSJohnny Chen         return result.Succeeded();
578e9a5627eSJohnny Chen     }
579e9a5627eSJohnny Chen 
580e9a5627eSJohnny Chen private:
581e9a5627eSJohnny Chen     CommandOptions m_options;
582e9a5627eSJohnny Chen     static const char *g_reader_instructions;
583e9a5627eSJohnny Chen 
584e9a5627eSJohnny Chen };
585e9a5627eSJohnny Chen 
586e9a5627eSJohnny Chen const char *
587e9a5627eSJohnny Chen CommandObjectWatchpointCommandAdd::g_reader_instructions = "Enter your debugger command(s).  Type 'DONE' to end.";
588e9a5627eSJohnny Chen 
589e9a5627eSJohnny Chen // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
590e9a5627eSJohnny Chen // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
591e9a5627eSJohnny Chen 
592e9a5627eSJohnny Chen static OptionEnumValueElement
593e9a5627eSJohnny Chen g_script_option_enumeration[4] =
594e9a5627eSJohnny Chen {
595e9a5627eSJohnny Chen     { eScriptLanguageNone,    "command",         "Commands are in the lldb command interpreter language"},
596e9a5627eSJohnny Chen     { eScriptLanguagePython,  "python",          "Commands are in the Python language."},
597e9a5627eSJohnny Chen     { eSortOrderByName,       "default-script",  "Commands are in the default scripting language."},
598e9a5627eSJohnny Chen     { 0,                      NULL,              NULL }
599e9a5627eSJohnny Chen };
600e9a5627eSJohnny Chen 
601e9a5627eSJohnny Chen OptionDefinition
602e9a5627eSJohnny Chen CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] =
603e9a5627eSJohnny Chen {
604bc6e85cbSFilipe Cabecinhas     { LLDB_OPT_SET_1,   false, "one-liner",       'o', required_argument, NULL, 0, eArgTypeOneLiner,
605e9a5627eSJohnny Chen         "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." },
606e9a5627eSJohnny Chen 
607bc6e85cbSFilipe Cabecinhas     { LLDB_OPT_SET_ALL, false, "stop-on-error",   'e', required_argument, NULL, 0, eArgTypeBoolean,
608e9a5627eSJohnny Chen         "Specify whether watchpoint command execution should terminate on error." },
609e9a5627eSJohnny Chen 
610bc6e85cbSFilipe Cabecinhas     { LLDB_OPT_SET_ALL, false, "script-type",     's', required_argument, g_script_option_enumeration, 0, eArgTypeNone,
611e9a5627eSJohnny Chen         "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
612e9a5627eSJohnny Chen 
613bc6e85cbSFilipe Cabecinhas     { LLDB_OPT_SET_2,   false, "python-function", 'F', required_argument, NULL, 0, eArgTypePythonFunction,
614e9a5627eSJohnny Chen         "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."},
615e9a5627eSJohnny Chen 
616e9a5627eSJohnny Chen     { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
617e9a5627eSJohnny Chen };
618e9a5627eSJohnny Chen 
619e9a5627eSJohnny Chen //-------------------------------------------------------------------------
620e9a5627eSJohnny Chen // CommandObjectWatchpointCommandDelete
621e9a5627eSJohnny Chen //-------------------------------------------------------------------------
622e9a5627eSJohnny Chen 
623e9a5627eSJohnny Chen class CommandObjectWatchpointCommandDelete : public CommandObjectParsed
624e9a5627eSJohnny Chen {
625e9a5627eSJohnny Chen public:
626e9a5627eSJohnny Chen     CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) :
627e9a5627eSJohnny Chen         CommandObjectParsed (interpreter,
628e9a5627eSJohnny Chen                              "delete",
629e9a5627eSJohnny Chen                              "Delete the set of commands from a watchpoint.",
630e9a5627eSJohnny Chen                              NULL)
631e9a5627eSJohnny Chen     {
632e9a5627eSJohnny Chen         CommandArgumentEntry arg;
633e9a5627eSJohnny Chen         CommandArgumentData wp_id_arg;
634e9a5627eSJohnny Chen 
635e9a5627eSJohnny Chen         // Define the first (and only) variant of this arg.
636e9a5627eSJohnny Chen         wp_id_arg.arg_type = eArgTypeWatchpointID;
637e9a5627eSJohnny Chen         wp_id_arg.arg_repetition = eArgRepeatPlain;
638e9a5627eSJohnny Chen 
639e9a5627eSJohnny Chen         // There is only one variant this argument could be; put it into the argument entry.
640e9a5627eSJohnny Chen         arg.push_back (wp_id_arg);
641e9a5627eSJohnny Chen 
642e9a5627eSJohnny Chen         // Push the data for the first argument into the m_arguments vector.
643e9a5627eSJohnny Chen         m_arguments.push_back (arg);
644e9a5627eSJohnny Chen     }
645e9a5627eSJohnny Chen 
646e9a5627eSJohnny Chen 
647e9a5627eSJohnny Chen     virtual
648e9a5627eSJohnny Chen     ~CommandObjectWatchpointCommandDelete () {}
649e9a5627eSJohnny Chen 
650e9a5627eSJohnny Chen protected:
651e9a5627eSJohnny Chen     virtual bool
652e9a5627eSJohnny Chen     DoExecute (Args& command, CommandReturnObject &result)
653e9a5627eSJohnny Chen     {
654e9a5627eSJohnny Chen         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
655e9a5627eSJohnny Chen 
656e9a5627eSJohnny Chen         if (target == NULL)
657e9a5627eSJohnny Chen         {
658e9a5627eSJohnny Chen             result.AppendError ("There is not a current executable; there are no watchpoints from which to delete commands");
659e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
660e9a5627eSJohnny Chen             return false;
661e9a5627eSJohnny Chen         }
662e9a5627eSJohnny Chen 
663e9a5627eSJohnny Chen         const WatchpointList &watchpoints = target->GetWatchpointList();
664e9a5627eSJohnny Chen         size_t num_watchpoints = watchpoints.GetSize();
665e9a5627eSJohnny Chen 
666e9a5627eSJohnny Chen         if (num_watchpoints == 0)
667e9a5627eSJohnny Chen         {
668e9a5627eSJohnny Chen             result.AppendError ("No watchpoints exist to have commands deleted");
669e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
670e9a5627eSJohnny Chen             return false;
671e9a5627eSJohnny Chen         }
672e9a5627eSJohnny Chen 
673e9a5627eSJohnny Chen         if (command.GetArgumentCount() == 0)
674e9a5627eSJohnny Chen         {
675e9a5627eSJohnny Chen             result.AppendError ("No watchpoint specified from which to delete the commands");
676e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
677e9a5627eSJohnny Chen             return false;
678e9a5627eSJohnny Chen         }
679e9a5627eSJohnny Chen 
680e9a5627eSJohnny Chen         std::vector<uint32_t> valid_wp_ids;
681e9a5627eSJohnny Chen         if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(command, valid_wp_ids))
682e9a5627eSJohnny Chen         {
683e9a5627eSJohnny Chen             result.AppendError("Invalid watchpoints specification.");
684e9a5627eSJohnny Chen             result.SetStatus(eReturnStatusFailed);
685e9a5627eSJohnny Chen             return false;
686e9a5627eSJohnny Chen         }
687e9a5627eSJohnny Chen 
688e9a5627eSJohnny Chen         result.SetStatus(eReturnStatusSuccessFinishNoResult);
689e9a5627eSJohnny Chen         const size_t count = valid_wp_ids.size();
690e9a5627eSJohnny Chen         for (size_t i = 0; i < count; ++i)
691e9a5627eSJohnny Chen         {
692e9a5627eSJohnny Chen             uint32_t cur_wp_id = valid_wp_ids.at (i);
693e9a5627eSJohnny Chen             if (cur_wp_id != LLDB_INVALID_WATCH_ID)
694e9a5627eSJohnny Chen             {
695e9a5627eSJohnny Chen                 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
696e9a5627eSJohnny Chen                 if (wp)
697e9a5627eSJohnny Chen                     wp->ClearCallback();
698e9a5627eSJohnny Chen             }
699e9a5627eSJohnny Chen             else
700e9a5627eSJohnny Chen             {
701e9a5627eSJohnny Chen                 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
702e9a5627eSJohnny Chen                                              cur_wp_id);
703e9a5627eSJohnny Chen                 result.SetStatus (eReturnStatusFailed);
704e9a5627eSJohnny Chen                 return false;
705e9a5627eSJohnny Chen             }
706e9a5627eSJohnny Chen         }
707e9a5627eSJohnny Chen         return result.Succeeded();
708e9a5627eSJohnny Chen     }
709e9a5627eSJohnny Chen };
710e9a5627eSJohnny Chen 
711e9a5627eSJohnny Chen //-------------------------------------------------------------------------
712e9a5627eSJohnny Chen // CommandObjectWatchpointCommandList
713e9a5627eSJohnny Chen //-------------------------------------------------------------------------
714e9a5627eSJohnny Chen 
715e9a5627eSJohnny Chen class CommandObjectWatchpointCommandList : public CommandObjectParsed
716e9a5627eSJohnny Chen {
717e9a5627eSJohnny Chen public:
718e9a5627eSJohnny Chen     CommandObjectWatchpointCommandList (CommandInterpreter &interpreter) :
719e9a5627eSJohnny Chen         CommandObjectParsed (interpreter,
720e9a5627eSJohnny Chen                              "list",
721e9a5627eSJohnny Chen                              "List the script or set of commands to be executed when the watchpoint is hit.",
722e9a5627eSJohnny Chen                               NULL)
723e9a5627eSJohnny Chen     {
724e9a5627eSJohnny Chen         CommandArgumentEntry arg;
725e9a5627eSJohnny Chen         CommandArgumentData wp_id_arg;
726e9a5627eSJohnny Chen 
727e9a5627eSJohnny Chen         // Define the first (and only) variant of this arg.
728e9a5627eSJohnny Chen         wp_id_arg.arg_type = eArgTypeWatchpointID;
729e9a5627eSJohnny Chen         wp_id_arg.arg_repetition = eArgRepeatPlain;
730e9a5627eSJohnny Chen 
731e9a5627eSJohnny Chen         // There is only one variant this argument could be; put it into the argument entry.
732e9a5627eSJohnny Chen         arg.push_back (wp_id_arg);
733e9a5627eSJohnny Chen 
734e9a5627eSJohnny Chen         // Push the data for the first argument into the m_arguments vector.
735e9a5627eSJohnny Chen         m_arguments.push_back (arg);
736e9a5627eSJohnny Chen     }
737e9a5627eSJohnny Chen 
738e9a5627eSJohnny Chen     virtual
739e9a5627eSJohnny Chen     ~CommandObjectWatchpointCommandList () {}
740e9a5627eSJohnny Chen 
741e9a5627eSJohnny Chen protected:
742e9a5627eSJohnny Chen     virtual bool
743e9a5627eSJohnny Chen     DoExecute (Args& command,
744e9a5627eSJohnny Chen              CommandReturnObject &result)
745e9a5627eSJohnny Chen     {
746e9a5627eSJohnny Chen         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
747e9a5627eSJohnny Chen 
748e9a5627eSJohnny Chen         if (target == NULL)
749e9a5627eSJohnny Chen         {
750e9a5627eSJohnny Chen             result.AppendError ("There is not a current executable; there are no watchpoints for which to list commands");
751e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
752e9a5627eSJohnny Chen             return false;
753e9a5627eSJohnny Chen         }
754e9a5627eSJohnny Chen 
755e9a5627eSJohnny Chen         const WatchpointList &watchpoints = target->GetWatchpointList();
756e9a5627eSJohnny Chen         size_t num_watchpoints = watchpoints.GetSize();
757e9a5627eSJohnny Chen 
758e9a5627eSJohnny Chen         if (num_watchpoints == 0)
759e9a5627eSJohnny Chen         {
760e9a5627eSJohnny Chen             result.AppendError ("No watchpoints exist for which to list commands");
761e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
762e9a5627eSJohnny Chen             return false;
763e9a5627eSJohnny Chen         }
764e9a5627eSJohnny Chen 
765e9a5627eSJohnny Chen         if (command.GetArgumentCount() == 0)
766e9a5627eSJohnny Chen         {
767e9a5627eSJohnny Chen             result.AppendError ("No watchpoint specified for which to list the commands");
768e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
769e9a5627eSJohnny Chen             return false;
770e9a5627eSJohnny Chen         }
771e9a5627eSJohnny Chen 
772e9a5627eSJohnny Chen         std::vector<uint32_t> valid_wp_ids;
773e9a5627eSJohnny Chen         if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(command, valid_wp_ids))
774e9a5627eSJohnny Chen         {
775e9a5627eSJohnny Chen             result.AppendError("Invalid watchpoints specification.");
776e9a5627eSJohnny Chen             result.SetStatus(eReturnStatusFailed);
777e9a5627eSJohnny Chen             return false;
778e9a5627eSJohnny Chen         }
779e9a5627eSJohnny Chen 
780e9a5627eSJohnny Chen         result.SetStatus(eReturnStatusSuccessFinishNoResult);
781e9a5627eSJohnny Chen         const size_t count = valid_wp_ids.size();
782e9a5627eSJohnny Chen         for (size_t i = 0; i < count; ++i)
783e9a5627eSJohnny Chen         {
784e9a5627eSJohnny Chen             uint32_t cur_wp_id = valid_wp_ids.at (i);
785e9a5627eSJohnny Chen             if (cur_wp_id != LLDB_INVALID_WATCH_ID)
786e9a5627eSJohnny Chen             {
787e9a5627eSJohnny Chen                 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
788e9a5627eSJohnny Chen 
789e9a5627eSJohnny Chen                 if (wp)
790e9a5627eSJohnny Chen                 {
791e9a5627eSJohnny Chen                     const WatchpointOptions *wp_options = wp->GetOptions();
792e9a5627eSJohnny Chen                     if (wp_options)
793e9a5627eSJohnny Chen                     {
794e9a5627eSJohnny Chen                         // Get the callback baton associated with the current watchpoint.
795e9a5627eSJohnny Chen                         const Baton *baton = wp_options->GetBaton();
796e9a5627eSJohnny Chen                         if (baton)
797e9a5627eSJohnny Chen                         {
798e9a5627eSJohnny Chen                             result.GetOutputStream().Printf ("Watchpoint %u:\n", cur_wp_id);
799e9a5627eSJohnny Chen                             result.GetOutputStream().IndentMore ();
800e9a5627eSJohnny Chen                             baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
801e9a5627eSJohnny Chen                             result.GetOutputStream().IndentLess ();
802e9a5627eSJohnny Chen                         }
803e9a5627eSJohnny Chen                         else
804e9a5627eSJohnny Chen                         {
805e9a5627eSJohnny Chen                             result.AppendMessageWithFormat ("Watchpoint %u does not have an associated command.\n",
806e9a5627eSJohnny Chen                                                             cur_wp_id);
807e9a5627eSJohnny Chen                         }
808e9a5627eSJohnny Chen                     }
809e9a5627eSJohnny Chen                     result.SetStatus (eReturnStatusSuccessFinishResult);
810e9a5627eSJohnny Chen                 }
811e9a5627eSJohnny Chen                 else
812e9a5627eSJohnny Chen                 {
813e9a5627eSJohnny Chen                     result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
814e9a5627eSJohnny Chen                     result.SetStatus (eReturnStatusFailed);
815e9a5627eSJohnny Chen                 }
816e9a5627eSJohnny Chen             }
817e9a5627eSJohnny Chen         }
818e9a5627eSJohnny Chen 
819e9a5627eSJohnny Chen         return result.Succeeded();
820e9a5627eSJohnny Chen     }
821e9a5627eSJohnny Chen };
822e9a5627eSJohnny Chen 
823e9a5627eSJohnny Chen //-------------------------------------------------------------------------
824e9a5627eSJohnny Chen // CommandObjectWatchpointCommand
825e9a5627eSJohnny Chen //-------------------------------------------------------------------------
826e9a5627eSJohnny Chen 
827e9a5627eSJohnny Chen CommandObjectWatchpointCommand::CommandObjectWatchpointCommand (CommandInterpreter &interpreter) :
828e9a5627eSJohnny Chen     CommandObjectMultiword (interpreter,
829e9a5627eSJohnny Chen                             "command",
830e9a5627eSJohnny Chen                             "A set of commands for adding, removing and examining bits of code to be executed when the watchpoint is hit (watchpoint 'commmands').",
831e9a5627eSJohnny Chen                             "command <sub-command> [<sub-command-options>] <watchpoint-id>")
832e9a5627eSJohnny Chen {
833e9a5627eSJohnny Chen     CommandObjectSP add_command_object (new CommandObjectWatchpointCommandAdd (interpreter));
834e9a5627eSJohnny Chen     CommandObjectSP delete_command_object (new CommandObjectWatchpointCommandDelete (interpreter));
835e9a5627eSJohnny Chen     CommandObjectSP list_command_object (new CommandObjectWatchpointCommandList (interpreter));
836e9a5627eSJohnny Chen 
837e9a5627eSJohnny Chen     add_command_object->SetCommandName ("watchpoint command add");
838e9a5627eSJohnny Chen     delete_command_object->SetCommandName ("watchpoint command delete");
839e9a5627eSJohnny Chen     list_command_object->SetCommandName ("watchpoint command list");
840e9a5627eSJohnny Chen 
841*03da4cc2SGreg Clayton     LoadSubCommand ("add",    add_command_object);
842*03da4cc2SGreg Clayton     LoadSubCommand ("delete", delete_command_object);
843*03da4cc2SGreg Clayton     LoadSubCommand ("list",   list_command_object);
844e9a5627eSJohnny Chen }
845e9a5627eSJohnny Chen 
846e9a5627eSJohnny Chen CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand ()
847e9a5627eSJohnny Chen {
848e9a5627eSJohnny Chen }
849e9a5627eSJohnny Chen 
850e9a5627eSJohnny Chen 
851