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