1ac7ddfbfSEd Maste //===-- CommandObjectWatchpointCommand.cpp ----------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste // The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste
104bb0738eSEd Maste #include <vector>
11ac7ddfbfSEd Maste
12ac7ddfbfSEd Maste #include "CommandObjectWatchpoint.h"
13435933ddSDimitry Andric #include "CommandObjectWatchpointCommand.h"
14435933ddSDimitry Andric #include "lldb/Breakpoint/StoppointCallbackContext.h"
15435933ddSDimitry Andric #include "lldb/Breakpoint/Watchpoint.h"
1612b93ac6SEd Maste #include "lldb/Core/IOHandler.h"
17f678e45dSDimitry Andric #include "lldb/Host/OptionParser.h"
18ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandInterpreter.h"
19ac7ddfbfSEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
204ba319b5SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
21ac7ddfbfSEd Maste #include "lldb/Target/Target.h"
22ac7ddfbfSEd Maste #include "lldb/Target/Thread.h"
23*b5893f02SDimitry Andric #include "lldb/Utility/State.h"
24ac7ddfbfSEd Maste
25ac7ddfbfSEd Maste using namespace lldb;
26ac7ddfbfSEd Maste using namespace lldb_private;
27ac7ddfbfSEd Maste
28ac7ddfbfSEd Maste //-------------------------------------------------------------------------
29ac7ddfbfSEd Maste // CommandObjectWatchpointCommandAdd
30ac7ddfbfSEd Maste //-------------------------------------------------------------------------
31ac7ddfbfSEd Maste
32435933ddSDimitry Andric // FIXME: "script-type" needs to have its contents determined dynamically, so
33435933ddSDimitry Andric // somebody can add a new scripting
34435933ddSDimitry Andric // language to lldb and have it pickable here without having to change this
35435933ddSDimitry Andric // enumeration by hand and rebuild lldb proper.
36435933ddSDimitry Andric
37*b5893f02SDimitry Andric static constexpr OptionEnumValueElement g_script_option_enumeration[] = {
38435933ddSDimitry Andric {eScriptLanguageNone, "command",
39435933ddSDimitry Andric "Commands are in the lldb command interpreter language"},
40435933ddSDimitry Andric {eScriptLanguagePython, "python", "Commands are in the Python language."},
41435933ddSDimitry Andric {eSortOrderByName, "default-script",
42*b5893f02SDimitry Andric "Commands are in the default scripting language."} };
43435933ddSDimitry Andric
ScriptOptionEnum()44*b5893f02SDimitry Andric static constexpr OptionEnumValues ScriptOptionEnum() {
45*b5893f02SDimitry Andric return OptionEnumValues(g_script_option_enumeration);
46*b5893f02SDimitry Andric }
47*b5893f02SDimitry Andric
48*b5893f02SDimitry Andric static constexpr OptionDefinition g_watchpoint_command_add_options[] = {
49435933ddSDimitry Andric // clang-format off
50*b5893f02SDimitry Andric { LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeOneLiner, "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." },
51*b5893f02SDimitry Andric { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "Specify whether watchpoint command execution should terminate on error." },
52*b5893f02SDimitry Andric { LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, nullptr, ScriptOptionEnum(), 0, eArgTypeNone, "Specify the language for the commands - if none is specified, the lldb command interpreter will be used." },
53*b5893f02SDimitry Andric { LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePythonFunction, "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate." }
54435933ddSDimitry Andric // clang-format on
55435933ddSDimitry Andric };
56435933ddSDimitry Andric
57435933ddSDimitry Andric class CommandObjectWatchpointCommandAdd : public CommandObjectParsed,
58435933ddSDimitry Andric public IOHandlerDelegateMultiline {
59ac7ddfbfSEd Maste public:
CommandObjectWatchpointCommandAdd(CommandInterpreter & interpreter)604bb0738eSEd Maste CommandObjectWatchpointCommandAdd(CommandInterpreter &interpreter)
61435933ddSDimitry Andric : CommandObjectParsed(interpreter, "add",
62435933ddSDimitry Andric "Add a set of LLDB commands to a watchpoint, to be "
63435933ddSDimitry Andric "executed whenever the watchpoint is hit.",
64435933ddSDimitry Andric nullptr),
65435933ddSDimitry Andric IOHandlerDelegateMultiline("DONE",
66435933ddSDimitry Andric IOHandlerDelegate::Completion::LLDBCommand),
67435933ddSDimitry Andric m_options() {
68ac7ddfbfSEd Maste SetHelpLong(
69b91a7dfcSDimitry Andric R"(
70b91a7dfcSDimitry Andric General information about entering watchpoint commands
71b91a7dfcSDimitry Andric ------------------------------------------------------
72b91a7dfcSDimitry Andric
73435933ddSDimitry Andric )"
74435933ddSDimitry Andric "This command will prompt for commands to be executed when the specified \
75b91a7dfcSDimitry Andric watchpoint is hit. Each command is typed on its own line following the '> ' \
76435933ddSDimitry Andric prompt until 'DONE' is entered."
77435933ddSDimitry Andric R"(
78b91a7dfcSDimitry Andric
79435933ddSDimitry Andric )"
80435933ddSDimitry Andric "Syntactic errors may not be detected when initially entered, and many \
81b91a7dfcSDimitry Andric malformed commands can silently fail when executed. If your watchpoint commands \
82435933ddSDimitry Andric do not appear to be executing, double-check the command syntax."
83435933ddSDimitry Andric R"(
84b91a7dfcSDimitry Andric
85435933ddSDimitry Andric )"
86435933ddSDimitry Andric "Note: You may enter any debugger command exactly as you would at the debugger \
87b91a7dfcSDimitry Andric prompt. There is no limit to the number of commands supplied, but do NOT enter \
88435933ddSDimitry Andric more than one command per line."
89435933ddSDimitry Andric R"(
90b91a7dfcSDimitry Andric
91b91a7dfcSDimitry Andric Special information about PYTHON watchpoint commands
92b91a7dfcSDimitry Andric ----------------------------------------------------
93b91a7dfcSDimitry Andric
94435933ddSDimitry Andric )"
95435933ddSDimitry Andric "You may enter either one or more lines of Python, including function \
96b91a7dfcSDimitry Andric definitions or calls to functions that will have been imported by the time \
97b91a7dfcSDimitry Andric the code executes. Single line watchpoint commands will be interpreted 'as is' \
98b91a7dfcSDimitry Andric when the watchpoint is hit. Multiple lines of Python will be wrapped in a \
99435933ddSDimitry Andric generated function, and a call to the function will be attached to the watchpoint."
100435933ddSDimitry Andric R"(
101b91a7dfcSDimitry Andric
102b91a7dfcSDimitry Andric This auto-generated function is passed in three arguments:
103b91a7dfcSDimitry Andric
104b91a7dfcSDimitry Andric frame: an lldb.SBFrame object for the frame which hit the watchpoint.
105b91a7dfcSDimitry Andric
106b91a7dfcSDimitry Andric wp: the watchpoint that was hit.
107b91a7dfcSDimitry Andric
108435933ddSDimitry Andric )"
109435933ddSDimitry Andric "When specifying a python function with the --python-function option, you need \
110435933ddSDimitry Andric to supply the function name prepended by the module name:"
111435933ddSDimitry Andric R"(
112b91a7dfcSDimitry Andric
113b91a7dfcSDimitry Andric --python-function myutils.watchpoint_callback
114b91a7dfcSDimitry Andric
115b91a7dfcSDimitry Andric The function itself must have the following prototype:
116b91a7dfcSDimitry Andric
117b91a7dfcSDimitry Andric def watchpoint_callback(frame, wp):
118b91a7dfcSDimitry Andric # Your code goes here
119b91a7dfcSDimitry Andric
120435933ddSDimitry Andric )"
121435933ddSDimitry Andric "The arguments are the same as the arguments passed to generated functions as \
122b91a7dfcSDimitry Andric described above. Note that the global variable 'lldb.frame' will NOT be updated when \
123b91a7dfcSDimitry Andric this function is called, so be sure to use the 'frame' argument. The 'frame' argument \
124b91a7dfcSDimitry Andric can get you to the thread via frame.GetThread(), the thread can get you to the \
125b91a7dfcSDimitry Andric process via thread.GetProcess(), and the process can get you back to the target \
126435933ddSDimitry Andric via process.GetTarget()."
127435933ddSDimitry Andric R"(
128b91a7dfcSDimitry Andric
129435933ddSDimitry Andric )"
130435933ddSDimitry Andric "Important Note: As Python code gets collected into functions, access to global \
131b91a7dfcSDimitry Andric variables requires explicit scoping using the 'global' keyword. Be sure to use correct \
132435933ddSDimitry Andric Python syntax, including indentation, when entering Python watchpoint commands."
133435933ddSDimitry Andric R"(
134b91a7dfcSDimitry Andric
135b91a7dfcSDimitry Andric Example Python one-line watchpoint command:
136b91a7dfcSDimitry Andric
137b91a7dfcSDimitry Andric (lldb) watchpoint command add -s python 1
138b91a7dfcSDimitry Andric Enter your Python command(s). Type 'DONE' to end.
139b91a7dfcSDimitry Andric > print "Hit this watchpoint!"
140b91a7dfcSDimitry Andric > DONE
141b91a7dfcSDimitry Andric
142b91a7dfcSDimitry Andric As a convenience, this also works for a short Python one-liner:
143b91a7dfcSDimitry Andric
144b91a7dfcSDimitry Andric (lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()'
145b91a7dfcSDimitry Andric (lldb) run
146b91a7dfcSDimitry Andric Launching '.../a.out' (x86_64)
147b91a7dfcSDimitry Andric (lldb) Fri Sep 10 12:17:45 2010
148b91a7dfcSDimitry Andric Process 21778 Stopped
149b91a7dfcSDimitry Andric * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread
150b91a7dfcSDimitry Andric 36
151b91a7dfcSDimitry Andric 37 int c(int val)
152b91a7dfcSDimitry Andric 38 {
153b91a7dfcSDimitry Andric 39 -> return val + 3;
154b91a7dfcSDimitry Andric 40 }
155b91a7dfcSDimitry Andric 41
156b91a7dfcSDimitry Andric 42 int main (int argc, char const *argv[])
157b91a7dfcSDimitry Andric
158b91a7dfcSDimitry Andric Example multiple line Python watchpoint command, using function definition:
159b91a7dfcSDimitry Andric
160b91a7dfcSDimitry Andric (lldb) watchpoint command add -s python 1
161b91a7dfcSDimitry Andric Enter your Python command(s). Type 'DONE' to end.
162b91a7dfcSDimitry Andric > def watchpoint_output (wp_no):
163b91a7dfcSDimitry Andric > out_string = "Hit watchpoint number " + repr (wp_no)
164b91a7dfcSDimitry Andric > print out_string
165b91a7dfcSDimitry Andric > return True
166b91a7dfcSDimitry Andric > watchpoint_output (1)
167b91a7dfcSDimitry Andric > DONE
168b91a7dfcSDimitry Andric
169b91a7dfcSDimitry Andric Example multiple line Python watchpoint command, using 'loose' Python:
170b91a7dfcSDimitry Andric
171b91a7dfcSDimitry Andric (lldb) watchpoint command add -s p 1
172b91a7dfcSDimitry Andric Enter your Python command(s). Type 'DONE' to end.
173b91a7dfcSDimitry Andric > global wp_count
174b91a7dfcSDimitry Andric > wp_count = wp_count + 1
175b91a7dfcSDimitry Andric > print "Hit this watchpoint " + repr(wp_count) + " times!"
176b91a7dfcSDimitry Andric > DONE
177b91a7dfcSDimitry Andric
178435933ddSDimitry Andric )"
179435933ddSDimitry Andric "In this case, since there is a reference to a global variable, \
180b91a7dfcSDimitry Andric 'wp_count', you will also need to make sure 'wp_count' exists and is \
181435933ddSDimitry Andric initialized:"
182435933ddSDimitry Andric R"(
183b91a7dfcSDimitry Andric
184b91a7dfcSDimitry Andric (lldb) script
185b91a7dfcSDimitry Andric >>> wp_count = 0
186b91a7dfcSDimitry Andric >>> quit()
187b91a7dfcSDimitry Andric
188435933ddSDimitry Andric )"
189435933ddSDimitry Andric "Final Note: A warning that no watchpoint command was generated when there \
190435933ddSDimitry Andric are no syntax errors may indicate that a function was declared but never called.");
191ac7ddfbfSEd Maste
192ac7ddfbfSEd Maste CommandArgumentEntry arg;
193ac7ddfbfSEd Maste CommandArgumentData wp_id_arg;
194ac7ddfbfSEd Maste
195ac7ddfbfSEd Maste // Define the first (and only) variant of this arg.
196ac7ddfbfSEd Maste wp_id_arg.arg_type = eArgTypeWatchpointID;
197ac7ddfbfSEd Maste wp_id_arg.arg_repetition = eArgRepeatPlain;
198ac7ddfbfSEd Maste
199435933ddSDimitry Andric // There is only one variant this argument could be; put it into the
200435933ddSDimitry Andric // argument entry.
201ac7ddfbfSEd Maste arg.push_back(wp_id_arg);
202ac7ddfbfSEd Maste
203ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector.
204ac7ddfbfSEd Maste m_arguments.push_back(arg);
205ac7ddfbfSEd Maste }
206ac7ddfbfSEd Maste
2074bb0738eSEd Maste ~CommandObjectWatchpointCommandAdd() override = default;
208ac7ddfbfSEd Maste
GetOptions()209435933ddSDimitry Andric Options *GetOptions() override { return &m_options; }
210ac7ddfbfSEd Maste
IOHandlerActivated(IOHandler & io_handler)211435933ddSDimitry Andric void IOHandlerActivated(IOHandler &io_handler) override {
21212b93ac6SEd Maste StreamFileSP output_sp(io_handler.GetOutputStreamFile());
213435933ddSDimitry Andric if (output_sp) {
214435933ddSDimitry Andric output_sp->PutCString(
215435933ddSDimitry Andric "Enter your debugger command(s). Type 'DONE' to end.\n");
21612b93ac6SEd Maste output_sp->Flush();
21712b93ac6SEd Maste }
21812b93ac6SEd Maste }
21912b93ac6SEd Maste
IOHandlerInputComplete(IOHandler & io_handler,std::string & line)220435933ddSDimitry Andric void IOHandlerInputComplete(IOHandler &io_handler,
221435933ddSDimitry Andric std::string &line) override {
22212b93ac6SEd Maste io_handler.SetIsDone(true);
22312b93ac6SEd Maste
224435933ddSDimitry Andric // The WatchpointOptions object is owned by the watchpoint or watchpoint
225435933ddSDimitry Andric // location
226435933ddSDimitry Andric WatchpointOptions *wp_options =
227435933ddSDimitry Andric (WatchpointOptions *)io_handler.GetUserData();
228435933ddSDimitry Andric if (wp_options) {
229435933ddSDimitry Andric std::unique_ptr<WatchpointOptions::CommandData> data_ap(
230435933ddSDimitry Andric new WatchpointOptions::CommandData());
231435933ddSDimitry Andric if (data_ap) {
23212b93ac6SEd Maste data_ap->user_source.SplitIntoLines(line);
233435933ddSDimitry Andric auto baton_sp = std::make_shared<WatchpointOptions::CommandBaton>(
234435933ddSDimitry Andric std::move(data_ap));
23512b93ac6SEd Maste wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
23612b93ac6SEd Maste }
23712b93ac6SEd Maste }
23812b93ac6SEd Maste }
23912b93ac6SEd Maste
CollectDataForWatchpointCommandCallback(WatchpointOptions * wp_options,CommandReturnObject & result)240435933ddSDimitry Andric void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,
241435933ddSDimitry Andric CommandReturnObject &result) {
242435933ddSDimitry Andric m_interpreter.GetLLDBCommandsFromIOHandler(
243435933ddSDimitry Andric "> ", // Prompt
24412b93ac6SEd Maste *this, // IOHandlerDelegate
24512b93ac6SEd Maste true, // Run IOHandler in async mode
246435933ddSDimitry Andric wp_options); // Baton for the "io_handler" that will be passed back into
247435933ddSDimitry Andric // our IOHandlerDelegate functions
248ac7ddfbfSEd Maste }
249ac7ddfbfSEd Maste
250ac7ddfbfSEd Maste /// Set a one-liner as the callback for the watchpoint.
SetWatchpointCommandCallback(WatchpointOptions * wp_options,const char * oneliner)251435933ddSDimitry Andric void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
252435933ddSDimitry Andric const char *oneliner) {
253435933ddSDimitry Andric std::unique_ptr<WatchpointOptions::CommandData> data_ap(
254435933ddSDimitry Andric new WatchpointOptions::CommandData());
255ac7ddfbfSEd Maste
2564ba319b5SDimitry Andric // It's necessary to set both user_source and script_source to the
2574ba319b5SDimitry Andric // oneliner. The former is used to generate callback description (as in
2584ba319b5SDimitry Andric // watchpoint command list) while the latter is used for Python to
2594ba319b5SDimitry Andric // interpret during the actual callback.
260ac7ddfbfSEd Maste data_ap->user_source.AppendString(oneliner);
261ac7ddfbfSEd Maste data_ap->script_source.assign(oneliner);
262ac7ddfbfSEd Maste data_ap->stop_on_error = m_options.m_stop_on_error;
263ac7ddfbfSEd Maste
264435933ddSDimitry Andric auto baton_sp =
265435933ddSDimitry Andric std::make_shared<WatchpointOptions::CommandBaton>(std::move(data_ap));
266ac7ddfbfSEd Maste wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
267ac7ddfbfSEd Maste }
268ac7ddfbfSEd Maste
269ac7ddfbfSEd Maste static bool
WatchpointOptionsCallbackFunction(void * baton,StoppointCallbackContext * context,lldb::user_id_t watch_id)270ac7ddfbfSEd Maste WatchpointOptionsCallbackFunction(void *baton,
271ac7ddfbfSEd Maste StoppointCallbackContext *context,
272435933ddSDimitry Andric lldb::user_id_t watch_id) {
273ac7ddfbfSEd Maste bool ret_value = true;
2744bb0738eSEd Maste if (baton == nullptr)
275ac7ddfbfSEd Maste return true;
276ac7ddfbfSEd Maste
277435933ddSDimitry Andric WatchpointOptions::CommandData *data =
278435933ddSDimitry Andric (WatchpointOptions::CommandData *)baton;
279ac7ddfbfSEd Maste StringList &commands = data->user_source;
280ac7ddfbfSEd Maste
281435933ddSDimitry Andric if (commands.GetSize() > 0) {
282ac7ddfbfSEd Maste ExecutionContext exe_ctx(context->exe_ctx_ref);
283ac7ddfbfSEd Maste Target *target = exe_ctx.GetTargetPtr();
284435933ddSDimitry Andric if (target) {
285ac7ddfbfSEd Maste CommandReturnObject result;
286ac7ddfbfSEd Maste Debugger &debugger = target->GetDebugger();
287435933ddSDimitry Andric // Rig up the results secondary output stream to the debugger's, so the
2884ba319b5SDimitry Andric // output will come out synchronously if the debugger is set up that
2894ba319b5SDimitry Andric // way.
290ac7ddfbfSEd Maste
291ac7ddfbfSEd Maste StreamSP output_stream(debugger.GetAsyncOutputStream());
292ac7ddfbfSEd Maste StreamSP error_stream(debugger.GetAsyncErrorStream());
293ac7ddfbfSEd Maste result.SetImmediateOutputStream(output_stream);
294ac7ddfbfSEd Maste result.SetImmediateErrorStream(error_stream);
295ac7ddfbfSEd Maste
2967aa51b79SEd Maste CommandInterpreterRunOptions options;
2977aa51b79SEd Maste options.SetStopOnContinue(true);
2987aa51b79SEd Maste options.SetStopOnError(data->stop_on_error);
2997aa51b79SEd Maste options.SetEchoCommands(false);
3007aa51b79SEd Maste options.SetPrintResults(true);
3017aa51b79SEd Maste options.SetAddToHistory(false);
302ac7ddfbfSEd Maste
303435933ddSDimitry Andric debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx,
304435933ddSDimitry Andric options, result);
305ac7ddfbfSEd Maste result.GetImmediateOutputStream()->Flush();
306ac7ddfbfSEd Maste result.GetImmediateErrorStream()->Flush();
307ac7ddfbfSEd Maste }
308ac7ddfbfSEd Maste }
309ac7ddfbfSEd Maste return ret_value;
310ac7ddfbfSEd Maste }
311ac7ddfbfSEd Maste
312435933ddSDimitry Andric class CommandOptions : public Options {
313ac7ddfbfSEd Maste public:
CommandOptions()314435933ddSDimitry Andric CommandOptions()
315435933ddSDimitry Andric : Options(), m_use_commands(false), m_use_script_language(false),
316435933ddSDimitry Andric m_script_language(eScriptLanguageNone), m_use_one_liner(false),
317435933ddSDimitry Andric m_one_liner(), m_function_name() {}
318ac7ddfbfSEd Maste
3194bb0738eSEd Maste ~CommandOptions() override = default;
320ac7ddfbfSEd Maste
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)3215517e702SDimitry Andric Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
322435933ddSDimitry Andric ExecutionContext *execution_context) override {
3235517e702SDimitry Andric Status error;
324ac7ddfbfSEd Maste const int short_option = m_getopt_table[option_idx].val;
325ac7ddfbfSEd Maste
326435933ddSDimitry Andric switch (short_option) {
327ac7ddfbfSEd Maste case 'o':
328ac7ddfbfSEd Maste m_use_one_liner = true;
329ac7ddfbfSEd Maste m_one_liner = option_arg;
330ac7ddfbfSEd Maste break;
331ac7ddfbfSEd Maste
332ac7ddfbfSEd Maste case 's':
3334ba319b5SDimitry Andric m_script_language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum(
334435933ddSDimitry Andric option_arg, GetDefinitions()[option_idx].enum_values,
335435933ddSDimitry Andric eScriptLanguageNone, error);
336ac7ddfbfSEd Maste
337435933ddSDimitry Andric m_use_script_language = (m_script_language == eScriptLanguagePython ||
338435933ddSDimitry Andric m_script_language == eScriptLanguageDefault);
339ac7ddfbfSEd Maste break;
340ac7ddfbfSEd Maste
341435933ddSDimitry Andric case 'e': {
342ac7ddfbfSEd Maste bool success = false;
3434ba319b5SDimitry Andric m_stop_on_error =
3444ba319b5SDimitry Andric OptionArgParser::ToBoolean(option_arg, false, &success);
345ac7ddfbfSEd Maste if (!success)
346435933ddSDimitry Andric error.SetErrorStringWithFormat(
347435933ddSDimitry Andric "invalid value for stop-on-error: \"%s\"",
348435933ddSDimitry Andric option_arg.str().c_str());
349435933ddSDimitry Andric } break;
350ac7ddfbfSEd Maste
351ac7ddfbfSEd Maste case 'F':
352ac7ddfbfSEd Maste m_use_one_liner = false;
353ac7ddfbfSEd Maste m_use_script_language = true;
354ac7ddfbfSEd Maste m_function_name.assign(option_arg);
355ac7ddfbfSEd Maste break;
356ac7ddfbfSEd Maste
357ac7ddfbfSEd Maste default:
358ac7ddfbfSEd Maste break;
359ac7ddfbfSEd Maste }
360ac7ddfbfSEd Maste return error;
361ac7ddfbfSEd Maste }
3624bb0738eSEd Maste
OptionParsingStarting(ExecutionContext * execution_context)363435933ddSDimitry Andric void OptionParsingStarting(ExecutionContext *execution_context) override {
364ac7ddfbfSEd Maste m_use_commands = true;
365ac7ddfbfSEd Maste m_use_script_language = false;
366ac7ddfbfSEd Maste m_script_language = eScriptLanguageNone;
367ac7ddfbfSEd Maste
368ac7ddfbfSEd Maste m_use_one_liner = false;
369ac7ddfbfSEd Maste m_stop_on_error = true;
370ac7ddfbfSEd Maste m_one_liner.clear();
371ac7ddfbfSEd Maste m_function_name.clear();
372ac7ddfbfSEd Maste }
373ac7ddfbfSEd Maste
GetDefinitions()374435933ddSDimitry Andric llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
375435933ddSDimitry Andric return llvm::makeArrayRef(g_watchpoint_command_add_options);
376ac7ddfbfSEd Maste }
377ac7ddfbfSEd Maste
378ac7ddfbfSEd Maste // Instance variables to hold the values for command options.
379ac7ddfbfSEd Maste
380ac7ddfbfSEd Maste bool m_use_commands;
381ac7ddfbfSEd Maste bool m_use_script_language;
382ac7ddfbfSEd Maste lldb::ScriptLanguage m_script_language;
383ac7ddfbfSEd Maste
384ac7ddfbfSEd Maste // Instance variables to hold the values for one_liner options.
385ac7ddfbfSEd Maste bool m_use_one_liner;
386ac7ddfbfSEd Maste std::string m_one_liner;
387ac7ddfbfSEd Maste bool m_stop_on_error;
388ac7ddfbfSEd Maste std::string m_function_name;
389ac7ddfbfSEd Maste };
390ac7ddfbfSEd Maste
391ac7ddfbfSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)392435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override {
393ac7ddfbfSEd Maste Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
394ac7ddfbfSEd Maste
395435933ddSDimitry Andric if (target == nullptr) {
396435933ddSDimitry Andric result.AppendError("There is not a current executable; there are no "
397435933ddSDimitry Andric "watchpoints to which to add commands");
398ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
399ac7ddfbfSEd Maste return false;
400ac7ddfbfSEd Maste }
401ac7ddfbfSEd Maste
402ac7ddfbfSEd Maste const WatchpointList &watchpoints = target->GetWatchpointList();
403ac7ddfbfSEd Maste size_t num_watchpoints = watchpoints.GetSize();
404ac7ddfbfSEd Maste
405435933ddSDimitry Andric if (num_watchpoints == 0) {
406ac7ddfbfSEd Maste result.AppendError("No watchpoints exist to have commands added");
407ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
408ac7ddfbfSEd Maste return false;
409ac7ddfbfSEd Maste }
410ac7ddfbfSEd Maste
411435933ddSDimitry Andric if (!m_options.m_use_script_language &&
412435933ddSDimitry Andric !m_options.m_function_name.empty()) {
413435933ddSDimitry Andric result.AppendError("need to enable scripting to have a function run as a "
414435933ddSDimitry Andric "watchpoint command");
415ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
416ac7ddfbfSEd Maste return false;
417ac7ddfbfSEd Maste }
418ac7ddfbfSEd Maste
419ac7ddfbfSEd Maste std::vector<uint32_t> valid_wp_ids;
420435933ddSDimitry Andric if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
421435933ddSDimitry Andric valid_wp_ids)) {
422ac7ddfbfSEd Maste result.AppendError("Invalid watchpoints specification.");
423ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
424ac7ddfbfSEd Maste return false;
425ac7ddfbfSEd Maste }
426ac7ddfbfSEd Maste
427ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult);
428ac7ddfbfSEd Maste const size_t count = valid_wp_ids.size();
429435933ddSDimitry Andric for (size_t i = 0; i < count; ++i) {
430ac7ddfbfSEd Maste uint32_t cur_wp_id = valid_wp_ids.at(i);
431435933ddSDimitry Andric if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
432ac7ddfbfSEd Maste Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
433ac7ddfbfSEd Maste // Sanity check wp first.
434435933ddSDimitry Andric if (wp == nullptr)
435435933ddSDimitry Andric continue;
436ac7ddfbfSEd Maste
437ac7ddfbfSEd Maste WatchpointOptions *wp_options = wp->GetOptions();
438ac7ddfbfSEd Maste // Skip this watchpoint if wp_options is not good.
439435933ddSDimitry Andric if (wp_options == nullptr)
440435933ddSDimitry Andric continue;
441ac7ddfbfSEd Maste
4424ba319b5SDimitry Andric // If we are using script language, get the script interpreter in order
4434ba319b5SDimitry Andric // to set or collect command callback. Otherwise, call the methods
4444ba319b5SDimitry Andric // associated with this object.
445435933ddSDimitry Andric if (m_options.m_use_script_language) {
446ac7ddfbfSEd Maste // Special handling for one-liner specified inline.
447435933ddSDimitry Andric if (m_options.m_use_one_liner) {
448435933ddSDimitry Andric m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback(
449435933ddSDimitry Andric wp_options, m_options.m_one_liner.c_str());
450ac7ddfbfSEd Maste }
4514ba319b5SDimitry Andric // Special handling for using a Python function by name instead of
4524ba319b5SDimitry Andric // extending the watchpoint callback data structures, we just
4534ba319b5SDimitry Andric // automatize what the user would do manually: make their watchpoint
4544ba319b5SDimitry Andric // command be a function call
455435933ddSDimitry Andric else if (!m_options.m_function_name.empty()) {
456ac7ddfbfSEd Maste std::string oneliner(m_options.m_function_name);
457ac7ddfbfSEd Maste oneliner += "(frame, wp, internal_dict)";
458435933ddSDimitry Andric m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback(
459435933ddSDimitry Andric wp_options, oneliner.c_str());
460435933ddSDimitry Andric } else {
461435933ddSDimitry Andric m_interpreter.GetScriptInterpreter()
462435933ddSDimitry Andric ->CollectDataForWatchpointCommandCallback(wp_options, result);
463ac7ddfbfSEd Maste }
464435933ddSDimitry Andric } else {
465ac7ddfbfSEd Maste // Special handling for one-liner specified inline.
466ac7ddfbfSEd Maste if (m_options.m_use_one_liner)
467ac7ddfbfSEd Maste SetWatchpointCommandCallback(wp_options,
468ac7ddfbfSEd Maste m_options.m_one_liner.c_str());
469ac7ddfbfSEd Maste else
470435933ddSDimitry Andric CollectDataForWatchpointCommandCallback(wp_options, result);
471ac7ddfbfSEd Maste }
472ac7ddfbfSEd Maste }
473ac7ddfbfSEd Maste }
474ac7ddfbfSEd Maste
475ac7ddfbfSEd Maste return result.Succeeded();
476ac7ddfbfSEd Maste }
477ac7ddfbfSEd Maste
478ac7ddfbfSEd Maste private:
479ac7ddfbfSEd Maste CommandOptions m_options;
480ac7ddfbfSEd Maste };
481ac7ddfbfSEd Maste
482ac7ddfbfSEd Maste //-------------------------------------------------------------------------
483ac7ddfbfSEd Maste // CommandObjectWatchpointCommandDelete
484ac7ddfbfSEd Maste //-------------------------------------------------------------------------
485ac7ddfbfSEd Maste
486435933ddSDimitry Andric class CommandObjectWatchpointCommandDelete : public CommandObjectParsed {
487ac7ddfbfSEd Maste public:
CommandObjectWatchpointCommandDelete(CommandInterpreter & interpreter)488435933ddSDimitry Andric CommandObjectWatchpointCommandDelete(CommandInterpreter &interpreter)
489435933ddSDimitry Andric : CommandObjectParsed(interpreter, "delete",
490ac7ddfbfSEd Maste "Delete the set of commands from a watchpoint.",
491435933ddSDimitry Andric nullptr) {
492ac7ddfbfSEd Maste CommandArgumentEntry arg;
493ac7ddfbfSEd Maste CommandArgumentData wp_id_arg;
494ac7ddfbfSEd Maste
495ac7ddfbfSEd Maste // Define the first (and only) variant of this arg.
496ac7ddfbfSEd Maste wp_id_arg.arg_type = eArgTypeWatchpointID;
497ac7ddfbfSEd Maste wp_id_arg.arg_repetition = eArgRepeatPlain;
498ac7ddfbfSEd Maste
499435933ddSDimitry Andric // There is only one variant this argument could be; put it into the
500435933ddSDimitry Andric // argument entry.
501ac7ddfbfSEd Maste arg.push_back(wp_id_arg);
502ac7ddfbfSEd Maste
503ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector.
504ac7ddfbfSEd Maste m_arguments.push_back(arg);
505ac7ddfbfSEd Maste }
506ac7ddfbfSEd Maste
5074bb0738eSEd Maste ~CommandObjectWatchpointCommandDelete() override = default;
508ac7ddfbfSEd Maste
509ac7ddfbfSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)510435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override {
511ac7ddfbfSEd Maste Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
512ac7ddfbfSEd Maste
513435933ddSDimitry Andric if (target == nullptr) {
514435933ddSDimitry Andric result.AppendError("There is not a current executable; there are no "
515435933ddSDimitry Andric "watchpoints from which to delete commands");
516ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
517ac7ddfbfSEd Maste return false;
518ac7ddfbfSEd Maste }
519ac7ddfbfSEd Maste
520ac7ddfbfSEd Maste const WatchpointList &watchpoints = target->GetWatchpointList();
521ac7ddfbfSEd Maste size_t num_watchpoints = watchpoints.GetSize();
522ac7ddfbfSEd Maste
523435933ddSDimitry Andric if (num_watchpoints == 0) {
524ac7ddfbfSEd Maste result.AppendError("No watchpoints exist to have commands deleted");
525ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
526ac7ddfbfSEd Maste return false;
527ac7ddfbfSEd Maste }
528ac7ddfbfSEd Maste
529435933ddSDimitry Andric if (command.GetArgumentCount() == 0) {
530435933ddSDimitry Andric result.AppendError(
531435933ddSDimitry Andric "No watchpoint specified from which to delete the commands");
532ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
533ac7ddfbfSEd Maste return false;
534ac7ddfbfSEd Maste }
535ac7ddfbfSEd Maste
536ac7ddfbfSEd Maste std::vector<uint32_t> valid_wp_ids;
537435933ddSDimitry Andric if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
538435933ddSDimitry Andric valid_wp_ids)) {
539ac7ddfbfSEd Maste result.AppendError("Invalid watchpoints specification.");
540ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
541ac7ddfbfSEd Maste return false;
542ac7ddfbfSEd Maste }
543ac7ddfbfSEd Maste
544ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult);
545ac7ddfbfSEd Maste const size_t count = valid_wp_ids.size();
546435933ddSDimitry Andric for (size_t i = 0; i < count; ++i) {
547ac7ddfbfSEd Maste uint32_t cur_wp_id = valid_wp_ids.at(i);
548435933ddSDimitry Andric if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
549ac7ddfbfSEd Maste Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
550ac7ddfbfSEd Maste if (wp)
551ac7ddfbfSEd Maste wp->ClearCallback();
552435933ddSDimitry Andric } else {
553435933ddSDimitry Andric result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
554ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
555ac7ddfbfSEd Maste return false;
556ac7ddfbfSEd Maste }
557ac7ddfbfSEd Maste }
558ac7ddfbfSEd Maste return result.Succeeded();
559ac7ddfbfSEd Maste }
560ac7ddfbfSEd Maste };
561ac7ddfbfSEd Maste
562ac7ddfbfSEd Maste //-------------------------------------------------------------------------
563ac7ddfbfSEd Maste // CommandObjectWatchpointCommandList
564ac7ddfbfSEd Maste //-------------------------------------------------------------------------
565ac7ddfbfSEd Maste
566435933ddSDimitry Andric class CommandObjectWatchpointCommandList : public CommandObjectParsed {
567ac7ddfbfSEd Maste public:
CommandObjectWatchpointCommandList(CommandInterpreter & interpreter)568435933ddSDimitry Andric CommandObjectWatchpointCommandList(CommandInterpreter &interpreter)
569435933ddSDimitry Andric : CommandObjectParsed(interpreter, "list", "List the script or set of "
570435933ddSDimitry Andric "commands to be executed when "
571435933ddSDimitry Andric "the watchpoint is hit.",
572435933ddSDimitry Andric nullptr) {
573ac7ddfbfSEd Maste CommandArgumentEntry arg;
574ac7ddfbfSEd Maste CommandArgumentData wp_id_arg;
575ac7ddfbfSEd Maste
576ac7ddfbfSEd Maste // Define the first (and only) variant of this arg.
577ac7ddfbfSEd Maste wp_id_arg.arg_type = eArgTypeWatchpointID;
578ac7ddfbfSEd Maste wp_id_arg.arg_repetition = eArgRepeatPlain;
579ac7ddfbfSEd Maste
580435933ddSDimitry Andric // There is only one variant this argument could be; put it into the
581435933ddSDimitry Andric // argument entry.
582ac7ddfbfSEd Maste arg.push_back(wp_id_arg);
583ac7ddfbfSEd Maste
584ac7ddfbfSEd Maste // Push the data for the first argument into the m_arguments vector.
585ac7ddfbfSEd Maste m_arguments.push_back(arg);
586ac7ddfbfSEd Maste }
587ac7ddfbfSEd Maste
5884bb0738eSEd Maste ~CommandObjectWatchpointCommandList() override = default;
589ac7ddfbfSEd Maste
590ac7ddfbfSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)591435933ddSDimitry Andric bool DoExecute(Args &command, CommandReturnObject &result) override {
592ac7ddfbfSEd Maste Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
593ac7ddfbfSEd Maste
594435933ddSDimitry Andric if (target == nullptr) {
595435933ddSDimitry Andric result.AppendError("There is not a current executable; there are no "
596435933ddSDimitry Andric "watchpoints for which to list commands");
597ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
598ac7ddfbfSEd Maste return false;
599ac7ddfbfSEd Maste }
600ac7ddfbfSEd Maste
601ac7ddfbfSEd Maste const WatchpointList &watchpoints = target->GetWatchpointList();
602ac7ddfbfSEd Maste size_t num_watchpoints = watchpoints.GetSize();
603ac7ddfbfSEd Maste
604435933ddSDimitry Andric if (num_watchpoints == 0) {
605ac7ddfbfSEd Maste result.AppendError("No watchpoints exist for which to list commands");
606ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
607ac7ddfbfSEd Maste return false;
608ac7ddfbfSEd Maste }
609ac7ddfbfSEd Maste
610435933ddSDimitry Andric if (command.GetArgumentCount() == 0) {
611435933ddSDimitry Andric result.AppendError(
612435933ddSDimitry Andric "No watchpoint specified for which to list the commands");
613ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
614ac7ddfbfSEd Maste return false;
615ac7ddfbfSEd Maste }
616ac7ddfbfSEd Maste
617ac7ddfbfSEd Maste std::vector<uint32_t> valid_wp_ids;
618435933ddSDimitry Andric if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
619435933ddSDimitry Andric valid_wp_ids)) {
620ac7ddfbfSEd Maste result.AppendError("Invalid watchpoints specification.");
621ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
622ac7ddfbfSEd Maste return false;
623ac7ddfbfSEd Maste }
624ac7ddfbfSEd Maste
625ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishNoResult);
626ac7ddfbfSEd Maste const size_t count = valid_wp_ids.size();
627435933ddSDimitry Andric for (size_t i = 0; i < count; ++i) {
628ac7ddfbfSEd Maste uint32_t cur_wp_id = valid_wp_ids.at(i);
629435933ddSDimitry Andric if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
630ac7ddfbfSEd Maste Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
631ac7ddfbfSEd Maste
632435933ddSDimitry Andric if (wp) {
633ac7ddfbfSEd Maste const WatchpointOptions *wp_options = wp->GetOptions();
634435933ddSDimitry Andric if (wp_options) {
635ac7ddfbfSEd Maste // Get the callback baton associated with the current watchpoint.
636ac7ddfbfSEd Maste const Baton *baton = wp_options->GetBaton();
637435933ddSDimitry Andric if (baton) {
638ac7ddfbfSEd Maste result.GetOutputStream().Printf("Watchpoint %u:\n", cur_wp_id);
639ac7ddfbfSEd Maste result.GetOutputStream().IndentMore();
640435933ddSDimitry Andric baton->GetDescription(&result.GetOutputStream(),
641435933ddSDimitry Andric eDescriptionLevelFull);
642ac7ddfbfSEd Maste result.GetOutputStream().IndentLess();
643435933ddSDimitry Andric } else {
644435933ddSDimitry Andric result.AppendMessageWithFormat(
645435933ddSDimitry Andric "Watchpoint %u does not have an associated command.\n",
646ac7ddfbfSEd Maste cur_wp_id);
647ac7ddfbfSEd Maste }
648ac7ddfbfSEd Maste }
649ac7ddfbfSEd Maste result.SetStatus(eReturnStatusSuccessFinishResult);
650435933ddSDimitry Andric } else {
651435933ddSDimitry Andric result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
652435933ddSDimitry Andric cur_wp_id);
653ac7ddfbfSEd Maste result.SetStatus(eReturnStatusFailed);
654ac7ddfbfSEd Maste }
655ac7ddfbfSEd Maste }
656ac7ddfbfSEd Maste }
657ac7ddfbfSEd Maste
658ac7ddfbfSEd Maste return result.Succeeded();
659ac7ddfbfSEd Maste }
660ac7ddfbfSEd Maste };
661ac7ddfbfSEd Maste
662ac7ddfbfSEd Maste //-------------------------------------------------------------------------
663ac7ddfbfSEd Maste // CommandObjectWatchpointCommand
664ac7ddfbfSEd Maste //-------------------------------------------------------------------------
665ac7ddfbfSEd Maste
CommandObjectWatchpointCommand(CommandInterpreter & interpreter)666435933ddSDimitry Andric CommandObjectWatchpointCommand::CommandObjectWatchpointCommand(
667435933ddSDimitry Andric CommandInterpreter &interpreter)
668435933ddSDimitry Andric : CommandObjectMultiword(
669435933ddSDimitry Andric interpreter, "command",
670435933ddSDimitry Andric "Commands for adding, removing and examining LLDB commands "
6714ba319b5SDimitry Andric "executed when the watchpoint is hit (watchpoint 'commands').",
672435933ddSDimitry Andric "command <sub-command> [<sub-command-options>] <watchpoint-id>") {
673435933ddSDimitry Andric CommandObjectSP add_command_object(
674435933ddSDimitry Andric new CommandObjectWatchpointCommandAdd(interpreter));
675435933ddSDimitry Andric CommandObjectSP delete_command_object(
676435933ddSDimitry Andric new CommandObjectWatchpointCommandDelete(interpreter));
677435933ddSDimitry Andric CommandObjectSP list_command_object(
678435933ddSDimitry Andric new CommandObjectWatchpointCommandList(interpreter));
679ac7ddfbfSEd Maste
680ac7ddfbfSEd Maste add_command_object->SetCommandName("watchpoint command add");
681ac7ddfbfSEd Maste delete_command_object->SetCommandName("watchpoint command delete");
682ac7ddfbfSEd Maste list_command_object->SetCommandName("watchpoint command list");
683ac7ddfbfSEd Maste
684ac7ddfbfSEd Maste LoadSubCommand("add", add_command_object);
685ac7ddfbfSEd Maste LoadSubCommand("delete", delete_command_object);
686ac7ddfbfSEd Maste LoadSubCommand("list", list_command_object);
687ac7ddfbfSEd Maste }
688ac7ddfbfSEd Maste
6894bb0738eSEd Maste CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand() = default;
690