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