]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/llvm/tools/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.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                 bool stop_on_continue = true;
283                 bool echo_commands    = false;
284                 bool print_results    = true;
285
286                 debugger.GetCommandInterpreter().HandleCommands (commands, 
287                                                                  &exe_ctx,
288                                                                  stop_on_continue, 
289                                                                  data->stop_on_error, 
290                                                                  echo_commands, 
291                                                                  print_results,
292                                                                  eLazyBoolNo,
293                                                                  result);
294                 result.GetImmediateOutputStream()->Flush();
295                 result.GetImmediateErrorStream()->Flush();
296            }
297         }
298         return ret_value;
299     }    
300
301     class CommandOptions : public Options
302     {
303     public:
304
305         CommandOptions (CommandInterpreter &interpreter) :
306             Options (interpreter),
307             m_use_commands (false),
308             m_use_script_language (false),
309             m_script_language (eScriptLanguageNone),
310             m_use_one_liner (false),
311             m_one_liner(),
312             m_function_name()
313         {
314         }
315
316         virtual
317         ~CommandOptions () {}
318
319         virtual Error
320         SetOptionValue (uint32_t option_idx, const char *option_arg)
321         {
322             Error error;
323             const int short_option = m_getopt_table[option_idx].val;
324
325             switch (short_option)
326             {
327             case 'o':
328                 m_use_one_liner = true;
329                 m_one_liner = option_arg;
330                 break;
331
332             case 's':
333                 m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg, 
334                                                                                      g_option_table[option_idx].enum_values, 
335                                                                                      eScriptLanguageNone,
336                                                                                      error);
337
338                 if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
339                 {
340                     m_use_script_language = true;
341                 }
342                 else
343                 {
344                     m_use_script_language = false;
345                 }          
346                 break;
347
348             case 'e':
349                 {
350                     bool success = false;
351                     m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
352                     if (!success)
353                         error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
354                 }
355                 break;
356                     
357             case 'F':
358                 {
359                     m_use_one_liner = false;
360                     m_use_script_language = true;
361                     m_function_name.assign(option_arg);
362                 }
363                 break;
364
365             default:
366                 break;
367             }
368             return error;
369         }
370         void
371         OptionParsingStarting ()
372         {
373             m_use_commands = true;
374             m_use_script_language = false;
375             m_script_language = eScriptLanguageNone;
376
377             m_use_one_liner = false;
378             m_stop_on_error = true;
379             m_one_liner.clear();
380             m_function_name.clear();
381         }
382
383         const OptionDefinition*
384         GetDefinitions ()
385         {
386             return g_option_table;
387         }
388
389         // Options table: Required for subclasses of Options.
390
391         static OptionDefinition g_option_table[];
392
393         // Instance variables to hold the values for command options.
394
395         bool m_use_commands;
396         bool m_use_script_language;
397         lldb::ScriptLanguage m_script_language;
398
399         // Instance variables to hold the values for one_liner options.
400         bool m_use_one_liner;
401         std::string m_one_liner;
402         bool m_stop_on_error;
403         std::string m_function_name;
404     };
405
406 protected:
407     virtual bool
408     DoExecute (Args& command, CommandReturnObject &result)
409     {
410         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
411
412         if (target == NULL)
413         {
414             result.AppendError ("There is not a current executable; there are no watchpoints to which to add commands");
415             result.SetStatus (eReturnStatusFailed);
416             return false;
417         }
418
419         const WatchpointList &watchpoints = target->GetWatchpointList();
420         size_t num_watchpoints = watchpoints.GetSize();
421
422         if (num_watchpoints == 0)
423         {
424             result.AppendError ("No watchpoints exist to have commands added");
425             result.SetStatus (eReturnStatusFailed);
426             return false;
427         }
428
429         if (m_options.m_use_script_language == false && m_options.m_function_name.size())
430         {
431             result.AppendError ("need to enable scripting to have a function run as a watchpoint command");
432             result.SetStatus (eReturnStatusFailed);
433             return false;
434         }
435         
436         std::vector<uint32_t> valid_wp_ids;
437         if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
438         {
439             result.AppendError("Invalid watchpoints specification.");
440             result.SetStatus(eReturnStatusFailed);
441             return false;
442         }
443
444         result.SetStatus(eReturnStatusSuccessFinishNoResult);
445         const size_t count = valid_wp_ids.size();
446         for (size_t i = 0; i < count; ++i)
447         {
448             uint32_t cur_wp_id = valid_wp_ids.at (i);
449             if (cur_wp_id != LLDB_INVALID_WATCH_ID)
450             {
451                 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
452                 // Sanity check wp first.
453                 if (wp == NULL) continue;
454
455                 WatchpointOptions *wp_options = wp->GetOptions();
456                 // Skip this watchpoint if wp_options is not good.
457                 if (wp_options == NULL) continue;
458
459                 // If we are using script language, get the script interpreter
460                 // in order to set or collect command callback.  Otherwise, call
461                 // the methods associated with this object.
462                 if (m_options.m_use_script_language)
463                 {
464                     // Special handling for one-liner specified inline.
465                     if (m_options.m_use_one_liner)
466                     {
467                         m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
468                                                                                             m_options.m_one_liner.c_str());
469                     }
470                     // Special handling for using a Python function by name
471                     // instead of extending the watchpoint callback data structures, we just automatize
472                     // what the user would do manually: make their watchpoint command be a function call
473                     else if (m_options.m_function_name.size())
474                     {
475                         std::string oneliner(m_options.m_function_name);
476                         oneliner += "(frame, wp, internal_dict)";
477                         m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
478                                                                                             oneliner.c_str());
479                     }
480                     else
481                     {
482                         m_interpreter.GetScriptInterpreter()->CollectDataForWatchpointCommandCallback (wp_options,
483                                                                                                        result);
484                     }
485                 }
486                 else
487                 {
488                     // Special handling for one-liner specified inline.
489                     if (m_options.m_use_one_liner)
490                         SetWatchpointCommandCallback (wp_options,
491                                                       m_options.m_one_liner.c_str());
492                     else
493                         CollectDataForWatchpointCommandCallback (wp_options, 
494                                                                  result);
495                 }
496             }
497         }
498
499         return result.Succeeded();
500     }
501
502 private:
503     CommandOptions m_options;
504 };
505
506
507 // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
508 // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
509
510 static OptionEnumValueElement
511 g_script_option_enumeration[4] =
512 {
513     { eScriptLanguageNone,    "command",         "Commands are in the lldb command interpreter language"},
514     { eScriptLanguagePython,  "python",          "Commands are in the Python language."},
515     { eSortOrderByName,       "default-script",  "Commands are in the default scripting language."},
516     { 0,                      NULL,              NULL }
517 };
518
519 OptionDefinition
520 CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] =
521 {
522     { LLDB_OPT_SET_1,   false, "one-liner",       'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOneLiner,
523         "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." },
524
525     { LLDB_OPT_SET_ALL, false, "stop-on-error",   'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeBoolean,
526         "Specify whether watchpoint command execution should terminate on error." },
527
528     { LLDB_OPT_SET_ALL, false, "script-type",     's', OptionParser::eRequiredArgument, g_script_option_enumeration, 0, eArgTypeNone,
529         "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
530
531     { LLDB_OPT_SET_2,   false, "python-function", 'F', OptionParser::eRequiredArgument, NULL, 0, eArgTypePythonFunction,
532         "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."},
533     
534     { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
535 };
536
537 //-------------------------------------------------------------------------
538 // CommandObjectWatchpointCommandDelete
539 //-------------------------------------------------------------------------
540
541 class CommandObjectWatchpointCommandDelete : public CommandObjectParsed
542 {
543 public:
544     CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) :
545         CommandObjectParsed (interpreter, 
546                              "delete",
547                              "Delete the set of commands from a watchpoint.",
548                              NULL)
549     {
550         CommandArgumentEntry arg;
551         CommandArgumentData wp_id_arg;
552
553         // Define the first (and only) variant of this arg.
554         wp_id_arg.arg_type = eArgTypeWatchpointID;
555         wp_id_arg.arg_repetition = eArgRepeatPlain;
556
557         // There is only one variant this argument could be; put it into the argument entry.
558         arg.push_back (wp_id_arg);
559
560         // Push the data for the first argument into the m_arguments vector.
561         m_arguments.push_back (arg);
562     }
563
564
565     virtual
566     ~CommandObjectWatchpointCommandDelete () {}
567
568 protected:
569     virtual bool
570     DoExecute (Args& command, CommandReturnObject &result)
571     {
572         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
573
574         if (target == NULL)
575         {
576             result.AppendError ("There is not a current executable; there are no watchpoints from which to delete commands");
577             result.SetStatus (eReturnStatusFailed);
578             return false;
579         }
580
581         const WatchpointList &watchpoints = target->GetWatchpointList();
582         size_t num_watchpoints = watchpoints.GetSize();
583
584         if (num_watchpoints == 0)
585         {
586             result.AppendError ("No watchpoints exist to have commands deleted");
587             result.SetStatus (eReturnStatusFailed);
588             return false;
589         }
590
591         if (command.GetArgumentCount() == 0)
592         {
593             result.AppendError ("No watchpoint specified from which to delete the commands");
594             result.SetStatus (eReturnStatusFailed);
595             return false;
596         }
597
598         std::vector<uint32_t> valid_wp_ids;
599         if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
600         {
601             result.AppendError("Invalid watchpoints specification.");
602             result.SetStatus(eReturnStatusFailed);
603             return false;
604         }
605
606         result.SetStatus(eReturnStatusSuccessFinishNoResult);
607         const size_t count = valid_wp_ids.size();
608         for (size_t i = 0; i < count; ++i)
609         {
610             uint32_t cur_wp_id = valid_wp_ids.at (i);
611             if (cur_wp_id != LLDB_INVALID_WATCH_ID)
612             {
613                 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
614                 if (wp)
615                     wp->ClearCallback();
616             }
617             else
618             {
619                 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", 
620                                              cur_wp_id);
621                 result.SetStatus (eReturnStatusFailed);
622                 return false;
623             }
624         }
625         return result.Succeeded();
626     }
627 };
628
629 //-------------------------------------------------------------------------
630 // CommandObjectWatchpointCommandList
631 //-------------------------------------------------------------------------
632
633 class CommandObjectWatchpointCommandList : public CommandObjectParsed
634 {
635 public:
636     CommandObjectWatchpointCommandList (CommandInterpreter &interpreter) :
637         CommandObjectParsed (interpreter,
638                              "list",
639                              "List the script or set of commands to be executed when the watchpoint is hit.",
640                               NULL)
641     {
642         CommandArgumentEntry arg;
643         CommandArgumentData wp_id_arg;
644
645         // Define the first (and only) variant of this arg.
646         wp_id_arg.arg_type = eArgTypeWatchpointID;
647         wp_id_arg.arg_repetition = eArgRepeatPlain;
648
649         // There is only one variant this argument could be; put it into the argument entry.
650         arg.push_back (wp_id_arg);
651
652         // Push the data for the first argument into the m_arguments vector.
653         m_arguments.push_back (arg);
654     }
655
656     virtual
657     ~CommandObjectWatchpointCommandList () {}
658
659 protected:
660     virtual bool
661     DoExecute (Args& command,
662              CommandReturnObject &result)
663     {
664         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
665
666         if (target == NULL)
667         {
668             result.AppendError ("There is not a current executable; there are no watchpoints for which to list commands");
669             result.SetStatus (eReturnStatusFailed);
670             return false;
671         }
672
673         const WatchpointList &watchpoints = target->GetWatchpointList();
674         size_t num_watchpoints = watchpoints.GetSize();
675
676         if (num_watchpoints == 0)
677         {
678             result.AppendError ("No watchpoints exist for which to list commands");
679             result.SetStatus (eReturnStatusFailed);
680             return false;
681         }
682
683         if (command.GetArgumentCount() == 0)
684         {
685             result.AppendError ("No watchpoint specified for which to list the commands");
686             result.SetStatus (eReturnStatusFailed);
687             return false;
688         }
689
690         std::vector<uint32_t> valid_wp_ids;
691         if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
692         {
693             result.AppendError("Invalid watchpoints specification.");
694             result.SetStatus(eReturnStatusFailed);
695             return false;
696         }
697
698         result.SetStatus(eReturnStatusSuccessFinishNoResult);
699         const size_t count = valid_wp_ids.size();
700         for (size_t i = 0; i < count; ++i)
701         {
702             uint32_t cur_wp_id = valid_wp_ids.at (i);
703             if (cur_wp_id != LLDB_INVALID_WATCH_ID)
704             {
705                 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
706                 
707                 if (wp)
708                 {
709                     const WatchpointOptions *wp_options = wp->GetOptions();
710                     if (wp_options)
711                     {
712                         // Get the callback baton associated with the current watchpoint.
713                         const Baton *baton = wp_options->GetBaton();
714                         if (baton)
715                         {
716                             result.GetOutputStream().Printf ("Watchpoint %u:\n", cur_wp_id);
717                             result.GetOutputStream().IndentMore ();
718                             baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
719                             result.GetOutputStream().IndentLess ();
720                         }
721                         else
722                         {
723                             result.AppendMessageWithFormat ("Watchpoint %u does not have an associated command.\n", 
724                                                             cur_wp_id);
725                         }
726                     }
727                     result.SetStatus (eReturnStatusSuccessFinishResult);
728                 }
729                 else
730                 {
731                     result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
732                     result.SetStatus (eReturnStatusFailed);
733                 }
734             }
735         }
736
737         return result.Succeeded();
738     }
739 };
740
741 //-------------------------------------------------------------------------
742 // CommandObjectWatchpointCommand
743 //-------------------------------------------------------------------------
744
745 CommandObjectWatchpointCommand::CommandObjectWatchpointCommand (CommandInterpreter &interpreter) :
746     CommandObjectMultiword (interpreter,
747                             "command",
748                             "A set of commands for adding, removing and examining bits of code to be executed when the watchpoint is hit (watchpoint 'commmands').",
749                             "command <sub-command> [<sub-command-options>] <watchpoint-id>")
750 {
751     CommandObjectSP add_command_object (new CommandObjectWatchpointCommandAdd (interpreter));
752     CommandObjectSP delete_command_object (new CommandObjectWatchpointCommandDelete (interpreter));
753     CommandObjectSP list_command_object (new CommandObjectWatchpointCommandList (interpreter));
754
755     add_command_object->SetCommandName ("watchpoint command add");
756     delete_command_object->SetCommandName ("watchpoint command delete");
757     list_command_object->SetCommandName ("watchpoint command list");
758
759     LoadSubCommand ("add",    add_command_object);
760     LoadSubCommand ("delete", delete_command_object);
761     LoadSubCommand ("list",   list_command_object);
762 }
763
764 CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand ()
765 {
766 }
767
768