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