xref: /src/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpointCommand.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===-- CommandObjectWatchpointCommand.cpp --------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste 
9f3fbd1c0SDimitry Andric #include <vector>
10f034231aSEd Maste 
11f034231aSEd Maste #include "CommandObjectWatchpoint.h"
1214f1b3e8SDimitry Andric #include "CommandObjectWatchpointCommand.h"
1314f1b3e8SDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h"
1414f1b3e8SDimitry Andric #include "lldb/Breakpoint/Watchpoint.h"
15866dcdacSEd Maste #include "lldb/Core/IOHandler.h"
1674a628f7SDimitry Andric #include "lldb/Host/OptionParser.h"
17f034231aSEd Maste #include "lldb/Interpreter/CommandInterpreter.h"
184b4fe385SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
19f034231aSEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
20f73363f1SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
21f034231aSEd Maste #include "lldb/Target/Target.h"
22f034231aSEd Maste 
23f034231aSEd Maste using namespace lldb;
24f034231aSEd Maste using namespace lldb_private;
25f034231aSEd Maste 
265f29bb8aSDimitry Andric #define LLDB_OPTIONS_watchpoint_command_add
275f29bb8aSDimitry Andric #include "CommandOptions.inc"
2814f1b3e8SDimitry Andric 
2914f1b3e8SDimitry Andric class CommandObjectWatchpointCommandAdd : public CommandObjectParsed,
3014f1b3e8SDimitry Andric                                           public IOHandlerDelegateMultiline {
31f034231aSEd Maste public:
CommandObjectWatchpointCommandAdd(CommandInterpreter & interpreter)32f3fbd1c0SDimitry Andric   CommandObjectWatchpointCommandAdd(CommandInterpreter &interpreter)
3314f1b3e8SDimitry Andric       : CommandObjectParsed(interpreter, "add",
3414f1b3e8SDimitry Andric                             "Add a set of LLDB commands to a watchpoint, to be "
35344a3780SDimitry Andric                             "executed whenever the watchpoint is hit.  "
36344a3780SDimitry Andric                             "The commands added to the watchpoint replace any "
37344a3780SDimitry Andric                             "commands previously added to it.",
38ead24645SDimitry Andric                             nullptr, eCommandRequiresTarget),
3914f1b3e8SDimitry Andric         IOHandlerDelegateMultiline("DONE",
406f8fc217SDimitry Andric                                    IOHandlerDelegate::Completion::LLDBCommand) {
41f034231aSEd Maste     SetHelpLong(
42027f1c96SDimitry Andric         R"(
43027f1c96SDimitry Andric General information about entering watchpoint commands
44027f1c96SDimitry Andric ------------------------------------------------------
45027f1c96SDimitry Andric 
4614f1b3e8SDimitry Andric )"
4714f1b3e8SDimitry Andric         "This command will prompt for commands to be executed when the specified \
48027f1c96SDimitry Andric watchpoint is hit.  Each command is typed on its own line following the '> ' \
4914f1b3e8SDimitry Andric prompt until 'DONE' is entered."
5014f1b3e8SDimitry Andric         R"(
51027f1c96SDimitry Andric 
5214f1b3e8SDimitry Andric )"
5314f1b3e8SDimitry Andric         "Syntactic errors may not be detected when initially entered, and many \
54027f1c96SDimitry Andric malformed commands can silently fail when executed.  If your watchpoint commands \
5514f1b3e8SDimitry Andric do not appear to be executing, double-check the command syntax."
5614f1b3e8SDimitry Andric         R"(
57027f1c96SDimitry Andric 
5814f1b3e8SDimitry Andric )"
5914f1b3e8SDimitry Andric         "Note: You may enter any debugger command exactly as you would at the debugger \
60027f1c96SDimitry Andric prompt.  There is no limit to the number of commands supplied, but do NOT enter \
6114f1b3e8SDimitry Andric more than one command per line."
6214f1b3e8SDimitry Andric         R"(
63027f1c96SDimitry Andric 
64027f1c96SDimitry Andric Special information about PYTHON watchpoint commands
65027f1c96SDimitry Andric ----------------------------------------------------
66027f1c96SDimitry Andric 
6714f1b3e8SDimitry Andric )"
6814f1b3e8SDimitry Andric         "You may enter either one or more lines of Python, including function \
69027f1c96SDimitry Andric definitions or calls to functions that will have been imported by the time \
70027f1c96SDimitry Andric the code executes.  Single line watchpoint commands will be interpreted 'as is' \
71027f1c96SDimitry Andric when the watchpoint is hit.  Multiple lines of Python will be wrapped in a \
7214f1b3e8SDimitry Andric generated function, and a call to the function will be attached to the watchpoint."
7314f1b3e8SDimitry Andric         R"(
74027f1c96SDimitry Andric 
75027f1c96SDimitry Andric This auto-generated function is passed in three arguments:
76027f1c96SDimitry Andric 
77027f1c96SDimitry Andric     frame:  an lldb.SBFrame object for the frame which hit the watchpoint.
78027f1c96SDimitry Andric 
79027f1c96SDimitry Andric     wp:     the watchpoint that was hit.
80027f1c96SDimitry Andric 
8114f1b3e8SDimitry Andric )"
8214f1b3e8SDimitry Andric         "When specifying a python function with the --python-function option, you need \
8314f1b3e8SDimitry Andric to supply the function name prepended by the module name:"
8414f1b3e8SDimitry Andric         R"(
85027f1c96SDimitry Andric 
86027f1c96SDimitry Andric     --python-function myutils.watchpoint_callback
87027f1c96SDimitry Andric 
88027f1c96SDimitry Andric The function itself must have the following prototype:
89027f1c96SDimitry Andric 
90027f1c96SDimitry Andric def watchpoint_callback(frame, wp):
91027f1c96SDimitry Andric   # Your code goes here
92027f1c96SDimitry Andric 
9314f1b3e8SDimitry Andric )"
9414f1b3e8SDimitry Andric         "The arguments are the same as the arguments passed to generated functions as \
95027f1c96SDimitry Andric described above.  Note that the global variable 'lldb.frame' will NOT be updated when \
96027f1c96SDimitry Andric this function is called, so be sure to use the 'frame' argument. The 'frame' argument \
97027f1c96SDimitry Andric can get you to the thread via frame.GetThread(), the thread can get you to the \
98027f1c96SDimitry Andric process via thread.GetProcess(), and the process can get you back to the target \
9914f1b3e8SDimitry Andric via process.GetTarget()."
10014f1b3e8SDimitry Andric         R"(
101027f1c96SDimitry Andric 
10214f1b3e8SDimitry Andric )"
10314f1b3e8SDimitry Andric         "Important Note: As Python code gets collected into functions, access to global \
104027f1c96SDimitry Andric variables requires explicit scoping using the 'global' keyword.  Be sure to use correct \
10514f1b3e8SDimitry Andric Python syntax, including indentation, when entering Python watchpoint commands."
10614f1b3e8SDimitry Andric         R"(
107027f1c96SDimitry Andric 
108027f1c96SDimitry Andric Example Python one-line watchpoint command:
109027f1c96SDimitry Andric 
110027f1c96SDimitry Andric (lldb) watchpoint command add -s python 1
111027f1c96SDimitry Andric Enter your Python command(s). Type 'DONE' to end.
112027f1c96SDimitry Andric > print "Hit this watchpoint!"
113027f1c96SDimitry Andric > DONE
114027f1c96SDimitry Andric 
115027f1c96SDimitry Andric As a convenience, this also works for a short Python one-liner:
116027f1c96SDimitry Andric 
117027f1c96SDimitry Andric (lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()'
118027f1c96SDimitry Andric (lldb) run
119027f1c96SDimitry Andric Launching '.../a.out'  (x86_64)
120027f1c96SDimitry Andric (lldb) Fri Sep 10 12:17:45 2010
121027f1c96SDimitry Andric Process 21778 Stopped
122027f1c96SDimitry Andric * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread
123027f1c96SDimitry Andric   36
124027f1c96SDimitry Andric   37   	int c(int val)
125027f1c96SDimitry Andric   38   	{
126027f1c96SDimitry Andric   39 ->	    return val + 3;
127027f1c96SDimitry Andric   40   	}
128027f1c96SDimitry Andric   41
129027f1c96SDimitry Andric   42   	int main (int argc, char const *argv[])
130027f1c96SDimitry Andric 
131027f1c96SDimitry Andric Example multiple line Python watchpoint command, using function definition:
132027f1c96SDimitry Andric 
133027f1c96SDimitry Andric (lldb) watchpoint command add -s python 1
134027f1c96SDimitry Andric Enter your Python command(s). Type 'DONE' to end.
135027f1c96SDimitry Andric > def watchpoint_output (wp_no):
136027f1c96SDimitry Andric >     out_string = "Hit watchpoint number " + repr (wp_no)
137027f1c96SDimitry Andric >     print out_string
138027f1c96SDimitry Andric >     return True
139027f1c96SDimitry Andric > watchpoint_output (1)
140027f1c96SDimitry Andric > DONE
141027f1c96SDimitry Andric 
142027f1c96SDimitry Andric Example multiple line Python watchpoint command, using 'loose' Python:
143027f1c96SDimitry Andric 
144027f1c96SDimitry Andric (lldb) watchpoint command add -s p 1
145027f1c96SDimitry Andric Enter your Python command(s). Type 'DONE' to end.
146027f1c96SDimitry Andric > global wp_count
147027f1c96SDimitry Andric > wp_count = wp_count + 1
148027f1c96SDimitry Andric > print "Hit this watchpoint " + repr(wp_count) + " times!"
149027f1c96SDimitry Andric > DONE
150027f1c96SDimitry Andric 
15114f1b3e8SDimitry Andric )"
15214f1b3e8SDimitry Andric         "In this case, since there is a reference to a global variable, \
153027f1c96SDimitry Andric 'wp_count', you will also need to make sure 'wp_count' exists and is \
15414f1b3e8SDimitry Andric initialized:"
15514f1b3e8SDimitry Andric         R"(
156027f1c96SDimitry Andric 
157027f1c96SDimitry Andric (lldb) script
158027f1c96SDimitry Andric >>> wp_count = 0
159027f1c96SDimitry Andric >>> quit()
160027f1c96SDimitry Andric 
16114f1b3e8SDimitry Andric )"
16214f1b3e8SDimitry Andric         "Final Note: A warning that no watchpoint command was generated when there \
16314f1b3e8SDimitry Andric are no syntax errors may indicate that a function was declared but never called.");
164f034231aSEd Maste 
165ac9a064cSDimitry Andric     AddSimpleArgumentList(eArgTypeWatchpointID);
166f034231aSEd Maste   }
167f034231aSEd Maste 
168f3fbd1c0SDimitry Andric   ~CommandObjectWatchpointCommandAdd() override = default;
169f034231aSEd Maste 
GetOptions()17014f1b3e8SDimitry Andric   Options *GetOptions() override { return &m_options; }
171f034231aSEd Maste 
IOHandlerActivated(IOHandler & io_handler,bool interactive)1725f29bb8aSDimitry Andric   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
173ead24645SDimitry Andric     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
1745f29bb8aSDimitry Andric     if (output_sp && interactive) {
17514f1b3e8SDimitry Andric       output_sp->PutCString(
17614f1b3e8SDimitry Andric           "Enter your debugger command(s).  Type 'DONE' to end.\n");
177866dcdacSEd Maste       output_sp->Flush();
178866dcdacSEd Maste     }
179866dcdacSEd Maste   }
180866dcdacSEd Maste 
IOHandlerInputComplete(IOHandler & io_handler,std::string & line)18114f1b3e8SDimitry Andric   void IOHandlerInputComplete(IOHandler &io_handler,
18214f1b3e8SDimitry Andric                               std::string &line) override {
183866dcdacSEd Maste     io_handler.SetIsDone(true);
184866dcdacSEd Maste 
18514f1b3e8SDimitry Andric     // The WatchpointOptions object is owned by the watchpoint or watchpoint
18614f1b3e8SDimitry Andric     // location
18714f1b3e8SDimitry Andric     WatchpointOptions *wp_options =
18814f1b3e8SDimitry Andric         (WatchpointOptions *)io_handler.GetUserData();
18914f1b3e8SDimitry Andric     if (wp_options) {
1905f29bb8aSDimitry Andric       std::unique_ptr<WatchpointOptions::CommandData> data_up(
19114f1b3e8SDimitry Andric           new WatchpointOptions::CommandData());
1925f29bb8aSDimitry Andric       if (data_up) {
1935f29bb8aSDimitry Andric         data_up->user_source.SplitIntoLines(line);
19414f1b3e8SDimitry Andric         auto baton_sp = std::make_shared<WatchpointOptions::CommandBaton>(
1955f29bb8aSDimitry Andric             std::move(data_up));
196866dcdacSEd Maste         wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
197866dcdacSEd Maste       }
198866dcdacSEd Maste     }
199866dcdacSEd Maste   }
200866dcdacSEd Maste 
CollectDataForWatchpointCommandCallback(WatchpointOptions * wp_options,CommandReturnObject & result)20114f1b3e8SDimitry Andric   void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,
20214f1b3e8SDimitry Andric                                                CommandReturnObject &result) {
20314f1b3e8SDimitry Andric     m_interpreter.GetLLDBCommandsFromIOHandler(
20414f1b3e8SDimitry Andric         "> ",        // Prompt
205866dcdacSEd Maste         *this,       // IOHandlerDelegate
20614f1b3e8SDimitry Andric         wp_options); // Baton for the "io_handler" that will be passed back into
20714f1b3e8SDimitry Andric                      // our IOHandlerDelegate functions
208f034231aSEd Maste   }
209f034231aSEd Maste 
210f034231aSEd Maste   /// Set a one-liner as the callback for the watchpoint.
SetWatchpointCommandCallback(WatchpointOptions * wp_options,const char * oneliner)21114f1b3e8SDimitry Andric   void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
21214f1b3e8SDimitry Andric                                     const char *oneliner) {
2135f29bb8aSDimitry Andric     std::unique_ptr<WatchpointOptions::CommandData> data_up(
21414f1b3e8SDimitry Andric         new WatchpointOptions::CommandData());
215f034231aSEd Maste 
216f73363f1SDimitry Andric     // It's necessary to set both user_source and script_source to the
217f73363f1SDimitry Andric     // oneliner. The former is used to generate callback description (as in
218f73363f1SDimitry Andric     // watchpoint command list) while the latter is used for Python to
219f73363f1SDimitry Andric     // interpret during the actual callback.
2205f29bb8aSDimitry Andric     data_up->user_source.AppendString(oneliner);
2215f29bb8aSDimitry Andric     data_up->script_source.assign(oneliner);
2225f29bb8aSDimitry Andric     data_up->stop_on_error = m_options.m_stop_on_error;
223f034231aSEd Maste 
22414f1b3e8SDimitry Andric     auto baton_sp =
2255f29bb8aSDimitry Andric         std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_up));
226f034231aSEd Maste     wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
227f034231aSEd Maste   }
228f034231aSEd Maste 
229f034231aSEd Maste   static bool
WatchpointOptionsCallbackFunction(void * baton,StoppointCallbackContext * context,lldb::user_id_t watch_id)230f034231aSEd Maste   WatchpointOptionsCallbackFunction(void *baton,
231f034231aSEd Maste                                     StoppointCallbackContext *context,
23214f1b3e8SDimitry Andric                                     lldb::user_id_t watch_id) {
233f034231aSEd Maste     bool ret_value = true;
234f3fbd1c0SDimitry Andric     if (baton == nullptr)
235f034231aSEd Maste       return true;
236f034231aSEd Maste 
23714f1b3e8SDimitry Andric     WatchpointOptions::CommandData *data =
23814f1b3e8SDimitry Andric         (WatchpointOptions::CommandData *)baton;
239f034231aSEd Maste     StringList &commands = data->user_source;
240f034231aSEd Maste 
24114f1b3e8SDimitry Andric     if (commands.GetSize() > 0) {
242f034231aSEd Maste       ExecutionContext exe_ctx(context->exe_ctx_ref);
243f034231aSEd Maste       Target *target = exe_ctx.GetTargetPtr();
24414f1b3e8SDimitry Andric       if (target) {
245f034231aSEd Maste         Debugger &debugger = target->GetDebugger();
246cfca06d7SDimitry Andric         CommandReturnObject result(debugger.GetUseColor());
247cfca06d7SDimitry Andric 
24814f1b3e8SDimitry Andric         // Rig up the results secondary output stream to the debugger's, so the
249f73363f1SDimitry Andric         // output will come out synchronously if the debugger is set up that
250f73363f1SDimitry Andric         // way.
251f034231aSEd Maste         StreamSP output_stream(debugger.GetAsyncOutputStream());
252f034231aSEd Maste         StreamSP error_stream(debugger.GetAsyncErrorStream());
253f034231aSEd Maste         result.SetImmediateOutputStream(output_stream);
254f034231aSEd Maste         result.SetImmediateErrorStream(error_stream);
255f034231aSEd Maste 
256205afe67SEd Maste         CommandInterpreterRunOptions options;
257205afe67SEd Maste         options.SetStopOnContinue(true);
258205afe67SEd Maste         options.SetStopOnError(data->stop_on_error);
259205afe67SEd Maste         options.SetEchoCommands(false);
260205afe67SEd Maste         options.SetPrintResults(true);
2615f29bb8aSDimitry Andric         options.SetPrintErrors(true);
262205afe67SEd Maste         options.SetAddToHistory(false);
263f034231aSEd Maste 
264344a3780SDimitry Andric         debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx,
26514f1b3e8SDimitry Andric                                                         options, result);
266f034231aSEd Maste         result.GetImmediateOutputStream()->Flush();
267f034231aSEd Maste         result.GetImmediateErrorStream()->Flush();
268f034231aSEd Maste       }
269f034231aSEd Maste     }
270f034231aSEd Maste     return ret_value;
271f034231aSEd Maste   }
272f034231aSEd Maste 
27314f1b3e8SDimitry Andric   class CommandOptions : public Options {
274f034231aSEd Maste   public:
275145449b1SDimitry Andric     CommandOptions() = default;
276f034231aSEd Maste 
277f3fbd1c0SDimitry Andric     ~CommandOptions() override = default;
278f034231aSEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)279b76161e4SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
28014f1b3e8SDimitry Andric                           ExecutionContext *execution_context) override {
281b76161e4SDimitry Andric       Status error;
282f034231aSEd Maste       const int short_option = m_getopt_table[option_idx].val;
283f034231aSEd Maste 
28414f1b3e8SDimitry Andric       switch (short_option) {
285f034231aSEd Maste       case 'o':
286f034231aSEd Maste         m_use_one_liner = true;
287cfca06d7SDimitry Andric         m_one_liner = std::string(option_arg);
288f034231aSEd Maste         break;
289f034231aSEd Maste 
290f034231aSEd Maste       case 's':
291f73363f1SDimitry Andric         m_script_language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum(
29214f1b3e8SDimitry Andric             option_arg, GetDefinitions()[option_idx].enum_values,
29314f1b3e8SDimitry Andric             eScriptLanguageNone, error);
294f034231aSEd Maste 
295706b4fc4SDimitry Andric         switch (m_script_language) {
296706b4fc4SDimitry Andric         case eScriptLanguagePython:
297706b4fc4SDimitry Andric         case eScriptLanguageLua:
298706b4fc4SDimitry Andric           m_use_script_language = true;
299706b4fc4SDimitry Andric           break;
300706b4fc4SDimitry Andric         case eScriptLanguageNone:
301706b4fc4SDimitry Andric         case eScriptLanguageUnknown:
302706b4fc4SDimitry Andric           m_use_script_language = false;
303706b4fc4SDimitry Andric           break;
304706b4fc4SDimitry Andric         }
305f034231aSEd Maste         break;
306f034231aSEd Maste 
30714f1b3e8SDimitry Andric       case 'e': {
308f034231aSEd Maste         bool success = false;
309f73363f1SDimitry Andric         m_stop_on_error =
310f73363f1SDimitry Andric             OptionArgParser::ToBoolean(option_arg, false, &success);
311f034231aSEd Maste         if (!success)
31214f1b3e8SDimitry Andric           error.SetErrorStringWithFormat(
31314f1b3e8SDimitry Andric               "invalid value for stop-on-error: \"%s\"",
31414f1b3e8SDimitry Andric               option_arg.str().c_str());
31514f1b3e8SDimitry Andric       } break;
316f034231aSEd Maste 
317f034231aSEd Maste       case 'F':
318f034231aSEd Maste         m_use_one_liner = false;
319cfca06d7SDimitry Andric         m_function_name.assign(std::string(option_arg));
320f034231aSEd Maste         break;
321f034231aSEd Maste 
322f034231aSEd Maste       default:
323ead24645SDimitry Andric         llvm_unreachable("Unimplemented option");
324f034231aSEd Maste       }
325f034231aSEd Maste       return error;
326f034231aSEd Maste     }
327f3fbd1c0SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)32814f1b3e8SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
329f034231aSEd Maste       m_use_commands = true;
330f034231aSEd Maste       m_use_script_language = false;
331f034231aSEd Maste       m_script_language = eScriptLanguageNone;
332f034231aSEd Maste 
333f034231aSEd Maste       m_use_one_liner = false;
334f034231aSEd Maste       m_stop_on_error = true;
335f034231aSEd Maste       m_one_liner.clear();
336f034231aSEd Maste       m_function_name.clear();
337f034231aSEd Maste     }
338f034231aSEd Maste 
GetDefinitions()33914f1b3e8SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
340e3b55780SDimitry Andric       return llvm::ArrayRef(g_watchpoint_command_add_options);
341f034231aSEd Maste     }
342f034231aSEd Maste 
343f034231aSEd Maste     // Instance variables to hold the values for command options.
344f034231aSEd Maste 
345344a3780SDimitry Andric     bool m_use_commands = false;
346344a3780SDimitry Andric     bool m_use_script_language = false;
347344a3780SDimitry Andric     lldb::ScriptLanguage m_script_language = eScriptLanguageNone;
348f034231aSEd Maste 
349f034231aSEd Maste     // Instance variables to hold the values for one_liner options.
350344a3780SDimitry Andric     bool m_use_one_liner = false;
351f034231aSEd Maste     std::string m_one_liner;
352f034231aSEd Maste     bool m_stop_on_error;
353f034231aSEd Maste     std::string m_function_name;
354f034231aSEd Maste   };
355f034231aSEd Maste 
356f034231aSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)357b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
358ead24645SDimitry Andric     Target *target = &GetSelectedTarget();
359f034231aSEd Maste 
360f034231aSEd Maste     const WatchpointList &watchpoints = target->GetWatchpointList();
361f034231aSEd Maste     size_t num_watchpoints = watchpoints.GetSize();
362f034231aSEd Maste 
36314f1b3e8SDimitry Andric     if (num_watchpoints == 0) {
364f034231aSEd Maste       result.AppendError("No watchpoints exist to have commands added");
365b1c73532SDimitry Andric       return;
366f034231aSEd Maste     }
367f034231aSEd Maste 
368706b4fc4SDimitry Andric     if (!m_options.m_function_name.empty()) {
369706b4fc4SDimitry Andric       if (!m_options.m_use_script_language) {
370706b4fc4SDimitry Andric         m_options.m_script_language = GetDebugger().GetScriptLanguage();
371706b4fc4SDimitry Andric         m_options.m_use_script_language = true;
372706b4fc4SDimitry Andric       }
373f034231aSEd Maste     }
374f034231aSEd Maste 
375f034231aSEd Maste     std::vector<uint32_t> valid_wp_ids;
37614f1b3e8SDimitry Andric     if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
37714f1b3e8SDimitry Andric                                                                valid_wp_ids)) {
378f034231aSEd Maste       result.AppendError("Invalid watchpoints specification.");
379b1c73532SDimitry Andric       return;
380f034231aSEd Maste     }
381f034231aSEd Maste 
382f034231aSEd Maste     result.SetStatus(eReturnStatusSuccessFinishNoResult);
383f034231aSEd Maste     const size_t count = valid_wp_ids.size();
38414f1b3e8SDimitry Andric     for (size_t i = 0; i < count; ++i) {
385f034231aSEd Maste       uint32_t cur_wp_id = valid_wp_ids.at(i);
38614f1b3e8SDimitry Andric       if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
387f034231aSEd Maste         Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
388f034231aSEd Maste         // Sanity check wp first.
38914f1b3e8SDimitry Andric         if (wp == nullptr)
39014f1b3e8SDimitry Andric           continue;
391f034231aSEd Maste 
392f034231aSEd Maste         WatchpointOptions *wp_options = wp->GetOptions();
393f034231aSEd Maste         // Skip this watchpoint if wp_options is not good.
39414f1b3e8SDimitry Andric         if (wp_options == nullptr)
39514f1b3e8SDimitry Andric           continue;
396f034231aSEd Maste 
397f73363f1SDimitry Andric         // If we are using script language, get the script interpreter in order
398f73363f1SDimitry Andric         // to set or collect command callback.  Otherwise, call the methods
399f73363f1SDimitry Andric         // associated with this object.
40014f1b3e8SDimitry Andric         if (m_options.m_use_script_language) {
401706b4fc4SDimitry Andric           ScriptInterpreter *script_interp = GetDebugger().GetScriptInterpreter(
402706b4fc4SDimitry Andric               /*can_create=*/true, m_options.m_script_language);
403f034231aSEd Maste           // Special handling for one-liner specified inline.
40414f1b3e8SDimitry Andric           if (m_options.m_use_one_liner) {
405706b4fc4SDimitry Andric             script_interp->SetWatchpointCommandCallback(
4067fa27ce4SDimitry Andric                 wp_options, m_options.m_one_liner.c_str(),
4077fa27ce4SDimitry Andric                 /*is_callback=*/false);
408f034231aSEd Maste           }
409f73363f1SDimitry Andric           // Special handling for using a Python function by name instead of
410f73363f1SDimitry Andric           // extending the watchpoint callback data structures, we just
411f73363f1SDimitry Andric           // automatize what the user would do manually: make their watchpoint
412f73363f1SDimitry Andric           // command be a function call
41314f1b3e8SDimitry Andric           else if (!m_options.m_function_name.empty()) {
4147fa27ce4SDimitry Andric             std::string function_signature = m_options.m_function_name;
4157fa27ce4SDimitry Andric             function_signature += "(frame, wp, internal_dict)";
416706b4fc4SDimitry Andric             script_interp->SetWatchpointCommandCallback(
4177fa27ce4SDimitry Andric                 wp_options, function_signature.c_str(), /*is_callback=*/true);
41814f1b3e8SDimitry Andric           } else {
419706b4fc4SDimitry Andric             script_interp->CollectDataForWatchpointCommandCallback(wp_options,
420706b4fc4SDimitry Andric                                                                    result);
421f034231aSEd Maste           }
42214f1b3e8SDimitry Andric         } else {
423f034231aSEd Maste           // Special handling for one-liner specified inline.
424f034231aSEd Maste           if (m_options.m_use_one_liner)
425f034231aSEd Maste             SetWatchpointCommandCallback(wp_options,
426f034231aSEd Maste                                          m_options.m_one_liner.c_str());
427f034231aSEd Maste           else
42814f1b3e8SDimitry Andric             CollectDataForWatchpointCommandCallback(wp_options, result);
429f034231aSEd Maste         }
430f034231aSEd Maste       }
431f034231aSEd Maste     }
432f034231aSEd Maste   }
433f034231aSEd Maste 
434f034231aSEd Maste private:
435f034231aSEd Maste   CommandOptions m_options;
436f034231aSEd Maste };
437f034231aSEd Maste 
438f034231aSEd Maste // CommandObjectWatchpointCommandDelete
439f034231aSEd Maste 
44014f1b3e8SDimitry Andric class CommandObjectWatchpointCommandDelete : public CommandObjectParsed {
441f034231aSEd Maste public:
CommandObjectWatchpointCommandDelete(CommandInterpreter & interpreter)44214f1b3e8SDimitry Andric   CommandObjectWatchpointCommandDelete(CommandInterpreter &interpreter)
44314f1b3e8SDimitry Andric       : CommandObjectParsed(interpreter, "delete",
444f034231aSEd Maste                             "Delete the set of commands from a watchpoint.",
445ead24645SDimitry Andric                             nullptr, eCommandRequiresTarget) {
446ac9a064cSDimitry Andric     AddSimpleArgumentList(eArgTypeWatchpointID);
447f034231aSEd Maste   }
448f034231aSEd Maste 
449f3fbd1c0SDimitry Andric   ~CommandObjectWatchpointCommandDelete() override = default;
450f034231aSEd Maste 
451f034231aSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)452b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
453ead24645SDimitry Andric     Target *target = &GetSelectedTarget();
454f034231aSEd Maste 
455f034231aSEd Maste     const WatchpointList &watchpoints = target->GetWatchpointList();
456f034231aSEd Maste     size_t num_watchpoints = watchpoints.GetSize();
457f034231aSEd Maste 
45814f1b3e8SDimitry Andric     if (num_watchpoints == 0) {
459f034231aSEd Maste       result.AppendError("No watchpoints exist to have commands deleted");
460b1c73532SDimitry Andric       return;
461f034231aSEd Maste     }
462f034231aSEd Maste 
46314f1b3e8SDimitry Andric     if (command.GetArgumentCount() == 0) {
46414f1b3e8SDimitry Andric       result.AppendError(
46514f1b3e8SDimitry Andric           "No watchpoint specified from which to delete the commands");
466b1c73532SDimitry Andric       return;
467f034231aSEd Maste     }
468f034231aSEd Maste 
469f034231aSEd Maste     std::vector<uint32_t> valid_wp_ids;
47014f1b3e8SDimitry Andric     if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
47114f1b3e8SDimitry Andric                                                                valid_wp_ids)) {
472f034231aSEd Maste       result.AppendError("Invalid watchpoints specification.");
473b1c73532SDimitry Andric       return;
474f034231aSEd Maste     }
475f034231aSEd Maste 
476f034231aSEd Maste     result.SetStatus(eReturnStatusSuccessFinishNoResult);
477f034231aSEd Maste     const size_t count = valid_wp_ids.size();
47814f1b3e8SDimitry Andric     for (size_t i = 0; i < count; ++i) {
479f034231aSEd Maste       uint32_t cur_wp_id = valid_wp_ids.at(i);
48014f1b3e8SDimitry Andric       if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
481f034231aSEd Maste         Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
482f034231aSEd Maste         if (wp)
483f034231aSEd Maste           wp->ClearCallback();
48414f1b3e8SDimitry Andric       } else {
48514f1b3e8SDimitry Andric         result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
486b1c73532SDimitry Andric         return;
487f034231aSEd Maste       }
488f034231aSEd Maste     }
489f034231aSEd Maste   }
490f034231aSEd Maste };
491f034231aSEd Maste 
492f034231aSEd Maste // CommandObjectWatchpointCommandList
493f034231aSEd Maste 
49414f1b3e8SDimitry Andric class CommandObjectWatchpointCommandList : public CommandObjectParsed {
495f034231aSEd Maste public:
CommandObjectWatchpointCommandList(CommandInterpreter & interpreter)49614f1b3e8SDimitry Andric   CommandObjectWatchpointCommandList(CommandInterpreter &interpreter)
497ead24645SDimitry Andric       : CommandObjectParsed(interpreter, "list",
498ead24645SDimitry Andric                             "List the script or set of commands to be executed "
499ead24645SDimitry Andric                             "when the watchpoint is hit.",
500ead24645SDimitry Andric                             nullptr, eCommandRequiresTarget) {
501ac9a064cSDimitry Andric     AddSimpleArgumentList(eArgTypeWatchpointID);
502f034231aSEd Maste   }
503f034231aSEd Maste 
504f3fbd1c0SDimitry Andric   ~CommandObjectWatchpointCommandList() override = default;
505f034231aSEd Maste 
506f034231aSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)507b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
508ead24645SDimitry Andric     Target *target = &GetSelectedTarget();
509f034231aSEd Maste 
510f034231aSEd Maste     const WatchpointList &watchpoints = target->GetWatchpointList();
511f034231aSEd Maste     size_t num_watchpoints = watchpoints.GetSize();
512f034231aSEd Maste 
51314f1b3e8SDimitry Andric     if (num_watchpoints == 0) {
514f034231aSEd Maste       result.AppendError("No watchpoints exist for which to list commands");
515b1c73532SDimitry Andric       return;
516f034231aSEd Maste     }
517f034231aSEd Maste 
51814f1b3e8SDimitry Andric     if (command.GetArgumentCount() == 0) {
51914f1b3e8SDimitry Andric       result.AppendError(
52014f1b3e8SDimitry Andric           "No watchpoint specified for which to list the commands");
521b1c73532SDimitry Andric       return;
522f034231aSEd Maste     }
523f034231aSEd Maste 
524f034231aSEd Maste     std::vector<uint32_t> valid_wp_ids;
52514f1b3e8SDimitry Andric     if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
52614f1b3e8SDimitry Andric                                                                valid_wp_ids)) {
527f034231aSEd Maste       result.AppendError("Invalid watchpoints specification.");
528b1c73532SDimitry Andric       return;
529f034231aSEd Maste     }
530f034231aSEd Maste 
531f034231aSEd Maste     result.SetStatus(eReturnStatusSuccessFinishNoResult);
532f034231aSEd Maste     const size_t count = valid_wp_ids.size();
53314f1b3e8SDimitry Andric     for (size_t i = 0; i < count; ++i) {
534f034231aSEd Maste       uint32_t cur_wp_id = valid_wp_ids.at(i);
53514f1b3e8SDimitry Andric       if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
536f034231aSEd Maste         Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
537f034231aSEd Maste 
53814f1b3e8SDimitry Andric         if (wp) {
539f034231aSEd Maste           const WatchpointOptions *wp_options = wp->GetOptions();
54014f1b3e8SDimitry Andric           if (wp_options) {
541f034231aSEd Maste             // Get the callback baton associated with the current watchpoint.
542f034231aSEd Maste             const Baton *baton = wp_options->GetBaton();
54314f1b3e8SDimitry Andric             if (baton) {
544f034231aSEd Maste               result.GetOutputStream().Printf("Watchpoint %u:\n", cur_wp_id);
545706b4fc4SDimitry Andric               baton->GetDescription(result.GetOutputStream().AsRawOstream(),
546706b4fc4SDimitry Andric                                     eDescriptionLevelFull,
547706b4fc4SDimitry Andric                                     result.GetOutputStream().GetIndentLevel() +
548706b4fc4SDimitry Andric                                         2);
54914f1b3e8SDimitry Andric             } else {
55014f1b3e8SDimitry Andric               result.AppendMessageWithFormat(
55114f1b3e8SDimitry Andric                   "Watchpoint %u does not have an associated command.\n",
552f034231aSEd Maste                   cur_wp_id);
553f034231aSEd Maste             }
554f034231aSEd Maste           }
555f034231aSEd Maste           result.SetStatus(eReturnStatusSuccessFinishResult);
55614f1b3e8SDimitry Andric         } else {
55714f1b3e8SDimitry Andric           result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
55814f1b3e8SDimitry Andric                                        cur_wp_id);
559f034231aSEd Maste         }
560f034231aSEd Maste       }
561f034231aSEd Maste     }
562f034231aSEd Maste   }
563f034231aSEd Maste };
564f034231aSEd Maste 
565f034231aSEd Maste // CommandObjectWatchpointCommand
566f034231aSEd Maste 
CommandObjectWatchpointCommand(CommandInterpreter & interpreter)56714f1b3e8SDimitry Andric CommandObjectWatchpointCommand::CommandObjectWatchpointCommand(
56814f1b3e8SDimitry Andric     CommandInterpreter &interpreter)
56914f1b3e8SDimitry Andric     : CommandObjectMultiword(
57014f1b3e8SDimitry Andric           interpreter, "command",
57114f1b3e8SDimitry Andric           "Commands for adding, removing and examining LLDB commands "
572f73363f1SDimitry Andric           "executed when the watchpoint is hit (watchpoint 'commands').",
57314f1b3e8SDimitry Andric           "command <sub-command> [<sub-command-options>] <watchpoint-id>") {
57414f1b3e8SDimitry Andric   CommandObjectSP add_command_object(
57514f1b3e8SDimitry Andric       new CommandObjectWatchpointCommandAdd(interpreter));
57614f1b3e8SDimitry Andric   CommandObjectSP delete_command_object(
57714f1b3e8SDimitry Andric       new CommandObjectWatchpointCommandDelete(interpreter));
57814f1b3e8SDimitry Andric   CommandObjectSP list_command_object(
57914f1b3e8SDimitry Andric       new CommandObjectWatchpointCommandList(interpreter));
580f034231aSEd Maste 
581f034231aSEd Maste   add_command_object->SetCommandName("watchpoint command add");
582f034231aSEd Maste   delete_command_object->SetCommandName("watchpoint command delete");
583f034231aSEd Maste   list_command_object->SetCommandName("watchpoint command list");
584f034231aSEd Maste 
585f034231aSEd Maste   LoadSubCommand("add", add_command_object);
586f034231aSEd Maste   LoadSubCommand("delete", delete_command_object);
587f034231aSEd Maste   LoadSubCommand("list", list_command_object);
588f034231aSEd Maste }
589f034231aSEd Maste 
590f3fbd1c0SDimitry Andric CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand() = default;
591