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