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