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
30using namespace lldb;
31using namespace lldb_private;
32
33//-------------------------------------------------------------------------
34// CommandObjectWatchpointCommandAdd
35//-------------------------------------------------------------------------
36
37
38class CommandObjectWatchpointCommandAdd :
39    public CommandObjectParsed,
40    public IOHandlerDelegateMultiline
41{
42public:
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\
56This command will cause you to be prompted to enter the command or set \n\
57of commands you wish to be executed when the specified watchpoint is \n\
58hit.  You will be told to enter your command(s), and will see a '> ' \n\
59prompt. Because you can enter one or many commands to be executed when \n\
60a watchpoint is hit, you will continue to be prompted after each \n\
61new-line that you enter, until you enter the word 'DONE', which will \n\
62cause the commands you have entered to be stored with the watchpoint \n\
63and executed when the watchpoint is hit. \n\
64 \n\
65Syntax checking is not necessarily done when watchpoint commands are \n\
66entered.  An improperly written watchpoint command will attempt to get \n\
67executed when the watchpoint gets hit, and usually silently fail.  If \n\
68your watchpoint command does not appear to be getting executed, go \n\
69back and check your syntax. \n\
70 \n\
71 \n\
72Special information about PYTHON watchpoint commands                            \n\
73----------------------------------------------------                            \n\
74                                                                                \n\
75You 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\
77single 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\
79definitions, they will be passed to the Python interpreter as soon as           \n\
80you finish entering the watchpoint command, and they can be called              \n\
81later (don't forget to add calls to them, if you want them called when          \n\
82the watchpoint is hit).  If you enter multiple lines of Python that             \n\
83are not function definitions, they will be collected into a new,                \n\
84automatically generated Python function, and a call to the newly                \n\
85generated function will be attached to the watchpoint.                          \n\
86                                                                                \n\
87This 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\
93Important Note: Because loose Python code gets collected into functions,        \n\
94if you want to access global variables in the 'loose' code, you need to         \n\
95specify that they are global, using the 'global' keyword.  Be sure to           \n\
96use correct Python syntax, including indentation, when entering Python          \n\
97watchpoint commands.                                                            \n\
98                                                                                \n\
99As a third option, you can pass the name of an already existing Python function \n\
100and that function will be attached to the watchpoint. It will get passed the    \n\
101frame and wp_loc arguments mentioned above.                                     \n\
102                                                                                \n\
103Example Python one-line watchpoint command: \n\
104 \n\
105(lldb) watchpoint command add -s python 1 \n\
106Enter your Python command(s). Type 'DONE' to end. \n\
107> print \"Hit this watchpoint!\" \n\
108> DONE \n\
109 \n\
110As 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\
113Launching '.../a.out'  (x86_64) \n\
114(lldb) Fri Sep 10 12:17:45 2010 \n\
115Process 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\
126Example multiple line Python watchpoint command, using function definition: \n\
127 \n\
128(lldb) watchpoint command add -s python 1 \n\
129Enter 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\
138Example multiple line Python watchpoint command, using 'loose' Python: \n\
139 \n\
140(lldb) watchpoint command add -s p 1 \n\
141Enter 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\
147In 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\
149initialized: \n\
150 \n\
151(lldb) script \n\
152>>> wp_count = 0 \n\
153>>> quit() \n\
154 \n\
155(lldb)  \n\
156 \n\
157 \n\
158Final Note:  If you get a warning that no watchpoint command was generated, \n\
159but you did not get any syntax errors, you probably forgot to add a call \n\
160to your functions. \n\
161 \n\
162Special information about debugger command watchpoint commands \n\
163-------------------------------------------------------------- \n\
164 \n\
165You may enter any debugger command, exactly as you would at the \n\
166debugger prompt.  You may enter as many debugger commands as you like, \n\
167but 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
406protected:
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
502private:
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
510static OptionEnumValueElement
511g_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
519OptionDefinition
520CommandObjectWatchpointCommandAdd::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
541class CommandObjectWatchpointCommandDelete : public CommandObjectParsed
542{
543public:
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
568protected:
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
633class CommandObjectWatchpointCommandList : public CommandObjectParsed
634{
635public:
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
659protected:
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
745CommandObjectWatchpointCommand::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
764CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand ()
765{
766}
767
768
769