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