1e9a5627eSJohnny Chen //===-- CommandObjectWatchpointCommand.cpp ----------------------*- C++ -*-===//
2e9a5627eSJohnny Chen //
3e9a5627eSJohnny Chen //                     The LLVM Compiler Infrastructure
4e9a5627eSJohnny Chen //
5e9a5627eSJohnny Chen // This file is distributed under the University of Illinois Open Source
6e9a5627eSJohnny Chen // License. See LICENSE.TXT for details.
7e9a5627eSJohnny Chen //
8e9a5627eSJohnny Chen //===----------------------------------------------------------------------===//
9e9a5627eSJohnny Chen 
10e9a5627eSJohnny Chen // C Includes
11e9a5627eSJohnny Chen // C++ Includes
12*49bcfd80SEugene Zelenko #include <vector>
13e9a5627eSJohnny Chen 
14*49bcfd80SEugene Zelenko // Other libraries and framework includes
15*49bcfd80SEugene Zelenko // Project includes
16e9a5627eSJohnny Chen #include "CommandObjectWatchpointCommand.h"
17e9a5627eSJohnny Chen #include "CommandObjectWatchpoint.h"
1844d93782SGreg Clayton #include "lldb/Core/IOHandler.h"
19e9a5627eSJohnny Chen #include "lldb/Interpreter/CommandInterpreter.h"
20e9a5627eSJohnny Chen #include "lldb/Interpreter/CommandReturnObject.h"
21e9a5627eSJohnny Chen #include "lldb/Target/Target.h"
22e9a5627eSJohnny Chen #include "lldb/Target/Thread.h"
23e9a5627eSJohnny Chen #include "lldb/Breakpoint/Watchpoint.h"
24e9a5627eSJohnny Chen #include "lldb/Breakpoint/StoppointCallbackContext.h"
25e9a5627eSJohnny Chen #include "lldb/Core/State.h"
26e9a5627eSJohnny Chen 
27e9a5627eSJohnny Chen using namespace lldb;
28e9a5627eSJohnny Chen using namespace lldb_private;
29e9a5627eSJohnny Chen 
30e9a5627eSJohnny Chen //-------------------------------------------------------------------------
31e9a5627eSJohnny Chen // CommandObjectWatchpointCommandAdd
32e9a5627eSJohnny Chen //-------------------------------------------------------------------------
33e9a5627eSJohnny Chen 
3444d93782SGreg Clayton class CommandObjectWatchpointCommandAdd :
3544d93782SGreg Clayton     public CommandObjectParsed,
3644d93782SGreg Clayton     public IOHandlerDelegateMultiline
37e9a5627eSJohnny Chen {
38e9a5627eSJohnny Chen public:
39e9a5627eSJohnny Chen     CommandObjectWatchpointCommandAdd (CommandInterpreter &interpreter) :
40e9a5627eSJohnny Chen         CommandObjectParsed(interpreter,
41e9a5627eSJohnny Chen                             "add",
42e9a5627eSJohnny Chen                             "Add a set of commands to a watchpoint, to be executed whenever the watchpoint is hit.",
43*49bcfd80SEugene Zelenko                             nullptr),
44c3d874a5SGreg Clayton         IOHandlerDelegateMultiline("DONE", IOHandlerDelegate::Completion::LLDBCommand),
45e9a5627eSJohnny Chen         m_options (interpreter)
46e9a5627eSJohnny Chen     {
47e9a5627eSJohnny Chen         SetHelpLong (
48ea671fbdSKate Stone R"(
49ea671fbdSKate Stone General information about entering watchpoint commands
50ea671fbdSKate Stone ------------------------------------------------------
51ea671fbdSKate Stone 
52ea671fbdSKate Stone )" "This command will prompt for commands to be executed when the specified \
53ea671fbdSKate Stone watchpoint is hit.  Each command is typed on its own line following the '> ' \
54ea671fbdSKate Stone prompt until 'DONE' is entered." R"(
55ea671fbdSKate Stone 
56ea671fbdSKate Stone )" "Syntactic errors may not be detected when initially entered, and many \
57ea671fbdSKate Stone malformed commands can silently fail when executed.  If your watchpoint commands \
58ea671fbdSKate Stone do not appear to be executing, double-check the command syntax." R"(
59ea671fbdSKate Stone 
60ea671fbdSKate Stone )" "Note: You may enter any debugger command exactly as you would at the debugger \
61ea671fbdSKate Stone prompt.  There is no limit to the number of commands supplied, but do NOT enter \
62ea671fbdSKate Stone more than one command per line." R"(
63ea671fbdSKate Stone 
64ea671fbdSKate Stone Special information about PYTHON watchpoint commands
65ea671fbdSKate Stone ----------------------------------------------------
66ea671fbdSKate Stone 
67ea671fbdSKate Stone )" "You may enter either one or more lines of Python, including function \
68ea671fbdSKate Stone definitions or calls to functions that will have been imported by the time \
69ea671fbdSKate Stone the code executes.  Single line watchpoint commands will be interpreted 'as is' \
70ea671fbdSKate Stone when the watchpoint is hit.  Multiple lines of Python will be wrapped in a \
71ea671fbdSKate Stone generated function, and a call to the function will be attached to the watchpoint." R"(
72ea671fbdSKate Stone 
73ea671fbdSKate Stone This auto-generated function is passed in three arguments:
74ea671fbdSKate Stone 
75ea671fbdSKate Stone     frame:  an lldb.SBFrame object for the frame which hit the watchpoint.
76ea671fbdSKate Stone 
77ea671fbdSKate Stone     wp:     the watchpoint that was hit.
78ea671fbdSKate Stone 
79ea671fbdSKate Stone )" "When specifying a python function with the --python-function option, you need \
80ea671fbdSKate Stone to supply the function name prepended by the module name:" R"(
81ea671fbdSKate Stone 
82ea671fbdSKate Stone     --python-function myutils.watchpoint_callback
83ea671fbdSKate Stone 
84ea671fbdSKate Stone The function itself must have the following prototype:
85ea671fbdSKate Stone 
86ea671fbdSKate Stone def watchpoint_callback(frame, wp):
87ea671fbdSKate Stone   # Your code goes here
88ea671fbdSKate Stone 
89ea671fbdSKate Stone )" "The arguments are the same as the arguments passed to generated functions as \
90ea671fbdSKate Stone described above.  Note that the global variable 'lldb.frame' will NOT be updated when \
91ea671fbdSKate Stone this function is called, so be sure to use the 'frame' argument. The 'frame' argument \
92ea671fbdSKate Stone can get you to the thread via frame.GetThread(), the thread can get you to the \
93ea671fbdSKate Stone process via thread.GetProcess(), and the process can get you back to the target \
94ea671fbdSKate Stone via process.GetTarget()." R"(
95ea671fbdSKate Stone 
96ea671fbdSKate Stone )" "Important Note: As Python code gets collected into functions, access to global \
97ea671fbdSKate Stone variables requires explicit scoping using the 'global' keyword.  Be sure to use correct \
98ea671fbdSKate Stone Python syntax, including indentation, when entering Python watchpoint commands." R"(
99ea671fbdSKate Stone 
100ea671fbdSKate Stone Example Python one-line watchpoint command:
101ea671fbdSKate Stone 
102ea671fbdSKate Stone (lldb) watchpoint command add -s python 1
103ea671fbdSKate Stone Enter your Python command(s). Type 'DONE' to end.
104ea671fbdSKate Stone > print "Hit this watchpoint!"
105ea671fbdSKate Stone > DONE
106ea671fbdSKate Stone 
107ea671fbdSKate Stone As a convenience, this also works for a short Python one-liner:
108ea671fbdSKate Stone 
109ea671fbdSKate Stone (lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()'
110ea671fbdSKate Stone (lldb) run
111ea671fbdSKate Stone Launching '.../a.out'  (x86_64)
112ea671fbdSKate Stone (lldb) Fri Sep 10 12:17:45 2010
113ea671fbdSKate Stone Process 21778 Stopped
114ea671fbdSKate Stone * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread
115ea671fbdSKate Stone   36
116ea671fbdSKate Stone   37   	int c(int val)
117ea671fbdSKate Stone   38   	{
118ea671fbdSKate Stone   39 ->	    return val + 3;
119ea671fbdSKate Stone   40   	}
120ea671fbdSKate Stone   41
121ea671fbdSKate Stone   42   	int main (int argc, char const *argv[])
122ea671fbdSKate Stone 
123ea671fbdSKate Stone Example multiple line Python watchpoint command, using function definition:
124ea671fbdSKate Stone 
125ea671fbdSKate Stone (lldb) watchpoint command add -s python 1
126ea671fbdSKate Stone Enter your Python command(s). Type 'DONE' to end.
127ea671fbdSKate Stone > def watchpoint_output (wp_no):
128ea671fbdSKate Stone >     out_string = "Hit watchpoint number " + repr (wp_no)
129ea671fbdSKate Stone >     print out_string
130ea671fbdSKate Stone >     return True
131ea671fbdSKate Stone > watchpoint_output (1)
132ea671fbdSKate Stone > DONE
133ea671fbdSKate Stone 
134ea671fbdSKate Stone Example multiple line Python watchpoint command, using 'loose' Python:
135ea671fbdSKate Stone 
136ea671fbdSKate Stone (lldb) watchpoint command add -s p 1
137ea671fbdSKate Stone Enter your Python command(s). Type 'DONE' to end.
138ea671fbdSKate Stone > global wp_count
139ea671fbdSKate Stone > wp_count = wp_count + 1
140ea671fbdSKate Stone > print "Hit this watchpoint " + repr(wp_count) + " times!"
141ea671fbdSKate Stone > DONE
142ea671fbdSKate Stone 
143ea671fbdSKate Stone )" "In this case, since there is a reference to a global variable, \
144ea671fbdSKate Stone 'wp_count', you will also need to make sure 'wp_count' exists and is \
145ea671fbdSKate Stone initialized:" R"(
146ea671fbdSKate Stone 
147ea671fbdSKate Stone (lldb) script
148ea671fbdSKate Stone >>> wp_count = 0
149ea671fbdSKate Stone >>> quit()
150ea671fbdSKate Stone 
151ea671fbdSKate Stone )" "Final Note: A warning that no watchpoint command was generated when there \
152ea671fbdSKate Stone are no syntax errors may indicate that a function was declared but never called."
153ea671fbdSKate Stone         );
154e9a5627eSJohnny Chen 
155e9a5627eSJohnny Chen         CommandArgumentEntry arg;
156e9a5627eSJohnny Chen         CommandArgumentData wp_id_arg;
157e9a5627eSJohnny Chen 
158e9a5627eSJohnny Chen         // Define the first (and only) variant of this arg.
159e9a5627eSJohnny Chen         wp_id_arg.arg_type = eArgTypeWatchpointID;
160e9a5627eSJohnny Chen         wp_id_arg.arg_repetition = eArgRepeatPlain;
161e9a5627eSJohnny Chen 
162e9a5627eSJohnny Chen         // There is only one variant this argument could be; put it into the argument entry.
163e9a5627eSJohnny Chen         arg.push_back (wp_id_arg);
164e9a5627eSJohnny Chen 
165e9a5627eSJohnny Chen         // Push the data for the first argument into the m_arguments vector.
166e9a5627eSJohnny Chen         m_arguments.push_back (arg);
167e9a5627eSJohnny Chen     }
168e9a5627eSJohnny Chen 
169*49bcfd80SEugene Zelenko     ~CommandObjectWatchpointCommandAdd() override = default;
170e9a5627eSJohnny Chen 
17113d21e9aSBruce Mitchener     Options *
17213d21e9aSBruce Mitchener     GetOptions () override
173e9a5627eSJohnny Chen     {
174e9a5627eSJohnny Chen         return &m_options;
175e9a5627eSJohnny Chen     }
176e9a5627eSJohnny Chen 
17713d21e9aSBruce Mitchener     void
17813d21e9aSBruce Mitchener     IOHandlerActivated (IOHandler &io_handler) override
17944d93782SGreg Clayton     {
18044d93782SGreg Clayton         StreamFileSP output_sp(io_handler.GetOutputStreamFile());
18144d93782SGreg Clayton         if (output_sp)
18244d93782SGreg Clayton         {
18344d93782SGreg Clayton             output_sp->PutCString("Enter your debugger command(s).  Type 'DONE' to end.\n");
18444d93782SGreg Clayton             output_sp->Flush();
18544d93782SGreg Clayton         }
18644d93782SGreg Clayton     }
18744d93782SGreg Clayton 
18813d21e9aSBruce Mitchener     void
18913d21e9aSBruce Mitchener     IOHandlerInputComplete (IOHandler &io_handler, std::string &line) override
19044d93782SGreg Clayton     {
19144d93782SGreg Clayton         io_handler.SetIsDone(true);
19244d93782SGreg Clayton 
19344d93782SGreg Clayton         // The WatchpointOptions object is owned by the watchpoint or watchpoint location
19444d93782SGreg Clayton         WatchpointOptions *wp_options = (WatchpointOptions *) io_handler.GetUserData();
19544d93782SGreg Clayton         if (wp_options)
19644d93782SGreg Clayton         {
19744d93782SGreg Clayton             std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
198*49bcfd80SEugene Zelenko             if (data_ap)
19944d93782SGreg Clayton             {
20044d93782SGreg Clayton                 data_ap->user_source.SplitIntoLines(line);
20144d93782SGreg Clayton                 BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
20244d93782SGreg Clayton                 wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
20344d93782SGreg Clayton             }
20444d93782SGreg Clayton         }
20544d93782SGreg Clayton     }
20644d93782SGreg Clayton 
207e9a5627eSJohnny Chen     void
208e9a5627eSJohnny Chen     CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
209e9a5627eSJohnny Chen                                              CommandReturnObject &result)
210e9a5627eSJohnny Chen     {
21144d93782SGreg Clayton         m_interpreter.GetLLDBCommandsFromIOHandler ("> ",           // Prompt
21244d93782SGreg Clayton                                                     *this,          // IOHandlerDelegate
21344d93782SGreg Clayton                                                     true,           // Run IOHandler in async mode
21444d93782SGreg Clayton                                                     wp_options);    // Baton for the "io_handler" that will be passed back into our IOHandlerDelegate functions
215e9a5627eSJohnny Chen     }
216e9a5627eSJohnny Chen 
217e9a5627eSJohnny Chen     /// Set a one-liner as the callback for the watchpoint.
218e9a5627eSJohnny Chen     void
219e9a5627eSJohnny Chen     SetWatchpointCommandCallback (WatchpointOptions *wp_options,
220e9a5627eSJohnny Chen                                   const char *oneliner)
221e9a5627eSJohnny Chen     {
2227b0992d9SGreg Clayton         std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
223e9a5627eSJohnny Chen 
224e9a5627eSJohnny Chen         // It's necessary to set both user_source and script_source to the oneliner.
225e9a5627eSJohnny Chen         // The former is used to generate callback description (as in watchpoint command list)
226e9a5627eSJohnny Chen         // while the latter is used for Python to interpret during the actual callback.
227e9a5627eSJohnny Chen         data_ap->user_source.AppendString (oneliner);
228e9a5627eSJohnny Chen         data_ap->script_source.assign (oneliner);
229e9a5627eSJohnny Chen         data_ap->stop_on_error = m_options.m_stop_on_error;
230e9a5627eSJohnny Chen 
231e9a5627eSJohnny Chen         BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
232e9a5627eSJohnny Chen         wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
233e9a5627eSJohnny Chen     }
234e9a5627eSJohnny Chen 
235e9a5627eSJohnny Chen     static bool
236e9a5627eSJohnny Chen     WatchpointOptionsCallbackFunction (void *baton,
237e9a5627eSJohnny Chen                                        StoppointCallbackContext *context,
238e9a5627eSJohnny Chen                                        lldb::user_id_t watch_id)
239e9a5627eSJohnny Chen     {
240e9a5627eSJohnny Chen         bool ret_value = true;
241*49bcfd80SEugene Zelenko         if (baton == nullptr)
242e9a5627eSJohnny Chen             return true;
243e9a5627eSJohnny Chen 
244e9a5627eSJohnny Chen         WatchpointOptions::CommandData *data = (WatchpointOptions::CommandData *) baton;
245e9a5627eSJohnny Chen         StringList &commands = data->user_source;
246e9a5627eSJohnny Chen 
247e9a5627eSJohnny Chen         if (commands.GetSize() > 0)
248e9a5627eSJohnny Chen         {
249e9a5627eSJohnny Chen             ExecutionContext exe_ctx (context->exe_ctx_ref);
250e9a5627eSJohnny Chen             Target *target = exe_ctx.GetTargetPtr();
251e9a5627eSJohnny Chen             if (target)
252e9a5627eSJohnny Chen             {
253e9a5627eSJohnny Chen                 CommandReturnObject result;
254e9a5627eSJohnny Chen                 Debugger &debugger = target->GetDebugger();
255e9a5627eSJohnny Chen                 // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
256e9a5627eSJohnny Chen                 // if the debugger is set up that way.
257e9a5627eSJohnny Chen 
258e9a5627eSJohnny Chen                 StreamSP output_stream (debugger.GetAsyncOutputStream());
259e9a5627eSJohnny Chen                 StreamSP error_stream (debugger.GetAsyncErrorStream());
260e9a5627eSJohnny Chen                 result.SetImmediateOutputStream (output_stream);
261e9a5627eSJohnny Chen                 result.SetImmediateErrorStream (error_stream);
262e9a5627eSJohnny Chen 
26326c7bf93SJim Ingham                 CommandInterpreterRunOptions options;
26426c7bf93SJim Ingham                 options.SetStopOnContinue (true);
26526c7bf93SJim Ingham                 options.SetStopOnError (data->stop_on_error);
26626c7bf93SJim Ingham                 options.SetEchoCommands (false);
26726c7bf93SJim Ingham                 options.SetPrintResults (true);
26826c7bf93SJim Ingham                 options.SetAddToHistory (false);
269e9a5627eSJohnny Chen 
270e9a5627eSJohnny Chen                 debugger.GetCommandInterpreter().HandleCommands (commands,
271e9a5627eSJohnny Chen                                                                  &exe_ctx,
27226c7bf93SJim Ingham                                                                  options,
273e9a5627eSJohnny Chen                                                                  result);
274e9a5627eSJohnny Chen                 result.GetImmediateOutputStream()->Flush();
275e9a5627eSJohnny Chen                 result.GetImmediateErrorStream()->Flush();
276e9a5627eSJohnny Chen            }
277e9a5627eSJohnny Chen         }
278e9a5627eSJohnny Chen         return ret_value;
279e9a5627eSJohnny Chen     }
280e9a5627eSJohnny Chen 
281e9a5627eSJohnny Chen     class CommandOptions : public Options
282e9a5627eSJohnny Chen     {
283e9a5627eSJohnny Chen     public:
284e9a5627eSJohnny Chen         CommandOptions (CommandInterpreter &interpreter) :
285e9a5627eSJohnny Chen             Options (interpreter),
286e9a5627eSJohnny Chen             m_use_commands (false),
287e9a5627eSJohnny Chen             m_use_script_language (false),
288e9a5627eSJohnny Chen             m_script_language (eScriptLanguageNone),
289e9a5627eSJohnny Chen             m_use_one_liner (false),
290e9a5627eSJohnny Chen             m_one_liner(),
291e9a5627eSJohnny Chen             m_function_name()
292e9a5627eSJohnny Chen         {
293e9a5627eSJohnny Chen         }
294e9a5627eSJohnny Chen 
295*49bcfd80SEugene Zelenko         ~CommandOptions() override = default;
296e9a5627eSJohnny Chen 
29713d21e9aSBruce Mitchener         Error
29813d21e9aSBruce Mitchener         SetOptionValue (uint32_t option_idx, const char *option_arg) override
299e9a5627eSJohnny Chen         {
300e9a5627eSJohnny Chen             Error error;
3013bcdfc0eSGreg Clayton             const int short_option = m_getopt_table[option_idx].val;
302e9a5627eSJohnny Chen 
303e9a5627eSJohnny Chen             switch (short_option)
304e9a5627eSJohnny Chen             {
305e9a5627eSJohnny Chen             case 'o':
306e9a5627eSJohnny Chen                 m_use_one_liner = true;
307e9a5627eSJohnny Chen                 m_one_liner = option_arg;
308e9a5627eSJohnny Chen                 break;
309e9a5627eSJohnny Chen 
310e9a5627eSJohnny Chen             case 's':
311e9a5627eSJohnny Chen                 m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
312e9a5627eSJohnny Chen                                                                                      g_option_table[option_idx].enum_values,
313e9a5627eSJohnny Chen                                                                                      eScriptLanguageNone,
314e9a5627eSJohnny Chen                                                                                      error);
315e9a5627eSJohnny Chen 
316*49bcfd80SEugene Zelenko                 m_use_script_language =
317*49bcfd80SEugene Zelenko                     (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault);
318e9a5627eSJohnny Chen                 break;
319e9a5627eSJohnny Chen 
320e9a5627eSJohnny Chen             case 'e':
321e9a5627eSJohnny Chen                 {
322e9a5627eSJohnny Chen                     bool success = false;
323e9a5627eSJohnny Chen                     m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
324e9a5627eSJohnny Chen                     if (!success)
325e9a5627eSJohnny Chen                         error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
326e9a5627eSJohnny Chen                 }
327e9a5627eSJohnny Chen                 break;
328e9a5627eSJohnny Chen 
329e9a5627eSJohnny Chen             case 'F':
330e9a5627eSJohnny Chen                 m_use_one_liner = false;
331e9a5627eSJohnny Chen                 m_use_script_language = true;
332e9a5627eSJohnny Chen                 m_function_name.assign(option_arg);
333e9a5627eSJohnny Chen                 break;
334e9a5627eSJohnny Chen 
335e9a5627eSJohnny Chen             default:
336e9a5627eSJohnny Chen                 break;
337e9a5627eSJohnny Chen             }
338e9a5627eSJohnny Chen             return error;
339e9a5627eSJohnny Chen         }
340*49bcfd80SEugene Zelenko 
341e9a5627eSJohnny Chen         void
34213d21e9aSBruce Mitchener         OptionParsingStarting () override
343e9a5627eSJohnny Chen         {
344e9a5627eSJohnny Chen             m_use_commands = true;
345e9a5627eSJohnny Chen             m_use_script_language = false;
346e9a5627eSJohnny Chen             m_script_language = eScriptLanguageNone;
347e9a5627eSJohnny Chen 
348e9a5627eSJohnny Chen             m_use_one_liner = false;
349e9a5627eSJohnny Chen             m_stop_on_error = true;
350e9a5627eSJohnny Chen             m_one_liner.clear();
351e9a5627eSJohnny Chen             m_function_name.clear();
352e9a5627eSJohnny Chen         }
353e9a5627eSJohnny Chen 
354e9a5627eSJohnny Chen         const OptionDefinition*
35513d21e9aSBruce Mitchener         GetDefinitions () override
356e9a5627eSJohnny Chen         {
357e9a5627eSJohnny Chen             return g_option_table;
358e9a5627eSJohnny Chen         }
359e9a5627eSJohnny Chen 
360e9a5627eSJohnny Chen         // Options table: Required for subclasses of Options.
361e9a5627eSJohnny Chen 
362e9a5627eSJohnny Chen         static OptionDefinition g_option_table[];
363e9a5627eSJohnny Chen 
364e9a5627eSJohnny Chen         // Instance variables to hold the values for command options.
365e9a5627eSJohnny Chen 
366e9a5627eSJohnny Chen         bool m_use_commands;
367e9a5627eSJohnny Chen         bool m_use_script_language;
368e9a5627eSJohnny Chen         lldb::ScriptLanguage m_script_language;
369e9a5627eSJohnny Chen 
370e9a5627eSJohnny Chen         // Instance variables to hold the values for one_liner options.
371e9a5627eSJohnny Chen         bool m_use_one_liner;
372e9a5627eSJohnny Chen         std::string m_one_liner;
373e9a5627eSJohnny Chen         bool m_stop_on_error;
374e9a5627eSJohnny Chen         std::string m_function_name;
375e9a5627eSJohnny Chen     };
376e9a5627eSJohnny Chen 
377e9a5627eSJohnny Chen protected:
37813d21e9aSBruce Mitchener     bool
37913d21e9aSBruce Mitchener     DoExecute (Args& command, CommandReturnObject &result) override
380e9a5627eSJohnny Chen     {
381e9a5627eSJohnny Chen         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
382e9a5627eSJohnny Chen 
383*49bcfd80SEugene Zelenko         if (target == nullptr)
384e9a5627eSJohnny Chen         {
385e9a5627eSJohnny Chen             result.AppendError ("There is not a current executable; there are no watchpoints to which to add commands");
386e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
387e9a5627eSJohnny Chen             return false;
388e9a5627eSJohnny Chen         }
389e9a5627eSJohnny Chen 
390e9a5627eSJohnny Chen         const WatchpointList &watchpoints = target->GetWatchpointList();
391e9a5627eSJohnny Chen         size_t num_watchpoints = watchpoints.GetSize();
392e9a5627eSJohnny Chen 
393e9a5627eSJohnny Chen         if (num_watchpoints == 0)
394e9a5627eSJohnny Chen         {
395e9a5627eSJohnny Chen             result.AppendError ("No watchpoints exist to have commands added");
396e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
397e9a5627eSJohnny Chen             return false;
398e9a5627eSJohnny Chen         }
399e9a5627eSJohnny Chen 
400*49bcfd80SEugene Zelenko         if (!m_options.m_use_script_language && !m_options.m_function_name.empty())
401e9a5627eSJohnny Chen         {
402e9a5627eSJohnny Chen             result.AppendError ("need to enable scripting to have a function run as a watchpoint command");
403e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
404e9a5627eSJohnny Chen             return false;
405e9a5627eSJohnny Chen         }
406e9a5627eSJohnny Chen 
407e9a5627eSJohnny Chen         std::vector<uint32_t> valid_wp_ids;
408b0b4513eSJim Ingham         if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
409e9a5627eSJohnny Chen         {
410e9a5627eSJohnny Chen             result.AppendError("Invalid watchpoints specification.");
411e9a5627eSJohnny Chen             result.SetStatus(eReturnStatusFailed);
412e9a5627eSJohnny Chen             return false;
413e9a5627eSJohnny Chen         }
414e9a5627eSJohnny Chen 
415e9a5627eSJohnny Chen         result.SetStatus(eReturnStatusSuccessFinishNoResult);
416e9a5627eSJohnny Chen         const size_t count = valid_wp_ids.size();
417e9a5627eSJohnny Chen         for (size_t i = 0; i < count; ++i)
418e9a5627eSJohnny Chen         {
419e9a5627eSJohnny Chen             uint32_t cur_wp_id = valid_wp_ids.at (i);
420e9a5627eSJohnny Chen             if (cur_wp_id != LLDB_INVALID_WATCH_ID)
421e9a5627eSJohnny Chen             {
422e9a5627eSJohnny Chen                 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
423e9a5627eSJohnny Chen                 // Sanity check wp first.
424*49bcfd80SEugene Zelenko                 if (wp == nullptr) continue;
425e9a5627eSJohnny Chen 
426e9a5627eSJohnny Chen                 WatchpointOptions *wp_options = wp->GetOptions();
427e9a5627eSJohnny Chen                 // Skip this watchpoint if wp_options is not good.
428*49bcfd80SEugene Zelenko                 if (wp_options == nullptr) continue;
429e9a5627eSJohnny Chen 
430e9a5627eSJohnny Chen                 // If we are using script language, get the script interpreter
431e9a5627eSJohnny Chen                 // in order to set or collect command callback.  Otherwise, call
432e9a5627eSJohnny Chen                 // the methods associated with this object.
433e9a5627eSJohnny Chen                 if (m_options.m_use_script_language)
434e9a5627eSJohnny Chen                 {
435e9a5627eSJohnny Chen                     // Special handling for one-liner specified inline.
436e9a5627eSJohnny Chen                     if (m_options.m_use_one_liner)
437e9a5627eSJohnny Chen                     {
438e9a5627eSJohnny Chen                         m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
439e9a5627eSJohnny Chen                                                                                             m_options.m_one_liner.c_str());
440e9a5627eSJohnny Chen                     }
441e9a5627eSJohnny Chen                     // Special handling for using a Python function by name
442e9a5627eSJohnny Chen                     // instead of extending the watchpoint callback data structures, we just automatize
443e9a5627eSJohnny Chen                     // what the user would do manually: make their watchpoint command be a function call
444*49bcfd80SEugene Zelenko                     else if (!m_options.m_function_name.empty())
445e9a5627eSJohnny Chen                     {
446e9a5627eSJohnny Chen                         std::string oneliner(m_options.m_function_name);
447e9a5627eSJohnny Chen                         oneliner += "(frame, wp, internal_dict)";
448e9a5627eSJohnny Chen                         m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
449e9a5627eSJohnny Chen                                                                                             oneliner.c_str());
450e9a5627eSJohnny Chen                     }
451e9a5627eSJohnny Chen                     else
452e9a5627eSJohnny Chen                     {
453e9a5627eSJohnny Chen                         m_interpreter.GetScriptInterpreter()->CollectDataForWatchpointCommandCallback (wp_options,
454e9a5627eSJohnny Chen                                                                                                        result);
455e9a5627eSJohnny Chen                     }
456e9a5627eSJohnny Chen                 }
457e9a5627eSJohnny Chen                 else
458e9a5627eSJohnny Chen                 {
459e9a5627eSJohnny Chen                     // Special handling for one-liner specified inline.
460e9a5627eSJohnny Chen                     if (m_options.m_use_one_liner)
461e9a5627eSJohnny Chen                         SetWatchpointCommandCallback (wp_options,
462e9a5627eSJohnny Chen                                                       m_options.m_one_liner.c_str());
463e9a5627eSJohnny Chen                     else
464e9a5627eSJohnny Chen                         CollectDataForWatchpointCommandCallback (wp_options,
465e9a5627eSJohnny Chen                                                                  result);
466e9a5627eSJohnny Chen                 }
467e9a5627eSJohnny Chen             }
468e9a5627eSJohnny Chen         }
469e9a5627eSJohnny Chen 
470e9a5627eSJohnny Chen         return result.Succeeded();
471e9a5627eSJohnny Chen     }
472e9a5627eSJohnny Chen 
473e9a5627eSJohnny Chen private:
474e9a5627eSJohnny Chen     CommandOptions m_options;
475e9a5627eSJohnny Chen };
476e9a5627eSJohnny Chen 
477e9a5627eSJohnny Chen // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
478e9a5627eSJohnny Chen // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
479e9a5627eSJohnny Chen 
480e9a5627eSJohnny Chen static OptionEnumValueElement
481e9a5627eSJohnny Chen g_script_option_enumeration[4] =
482e9a5627eSJohnny Chen {
483e9a5627eSJohnny Chen     { eScriptLanguageNone,    "command",         "Commands are in the lldb command interpreter language"},
484e9a5627eSJohnny Chen     { eScriptLanguagePython,  "python",          "Commands are in the Python language."},
485e9a5627eSJohnny Chen     { eSortOrderByName,       "default-script",  "Commands are in the default scripting language."},
486*49bcfd80SEugene Zelenko     { 0,                      nullptr,           nullptr }
487e9a5627eSJohnny Chen };
488e9a5627eSJohnny Chen 
489e9a5627eSJohnny Chen OptionDefinition
490e9a5627eSJohnny Chen CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] =
491e9a5627eSJohnny Chen {
492*49bcfd80SEugene Zelenko     { LLDB_OPT_SET_1,   false, "one-liner",       'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOneLiner,
493e9a5627eSJohnny Chen         "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." },
494e9a5627eSJohnny Chen 
495*49bcfd80SEugene Zelenko     { LLDB_OPT_SET_ALL, false, "stop-on-error",   'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean,
496e9a5627eSJohnny Chen         "Specify whether watchpoint command execution should terminate on error." },
497e9a5627eSJohnny Chen 
498*49bcfd80SEugene Zelenko     { LLDB_OPT_SET_ALL, false, "script-type",     's', OptionParser::eRequiredArgument, nullptr, g_script_option_enumeration, 0, eArgTypeNone,
499e9a5627eSJohnny Chen         "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
500e9a5627eSJohnny Chen 
501*49bcfd80SEugene Zelenko     { LLDB_OPT_SET_2,   false, "python-function", 'F', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePythonFunction,
502e9a5627eSJohnny Chen         "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."},
503e9a5627eSJohnny Chen 
504*49bcfd80SEugene Zelenko     { 0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr }
505e9a5627eSJohnny Chen };
506e9a5627eSJohnny Chen 
507e9a5627eSJohnny Chen //-------------------------------------------------------------------------
508e9a5627eSJohnny Chen // CommandObjectWatchpointCommandDelete
509e9a5627eSJohnny Chen //-------------------------------------------------------------------------
510e9a5627eSJohnny Chen 
511e9a5627eSJohnny Chen class CommandObjectWatchpointCommandDelete : public CommandObjectParsed
512e9a5627eSJohnny Chen {
513e9a5627eSJohnny Chen public:
514e9a5627eSJohnny Chen     CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) :
515e9a5627eSJohnny Chen         CommandObjectParsed(interpreter,
516e9a5627eSJohnny Chen                             "delete",
517e9a5627eSJohnny Chen                             "Delete the set of commands from a watchpoint.",
518*49bcfd80SEugene Zelenko                             nullptr)
519e9a5627eSJohnny Chen     {
520e9a5627eSJohnny Chen         CommandArgumentEntry arg;
521e9a5627eSJohnny Chen         CommandArgumentData wp_id_arg;
522e9a5627eSJohnny Chen 
523e9a5627eSJohnny Chen         // Define the first (and only) variant of this arg.
524e9a5627eSJohnny Chen         wp_id_arg.arg_type = eArgTypeWatchpointID;
525e9a5627eSJohnny Chen         wp_id_arg.arg_repetition = eArgRepeatPlain;
526e9a5627eSJohnny Chen 
527e9a5627eSJohnny Chen         // There is only one variant this argument could be; put it into the argument entry.
528e9a5627eSJohnny Chen         arg.push_back (wp_id_arg);
529e9a5627eSJohnny Chen 
530e9a5627eSJohnny Chen         // Push the data for the first argument into the m_arguments vector.
531e9a5627eSJohnny Chen         m_arguments.push_back (arg);
532e9a5627eSJohnny Chen     }
533e9a5627eSJohnny Chen 
534*49bcfd80SEugene Zelenko     ~CommandObjectWatchpointCommandDelete() override = default;
535e9a5627eSJohnny Chen 
536e9a5627eSJohnny Chen protected:
53713d21e9aSBruce Mitchener     bool
53813d21e9aSBruce Mitchener     DoExecute (Args& command, CommandReturnObject &result) override
539e9a5627eSJohnny Chen     {
540e9a5627eSJohnny Chen         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
541e9a5627eSJohnny Chen 
542*49bcfd80SEugene Zelenko         if (target == nullptr)
543e9a5627eSJohnny Chen         {
544e9a5627eSJohnny Chen             result.AppendError ("There is not a current executable; there are no watchpoints from which to delete commands");
545e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
546e9a5627eSJohnny Chen             return false;
547e9a5627eSJohnny Chen         }
548e9a5627eSJohnny Chen 
549e9a5627eSJohnny Chen         const WatchpointList &watchpoints = target->GetWatchpointList();
550e9a5627eSJohnny Chen         size_t num_watchpoints = watchpoints.GetSize();
551e9a5627eSJohnny Chen 
552e9a5627eSJohnny Chen         if (num_watchpoints == 0)
553e9a5627eSJohnny Chen         {
554e9a5627eSJohnny Chen             result.AppendError ("No watchpoints exist to have commands deleted");
555e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
556e9a5627eSJohnny Chen             return false;
557e9a5627eSJohnny Chen         }
558e9a5627eSJohnny Chen 
559e9a5627eSJohnny Chen         if (command.GetArgumentCount() == 0)
560e9a5627eSJohnny Chen         {
561e9a5627eSJohnny Chen             result.AppendError ("No watchpoint specified from which to delete the commands");
562e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
563e9a5627eSJohnny Chen             return false;
564e9a5627eSJohnny Chen         }
565e9a5627eSJohnny Chen 
566e9a5627eSJohnny Chen         std::vector<uint32_t> valid_wp_ids;
567b0b4513eSJim Ingham         if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
568e9a5627eSJohnny Chen         {
569e9a5627eSJohnny Chen             result.AppendError("Invalid watchpoints specification.");
570e9a5627eSJohnny Chen             result.SetStatus(eReturnStatusFailed);
571e9a5627eSJohnny Chen             return false;
572e9a5627eSJohnny Chen         }
573e9a5627eSJohnny Chen 
574e9a5627eSJohnny Chen         result.SetStatus(eReturnStatusSuccessFinishNoResult);
575e9a5627eSJohnny Chen         const size_t count = valid_wp_ids.size();
576e9a5627eSJohnny Chen         for (size_t i = 0; i < count; ++i)
577e9a5627eSJohnny Chen         {
578e9a5627eSJohnny Chen             uint32_t cur_wp_id = valid_wp_ids.at (i);
579e9a5627eSJohnny Chen             if (cur_wp_id != LLDB_INVALID_WATCH_ID)
580e9a5627eSJohnny Chen             {
581e9a5627eSJohnny Chen                 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
582e9a5627eSJohnny Chen                 if (wp)
583e9a5627eSJohnny Chen                     wp->ClearCallback();
584e9a5627eSJohnny Chen             }
585e9a5627eSJohnny Chen             else
586e9a5627eSJohnny Chen             {
587e9a5627eSJohnny Chen                 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
588e9a5627eSJohnny Chen                                              cur_wp_id);
589e9a5627eSJohnny Chen                 result.SetStatus (eReturnStatusFailed);
590e9a5627eSJohnny Chen                 return false;
591e9a5627eSJohnny Chen             }
592e9a5627eSJohnny Chen         }
593e9a5627eSJohnny Chen         return result.Succeeded();
594e9a5627eSJohnny Chen     }
595e9a5627eSJohnny Chen };
596e9a5627eSJohnny Chen 
597e9a5627eSJohnny Chen //-------------------------------------------------------------------------
598e9a5627eSJohnny Chen // CommandObjectWatchpointCommandList
599e9a5627eSJohnny Chen //-------------------------------------------------------------------------
600e9a5627eSJohnny Chen 
601e9a5627eSJohnny Chen class CommandObjectWatchpointCommandList : public CommandObjectParsed
602e9a5627eSJohnny Chen {
603e9a5627eSJohnny Chen public:
604e9a5627eSJohnny Chen     CommandObjectWatchpointCommandList (CommandInterpreter &interpreter) :
605e9a5627eSJohnny Chen         CommandObjectParsed(interpreter,
606e9a5627eSJohnny Chen                             "list",
607e9a5627eSJohnny Chen                             "List the script or set of commands to be executed when the watchpoint is hit.",
608*49bcfd80SEugene Zelenko                             nullptr)
609e9a5627eSJohnny Chen     {
610e9a5627eSJohnny Chen         CommandArgumentEntry arg;
611e9a5627eSJohnny Chen         CommandArgumentData wp_id_arg;
612e9a5627eSJohnny Chen 
613e9a5627eSJohnny Chen         // Define the first (and only) variant of this arg.
614e9a5627eSJohnny Chen         wp_id_arg.arg_type = eArgTypeWatchpointID;
615e9a5627eSJohnny Chen         wp_id_arg.arg_repetition = eArgRepeatPlain;
616e9a5627eSJohnny Chen 
617e9a5627eSJohnny Chen         // There is only one variant this argument could be; put it into the argument entry.
618e9a5627eSJohnny Chen         arg.push_back (wp_id_arg);
619e9a5627eSJohnny Chen 
620e9a5627eSJohnny Chen         // Push the data for the first argument into the m_arguments vector.
621e9a5627eSJohnny Chen         m_arguments.push_back (arg);
622e9a5627eSJohnny Chen     }
623e9a5627eSJohnny Chen 
624*49bcfd80SEugene Zelenko     ~CommandObjectWatchpointCommandList() override = default;
625e9a5627eSJohnny Chen 
626e9a5627eSJohnny Chen protected:
62713d21e9aSBruce Mitchener     bool
62813d21e9aSBruce Mitchener     DoExecute (Args& command, CommandReturnObject &result) override
629e9a5627eSJohnny Chen     {
630e9a5627eSJohnny Chen         Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
631e9a5627eSJohnny Chen 
632*49bcfd80SEugene Zelenko         if (target == nullptr)
633e9a5627eSJohnny Chen         {
634e9a5627eSJohnny Chen             result.AppendError ("There is not a current executable; there are no watchpoints for which to list commands");
635e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
636e9a5627eSJohnny Chen             return false;
637e9a5627eSJohnny Chen         }
638e9a5627eSJohnny Chen 
639e9a5627eSJohnny Chen         const WatchpointList &watchpoints = target->GetWatchpointList();
640e9a5627eSJohnny Chen         size_t num_watchpoints = watchpoints.GetSize();
641e9a5627eSJohnny Chen 
642e9a5627eSJohnny Chen         if (num_watchpoints == 0)
643e9a5627eSJohnny Chen         {
644e9a5627eSJohnny Chen             result.AppendError ("No watchpoints exist for which to list commands");
645e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
646e9a5627eSJohnny Chen             return false;
647e9a5627eSJohnny Chen         }
648e9a5627eSJohnny Chen 
649e9a5627eSJohnny Chen         if (command.GetArgumentCount() == 0)
650e9a5627eSJohnny Chen         {
651e9a5627eSJohnny Chen             result.AppendError ("No watchpoint specified for which to list the commands");
652e9a5627eSJohnny Chen             result.SetStatus (eReturnStatusFailed);
653e9a5627eSJohnny Chen             return false;
654e9a5627eSJohnny Chen         }
655e9a5627eSJohnny Chen 
656e9a5627eSJohnny Chen         std::vector<uint32_t> valid_wp_ids;
657b0b4513eSJim Ingham         if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
658e9a5627eSJohnny Chen         {
659e9a5627eSJohnny Chen             result.AppendError("Invalid watchpoints specification.");
660e9a5627eSJohnny Chen             result.SetStatus(eReturnStatusFailed);
661e9a5627eSJohnny Chen             return false;
662e9a5627eSJohnny Chen         }
663e9a5627eSJohnny Chen 
664e9a5627eSJohnny Chen         result.SetStatus(eReturnStatusSuccessFinishNoResult);
665e9a5627eSJohnny Chen         const size_t count = valid_wp_ids.size();
666e9a5627eSJohnny Chen         for (size_t i = 0; i < count; ++i)
667e9a5627eSJohnny Chen         {
668e9a5627eSJohnny Chen             uint32_t cur_wp_id = valid_wp_ids.at (i);
669e9a5627eSJohnny Chen             if (cur_wp_id != LLDB_INVALID_WATCH_ID)
670e9a5627eSJohnny Chen             {
671e9a5627eSJohnny Chen                 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
672e9a5627eSJohnny Chen 
673e9a5627eSJohnny Chen                 if (wp)
674e9a5627eSJohnny Chen                 {
675e9a5627eSJohnny Chen                     const WatchpointOptions *wp_options = wp->GetOptions();
676e9a5627eSJohnny Chen                     if (wp_options)
677e9a5627eSJohnny Chen                     {
678e9a5627eSJohnny Chen                         // Get the callback baton associated with the current watchpoint.
679e9a5627eSJohnny Chen                         const Baton *baton = wp_options->GetBaton();
680e9a5627eSJohnny Chen                         if (baton)
681e9a5627eSJohnny Chen                         {
682e9a5627eSJohnny Chen                             result.GetOutputStream().Printf ("Watchpoint %u:\n", cur_wp_id);
683e9a5627eSJohnny Chen                             result.GetOutputStream().IndentMore ();
684e9a5627eSJohnny Chen                             baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
685e9a5627eSJohnny Chen                             result.GetOutputStream().IndentLess ();
686e9a5627eSJohnny Chen                         }
687e9a5627eSJohnny Chen                         else
688e9a5627eSJohnny Chen                         {
689e9a5627eSJohnny Chen                             result.AppendMessageWithFormat ("Watchpoint %u does not have an associated command.\n",
690e9a5627eSJohnny Chen                                                             cur_wp_id);
691e9a5627eSJohnny Chen                         }
692e9a5627eSJohnny Chen                     }
693e9a5627eSJohnny Chen                     result.SetStatus (eReturnStatusSuccessFinishResult);
694e9a5627eSJohnny Chen                 }
695e9a5627eSJohnny Chen                 else
696e9a5627eSJohnny Chen                 {
697e9a5627eSJohnny Chen                     result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
698e9a5627eSJohnny Chen                     result.SetStatus (eReturnStatusFailed);
699e9a5627eSJohnny Chen                 }
700e9a5627eSJohnny Chen             }
701e9a5627eSJohnny Chen         }
702e9a5627eSJohnny Chen 
703e9a5627eSJohnny Chen         return result.Succeeded();
704e9a5627eSJohnny Chen     }
705e9a5627eSJohnny Chen };
706e9a5627eSJohnny Chen 
707e9a5627eSJohnny Chen //-------------------------------------------------------------------------
708e9a5627eSJohnny Chen // CommandObjectWatchpointCommand
709e9a5627eSJohnny Chen //-------------------------------------------------------------------------
710e9a5627eSJohnny Chen 
711e9a5627eSJohnny Chen CommandObjectWatchpointCommand::CommandObjectWatchpointCommand (CommandInterpreter &interpreter) :
712e9a5627eSJohnny Chen     CommandObjectMultiword (interpreter,
713e9a5627eSJohnny Chen                             "command",
714e9a5627eSJohnny Chen                             "A set of commands for adding, removing and examining bits of code to be executed when the watchpoint is hit (watchpoint 'commmands').",
715e9a5627eSJohnny Chen                             "command <sub-command> [<sub-command-options>] <watchpoint-id>")
716e9a5627eSJohnny Chen {
717e9a5627eSJohnny Chen     CommandObjectSP add_command_object (new CommandObjectWatchpointCommandAdd (interpreter));
718e9a5627eSJohnny Chen     CommandObjectSP delete_command_object (new CommandObjectWatchpointCommandDelete (interpreter));
719e9a5627eSJohnny Chen     CommandObjectSP list_command_object (new CommandObjectWatchpointCommandList (interpreter));
720e9a5627eSJohnny Chen 
721e9a5627eSJohnny Chen     add_command_object->SetCommandName ("watchpoint command add");
722e9a5627eSJohnny Chen     delete_command_object->SetCommandName ("watchpoint command delete");
723e9a5627eSJohnny Chen     list_command_object->SetCommandName ("watchpoint command list");
724e9a5627eSJohnny Chen 
72503da4cc2SGreg Clayton     LoadSubCommand ("add",    add_command_object);
72603da4cc2SGreg Clayton     LoadSubCommand ("delete", delete_command_object);
72703da4cc2SGreg Clayton     LoadSubCommand ("list",   list_command_object);
728e9a5627eSJohnny Chen }
729e9a5627eSJohnny Chen 
730*49bcfd80SEugene Zelenko CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand() = default;
731