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