blob: 1cd253bf89e11df93abba378b3c20725d1bcc1dc [file] [log] [blame]
Johnny Chene9a56272012-08-09 23:09:42 +00001//===-- CommandObjectWatchpointCommand.cpp ----------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// C Includes
11// C++ Includes
Eugene Zelenko49bcfd82016-02-23 01:43:44 +000012#include <vector>
Johnny Chene9a56272012-08-09 23:09:42 +000013
Eugene Zelenko49bcfd82016-02-23 01:43:44 +000014// Other libraries and framework includes
15// Project includes
Johnny Chene9a56272012-08-09 23:09:42 +000016#include "CommandObjectWatchpoint.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000017#include "CommandObjectWatchpointCommand.h"
18#include "lldb/Breakpoint/StoppointCallbackContext.h"
19#include "lldb/Breakpoint/Watchpoint.h"
Greg Clayton44d93782014-01-27 23:43:24 +000020#include "lldb/Core/IOHandler.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000021#include "lldb/Core/State.h"
Johnny Chene9a56272012-08-09 23:09:42 +000022#include "lldb/Interpreter/CommandInterpreter.h"
23#include "lldb/Interpreter/CommandReturnObject.h"
24#include "lldb/Target/Target.h"
25#include "lldb/Target/Thread.h"
Johnny Chene9a56272012-08-09 23:09:42 +000026
Johnny Chene9a56272012-08-09 23:09:42 +000027using namespace lldb;
28using namespace lldb_private;
29
30//-------------------------------------------------------------------------
31// CommandObjectWatchpointCommandAdd
32//-------------------------------------------------------------------------
33
Kate Stoneb9c1b512016-09-06 20:57:50 +000034class CommandObjectWatchpointCommandAdd : public CommandObjectParsed,
35 public IOHandlerDelegateMultiline {
Johnny Chene9a56272012-08-09 23:09:42 +000036public:
Kate Stoneb9c1b512016-09-06 20:57:50 +000037 CommandObjectWatchpointCommandAdd(CommandInterpreter &interpreter)
38 : CommandObjectParsed(interpreter, "add",
39 "Add a set of LLDB commands to a watchpoint, to be "
40 "executed whenever the watchpoint is hit.",
41 nullptr),
42 IOHandlerDelegateMultiline("DONE",
43 IOHandlerDelegate::Completion::LLDBCommand),
44 m_options() {
45 SetHelpLong(
46 R"(
Kate Stoneea671fb2015-07-14 05:48:36 +000047General information about entering watchpoint commands
48------------------------------------------------------
49
Kate Stoneb9c1b512016-09-06 20:57:50 +000050)"
51 "This command will prompt for commands to be executed when the specified \
Kate Stoneea671fb2015-07-14 05:48:36 +000052watchpoint is hit. Each command is typed on its own line following the '> ' \
Kate Stoneb9c1b512016-09-06 20:57:50 +000053prompt until 'DONE' is entered."
54 R"(
Kate Stoneea671fb2015-07-14 05:48:36 +000055
Kate Stoneb9c1b512016-09-06 20:57:50 +000056)"
57 "Syntactic errors may not be detected when initially entered, and many \
Kate Stoneea671fb2015-07-14 05:48:36 +000058malformed commands can silently fail when executed. If your watchpoint commands \
Kate Stoneb9c1b512016-09-06 20:57:50 +000059do not appear to be executing, double-check the command syntax."
60 R"(
Kate Stoneea671fb2015-07-14 05:48:36 +000061
Kate Stoneb9c1b512016-09-06 20:57:50 +000062)"
63 "Note: You may enter any debugger command exactly as you would at the debugger \
Kate Stoneea671fb2015-07-14 05:48:36 +000064prompt. There is no limit to the number of commands supplied, but do NOT enter \
Kate Stoneb9c1b512016-09-06 20:57:50 +000065more than one command per line."
66 R"(
Kate Stoneea671fb2015-07-14 05:48:36 +000067
68Special information about PYTHON watchpoint commands
69----------------------------------------------------
70
Kate Stoneb9c1b512016-09-06 20:57:50 +000071)"
72 "You may enter either one or more lines of Python, including function \
Kate Stoneea671fb2015-07-14 05:48:36 +000073definitions or calls to functions that will have been imported by the time \
74the code executes. Single line watchpoint commands will be interpreted 'as is' \
75when the watchpoint is hit. Multiple lines of Python will be wrapped in a \
Kate Stoneb9c1b512016-09-06 20:57:50 +000076generated function, and a call to the function will be attached to the watchpoint."
77 R"(
Kate Stoneea671fb2015-07-14 05:48:36 +000078
79This auto-generated function is passed in three arguments:
80
81 frame: an lldb.SBFrame object for the frame which hit the watchpoint.
82
83 wp: the watchpoint that was hit.
84
Kate Stoneb9c1b512016-09-06 20:57:50 +000085)"
86 "When specifying a python function with the --python-function option, you need \
87to supply the function name prepended by the module name:"
88 R"(
Kate Stoneea671fb2015-07-14 05:48:36 +000089
90 --python-function myutils.watchpoint_callback
91
92The function itself must have the following prototype:
93
94def watchpoint_callback(frame, wp):
95 # Your code goes here
96
Kate Stoneb9c1b512016-09-06 20:57:50 +000097)"
98 "The arguments are the same as the arguments passed to generated functions as \
Kate Stoneea671fb2015-07-14 05:48:36 +000099described above. Note that the global variable 'lldb.frame' will NOT be updated when \
100this function is called, so be sure to use the 'frame' argument. The 'frame' argument \
101can get you to the thread via frame.GetThread(), the thread can get you to the \
102process via thread.GetProcess(), and the process can get you back to the target \
Kate Stoneb9c1b512016-09-06 20:57:50 +0000103via process.GetTarget()."
104 R"(
Kate Stoneea671fb2015-07-14 05:48:36 +0000105
Kate Stoneb9c1b512016-09-06 20:57:50 +0000106)"
107 "Important Note: As Python code gets collected into functions, access to global \
Kate Stoneea671fb2015-07-14 05:48:36 +0000108variables requires explicit scoping using the 'global' keyword. Be sure to use correct \
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109Python syntax, including indentation, when entering Python watchpoint commands."
110 R"(
Kate Stoneea671fb2015-07-14 05:48:36 +0000111
112Example Python one-line watchpoint command:
113
114(lldb) watchpoint command add -s python 1
115Enter your Python command(s). Type 'DONE' to end.
116> print "Hit this watchpoint!"
117> DONE
118
119As a convenience, this also works for a short Python one-liner:
120
121(lldb) watchpoint command add -s python 1 -o 'import time; print time.asctime()'
122(lldb) run
123Launching '.../a.out' (x86_64)
124(lldb) Fri Sep 10 12:17:45 2010
125Process 21778 Stopped
126* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread
127 36
128 37 int c(int val)
129 38 {
130 39 -> return val + 3;
131 40 }
132 41
133 42 int main (int argc, char const *argv[])
134
135Example multiple line Python watchpoint command, using function definition:
136
137(lldb) watchpoint command add -s python 1
138Enter your Python command(s). Type 'DONE' to end.
139> def watchpoint_output (wp_no):
140> out_string = "Hit watchpoint number " + repr (wp_no)
141> print out_string
142> return True
143> watchpoint_output (1)
144> DONE
145
146Example multiple line Python watchpoint command, using 'loose' Python:
147
148(lldb) watchpoint command add -s p 1
149Enter your Python command(s). Type 'DONE' to end.
150> global wp_count
151> wp_count = wp_count + 1
152> print "Hit this watchpoint " + repr(wp_count) + " times!"
153> DONE
154
Kate Stoneb9c1b512016-09-06 20:57:50 +0000155)"
156 "In this case, since there is a reference to a global variable, \
Kate Stoneea671fb2015-07-14 05:48:36 +0000157'wp_count', you will also need to make sure 'wp_count' exists and is \
Kate Stoneb9c1b512016-09-06 20:57:50 +0000158initialized:"
159 R"(
Kate Stoneea671fb2015-07-14 05:48:36 +0000160
161(lldb) script
162>>> wp_count = 0
163>>> quit()
164
Kate Stoneb9c1b512016-09-06 20:57:50 +0000165)"
166 "Final Note: A warning that no watchpoint command was generated when there \
167are no syntax errors may indicate that a function was declared but never called.");
Johnny Chene9a56272012-08-09 23:09:42 +0000168
Kate Stoneb9c1b512016-09-06 20:57:50 +0000169 CommandArgumentEntry arg;
170 CommandArgumentData wp_id_arg;
Johnny Chene9a56272012-08-09 23:09:42 +0000171
Kate Stoneb9c1b512016-09-06 20:57:50 +0000172 // Define the first (and only) variant of this arg.
173 wp_id_arg.arg_type = eArgTypeWatchpointID;
174 wp_id_arg.arg_repetition = eArgRepeatPlain;
Johnny Chene9a56272012-08-09 23:09:42 +0000175
Kate Stoneb9c1b512016-09-06 20:57:50 +0000176 // There is only one variant this argument could be; put it into the
177 // argument entry.
178 arg.push_back(wp_id_arg);
Johnny Chene9a56272012-08-09 23:09:42 +0000179
Kate Stoneb9c1b512016-09-06 20:57:50 +0000180 // Push the data for the first argument into the m_arguments vector.
181 m_arguments.push_back(arg);
182 }
183
184 ~CommandObjectWatchpointCommandAdd() override = default;
185
186 Options *GetOptions() override { return &m_options; }
187
188 void IOHandlerActivated(IOHandler &io_handler) override {
189 StreamFileSP output_sp(io_handler.GetOutputStreamFile());
190 if (output_sp) {
191 output_sp->PutCString(
192 "Enter your debugger command(s). Type 'DONE' to end.\n");
193 output_sp->Flush();
194 }
195 }
196
197 void IOHandlerInputComplete(IOHandler &io_handler,
198 std::string &line) override {
199 io_handler.SetIsDone(true);
200
201 // The WatchpointOptions object is owned by the watchpoint or watchpoint
202 // location
203 WatchpointOptions *wp_options =
204 (WatchpointOptions *)io_handler.GetUserData();
205 if (wp_options) {
206 std::unique_ptr<WatchpointOptions::CommandData> data_ap(
207 new WatchpointOptions::CommandData());
208 if (data_ap) {
209 data_ap->user_source.SplitIntoLines(line);
210 BatonSP baton_sp(
211 new WatchpointOptions::CommandBaton(data_ap.release()));
212 wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
213 }
214 }
215 }
216
217 void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,
218 CommandReturnObject &result) {
219 m_interpreter.GetLLDBCommandsFromIOHandler(
220 "> ", // Prompt
221 *this, // IOHandlerDelegate
222 true, // Run IOHandler in async mode
223 wp_options); // Baton for the "io_handler" that will be passed back into
224 // our IOHandlerDelegate functions
225 }
226
227 /// Set a one-liner as the callback for the watchpoint.
228 void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
229 const char *oneliner) {
230 std::unique_ptr<WatchpointOptions::CommandData> data_ap(
231 new WatchpointOptions::CommandData());
232
233 // It's necessary to set both user_source and script_source to the oneliner.
234 // The former is used to generate callback description (as in watchpoint
235 // command list)
236 // while the latter is used for Python to interpret during the actual
237 // callback.
238 data_ap->user_source.AppendString(oneliner);
239 data_ap->script_source.assign(oneliner);
240 data_ap->stop_on_error = m_options.m_stop_on_error;
241
242 BatonSP baton_sp(new WatchpointOptions::CommandBaton(data_ap.release()));
243 wp_options->SetCallback(WatchpointOptionsCallbackFunction, baton_sp);
244 }
245
246 static bool
247 WatchpointOptionsCallbackFunction(void *baton,
248 StoppointCallbackContext *context,
249 lldb::user_id_t watch_id) {
250 bool ret_value = true;
251 if (baton == nullptr)
252 return true;
253
254 WatchpointOptions::CommandData *data =
255 (WatchpointOptions::CommandData *)baton;
256 StringList &commands = data->user_source;
257
258 if (commands.GetSize() > 0) {
259 ExecutionContext exe_ctx(context->exe_ctx_ref);
260 Target *target = exe_ctx.GetTargetPtr();
261 if (target) {
262 CommandReturnObject result;
263 Debugger &debugger = target->GetDebugger();
264 // Rig up the results secondary output stream to the debugger's, so the
265 // output will come out synchronously
266 // if the debugger is set up that way.
267
268 StreamSP output_stream(debugger.GetAsyncOutputStream());
269 StreamSP error_stream(debugger.GetAsyncErrorStream());
270 result.SetImmediateOutputStream(output_stream);
271 result.SetImmediateErrorStream(error_stream);
272
273 CommandInterpreterRunOptions options;
274 options.SetStopOnContinue(true);
275 options.SetStopOnError(data->stop_on_error);
276 options.SetEchoCommands(false);
277 options.SetPrintResults(true);
278 options.SetAddToHistory(false);
279
280 debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx,
281 options, result);
282 result.GetImmediateOutputStream()->Flush();
283 result.GetImmediateErrorStream()->Flush();
284 }
285 }
286 return ret_value;
287 }
288
289 class CommandOptions : public Options {
290 public:
291 CommandOptions()
292 : Options(), m_use_commands(false), m_use_script_language(false),
293 m_script_language(eScriptLanguageNone), m_use_one_liner(false),
294 m_one_liner(), m_function_name() {}
295
296 ~CommandOptions() override = default;
297
298 Error SetOptionValue(uint32_t option_idx, const char *option_arg,
299 ExecutionContext *execution_context) override {
300 Error error;
301 const int short_option = m_getopt_table[option_idx].val;
302
303 switch (short_option) {
304 case 'o':
305 m_use_one_liner = true;
306 m_one_liner = option_arg;
307 break;
308
309 case 's':
310 m_script_language = (lldb::ScriptLanguage)Args::StringToOptionEnum(
311 option_arg, g_option_table[option_idx].enum_values,
312 eScriptLanguageNone, error);
313
314 m_use_script_language = (m_script_language == eScriptLanguagePython ||
315 m_script_language == eScriptLanguageDefault);
316 break;
317
318 case 'e': {
319 bool success = false;
320 m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
321 if (!success)
322 error.SetErrorStringWithFormat(
323 "invalid value for stop-on-error: \"%s\"", option_arg);
324 } break;
325
326 case 'F':
327 m_use_one_liner = false;
328 m_use_script_language = true;
329 m_function_name.assign(option_arg);
330 break;
331
332 default:
333 break;
334 }
335 return error;
Johnny Chene9a56272012-08-09 23:09:42 +0000336 }
337
Kate Stoneb9c1b512016-09-06 20:57:50 +0000338 void OptionParsingStarting(ExecutionContext *execution_context) override {
339 m_use_commands = true;
340 m_use_script_language = false;
341 m_script_language = eScriptLanguageNone;
Johnny Chene9a56272012-08-09 23:09:42 +0000342
Kate Stoneb9c1b512016-09-06 20:57:50 +0000343 m_use_one_liner = false;
344 m_stop_on_error = true;
345 m_one_liner.clear();
346 m_function_name.clear();
Johnny Chene9a56272012-08-09 23:09:42 +0000347 }
348
Kate Stoneb9c1b512016-09-06 20:57:50 +0000349 const OptionDefinition *GetDefinitions() override { return g_option_table; }
Eugene Zelenko49bcfd82016-02-23 01:43:44 +0000350
Kate Stoneb9c1b512016-09-06 20:57:50 +0000351 // Options table: Required for subclasses of Options.
Greg Clayton44d93782014-01-27 23:43:24 +0000352
Kate Stoneb9c1b512016-09-06 20:57:50 +0000353 static OptionDefinition g_option_table[];
Johnny Chene9a56272012-08-09 23:09:42 +0000354
Kate Stoneb9c1b512016-09-06 20:57:50 +0000355 // Instance variables to hold the values for command options.
Johnny Chene9a56272012-08-09 23:09:42 +0000356
Kate Stoneb9c1b512016-09-06 20:57:50 +0000357 bool m_use_commands;
358 bool m_use_script_language;
359 lldb::ScriptLanguage m_script_language;
Eugene Zelenko49bcfd82016-02-23 01:43:44 +0000360
Kate Stoneb9c1b512016-09-06 20:57:50 +0000361 // Instance variables to hold the values for one_liner options.
362 bool m_use_one_liner;
363 std::string m_one_liner;
364 bool m_stop_on_error;
365 std::string m_function_name;
366 };
Johnny Chene9a56272012-08-09 23:09:42 +0000367
368protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000369 bool DoExecute(Args &command, CommandReturnObject &result) override {
370 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
Johnny Chene9a56272012-08-09 23:09:42 +0000371
Kate Stoneb9c1b512016-09-06 20:57:50 +0000372 if (target == nullptr) {
373 result.AppendError("There is not a current executable; there are no "
374 "watchpoints to which to add commands");
375 result.SetStatus(eReturnStatusFailed);
376 return false;
Johnny Chene9a56272012-08-09 23:09:42 +0000377 }
378
Kate Stoneb9c1b512016-09-06 20:57:50 +0000379 const WatchpointList &watchpoints = target->GetWatchpointList();
380 size_t num_watchpoints = watchpoints.GetSize();
381
382 if (num_watchpoints == 0) {
383 result.AppendError("No watchpoints exist to have commands added");
384 result.SetStatus(eReturnStatusFailed);
385 return false;
386 }
387
388 if (!m_options.m_use_script_language &&
389 !m_options.m_function_name.empty()) {
390 result.AppendError("need to enable scripting to have a function run as a "
391 "watchpoint command");
392 result.SetStatus(eReturnStatusFailed);
393 return false;
394 }
395
396 std::vector<uint32_t> valid_wp_ids;
397 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
398 valid_wp_ids)) {
399 result.AppendError("Invalid watchpoints specification.");
400 result.SetStatus(eReturnStatusFailed);
401 return false;
402 }
403
404 result.SetStatus(eReturnStatusSuccessFinishNoResult);
405 const size_t count = valid_wp_ids.size();
406 for (size_t i = 0; i < count; ++i) {
407 uint32_t cur_wp_id = valid_wp_ids.at(i);
408 if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
409 Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
410 // Sanity check wp first.
411 if (wp == nullptr)
412 continue;
413
414 WatchpointOptions *wp_options = wp->GetOptions();
415 // Skip this watchpoint if wp_options is not good.
416 if (wp_options == nullptr)
417 continue;
418
419 // If we are using script language, get the script interpreter
420 // in order to set or collect command callback. Otherwise, call
421 // the methods associated with this object.
422 if (m_options.m_use_script_language) {
423 // Special handling for one-liner specified inline.
424 if (m_options.m_use_one_liner) {
425 m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback(
426 wp_options, m_options.m_one_liner.c_str());
427 }
428 // Special handling for using a Python function by name
429 // instead of extending the watchpoint callback data structures, we
430 // just automatize
431 // what the user would do manually: make their watchpoint command be a
432 // function call
433 else if (!m_options.m_function_name.empty()) {
434 std::string oneliner(m_options.m_function_name);
435 oneliner += "(frame, wp, internal_dict)";
436 m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback(
437 wp_options, oneliner.c_str());
438 } else {
439 m_interpreter.GetScriptInterpreter()
440 ->CollectDataForWatchpointCommandCallback(wp_options, result);
441 }
442 } else {
443 // Special handling for one-liner specified inline.
444 if (m_options.m_use_one_liner)
445 SetWatchpointCommandCallback(wp_options,
446 m_options.m_one_liner.c_str());
447 else
448 CollectDataForWatchpointCommandCallback(wp_options, result);
449 }
450 }
451 }
452
453 return result.Succeeded();
454 }
455
Johnny Chene9a56272012-08-09 23:09:42 +0000456private:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000457 CommandOptions m_options;
Johnny Chene9a56272012-08-09 23:09:42 +0000458};
459
Kate Stoneb9c1b512016-09-06 20:57:50 +0000460// FIXME: "script-type" needs to have its contents determined dynamically, so
461// somebody can add a new scripting
462// language to lldb and have it pickable here without having to change this
463// enumeration by hand and rebuild lldb proper.
Johnny Chene9a56272012-08-09 23:09:42 +0000464
Kate Stoneb9c1b512016-09-06 20:57:50 +0000465static OptionEnumValueElement g_script_option_enumeration[4] = {
466 {eScriptLanguageNone, "command",
467 "Commands are in the lldb command interpreter language"},
468 {eScriptLanguagePython, "python", "Commands are in the Python language."},
469 {eSortOrderByName, "default-script",
470 "Commands are in the default scripting language."},
471 {0, nullptr, nullptr}};
Johnny Chene9a56272012-08-09 23:09:42 +0000472
473OptionDefinition
Kate Stoneb9c1b512016-09-06 20:57:50 +0000474 CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] = {
475 // clang-format off
Kate Stoneac9c3a62016-08-26 23:28:47 +0000476 {LLDB_OPT_SET_1, false, "one-liner", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOneLiner, "Specify a one-line watchpoint command inline. Be sure to surround it with quotes."},
477 {LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Specify whether watchpoint command execution should terminate on error."},
478 {LLDB_OPT_SET_ALL, false, "script-type", 's', OptionParser::eRequiredArgument, nullptr, g_script_option_enumeration, 0, eArgTypeNone, "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
479 {LLDB_OPT_SET_2, false, "python-function", 'F', OptionParser::eRequiredArgument, nullptr, 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."},
480 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000481 // clang-format on
Johnny Chene9a56272012-08-09 23:09:42 +0000482};
483
484//-------------------------------------------------------------------------
485// CommandObjectWatchpointCommandDelete
486//-------------------------------------------------------------------------
487
Kate Stoneb9c1b512016-09-06 20:57:50 +0000488class CommandObjectWatchpointCommandDelete : public CommandObjectParsed {
Johnny Chene9a56272012-08-09 23:09:42 +0000489public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000490 CommandObjectWatchpointCommandDelete(CommandInterpreter &interpreter)
491 : CommandObjectParsed(interpreter, "delete",
Eugene Zelenko49bcfd82016-02-23 01:43:44 +0000492 "Delete the set of commands from a watchpoint.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000493 nullptr) {
494 CommandArgumentEntry arg;
495 CommandArgumentData wp_id_arg;
Johnny Chene9a56272012-08-09 23:09:42 +0000496
Kate Stoneb9c1b512016-09-06 20:57:50 +0000497 // Define the first (and only) variant of this arg.
498 wp_id_arg.arg_type = eArgTypeWatchpointID;
499 wp_id_arg.arg_repetition = eArgRepeatPlain;
Johnny Chene9a56272012-08-09 23:09:42 +0000500
Kate Stoneb9c1b512016-09-06 20:57:50 +0000501 // There is only one variant this argument could be; put it into the
502 // argument entry.
503 arg.push_back(wp_id_arg);
Johnny Chene9a56272012-08-09 23:09:42 +0000504
Kate Stoneb9c1b512016-09-06 20:57:50 +0000505 // Push the data for the first argument into the m_arguments vector.
506 m_arguments.push_back(arg);
507 }
Johnny Chene9a56272012-08-09 23:09:42 +0000508
Kate Stoneb9c1b512016-09-06 20:57:50 +0000509 ~CommandObjectWatchpointCommandDelete() override = default;
Johnny Chene9a56272012-08-09 23:09:42 +0000510
511protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000512 bool DoExecute(Args &command, CommandReturnObject &result) override {
513 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
Johnny Chene9a56272012-08-09 23:09:42 +0000514
Kate Stoneb9c1b512016-09-06 20:57:50 +0000515 if (target == nullptr) {
516 result.AppendError("There is not a current executable; there are no "
517 "watchpoints from which to delete commands");
518 result.SetStatus(eReturnStatusFailed);
519 return false;
Johnny Chene9a56272012-08-09 23:09:42 +0000520 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000521
522 const WatchpointList &watchpoints = target->GetWatchpointList();
523 size_t num_watchpoints = watchpoints.GetSize();
524
525 if (num_watchpoints == 0) {
526 result.AppendError("No watchpoints exist to have commands deleted");
527 result.SetStatus(eReturnStatusFailed);
528 return false;
529 }
530
531 if (command.GetArgumentCount() == 0) {
532 result.AppendError(
533 "No watchpoint specified from which to delete the commands");
534 result.SetStatus(eReturnStatusFailed);
535 return false;
536 }
537
538 std::vector<uint32_t> valid_wp_ids;
539 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
540 valid_wp_ids)) {
541 result.AppendError("Invalid watchpoints specification.");
542 result.SetStatus(eReturnStatusFailed);
543 return false;
544 }
545
546 result.SetStatus(eReturnStatusSuccessFinishNoResult);
547 const size_t count = valid_wp_ids.size();
548 for (size_t i = 0; i < count; ++i) {
549 uint32_t cur_wp_id = valid_wp_ids.at(i);
550 if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
551 Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
552 if (wp)
553 wp->ClearCallback();
554 } else {
555 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
556 result.SetStatus(eReturnStatusFailed);
557 return false;
558 }
559 }
560 return result.Succeeded();
561 }
Johnny Chene9a56272012-08-09 23:09:42 +0000562};
563
564//-------------------------------------------------------------------------
565// CommandObjectWatchpointCommandList
566//-------------------------------------------------------------------------
567
Kate Stoneb9c1b512016-09-06 20:57:50 +0000568class CommandObjectWatchpointCommandList : public CommandObjectParsed {
Johnny Chene9a56272012-08-09 23:09:42 +0000569public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000570 CommandObjectWatchpointCommandList(CommandInterpreter &interpreter)
571 : CommandObjectParsed(interpreter, "list", "List the script or set of "
572 "commands to be executed when "
573 "the watchpoint is hit.",
574 nullptr) {
575 CommandArgumentEntry arg;
576 CommandArgumentData wp_id_arg;
Johnny Chene9a56272012-08-09 23:09:42 +0000577
Kate Stoneb9c1b512016-09-06 20:57:50 +0000578 // Define the first (and only) variant of this arg.
579 wp_id_arg.arg_type = eArgTypeWatchpointID;
580 wp_id_arg.arg_repetition = eArgRepeatPlain;
Johnny Chene9a56272012-08-09 23:09:42 +0000581
Kate Stoneb9c1b512016-09-06 20:57:50 +0000582 // There is only one variant this argument could be; put it into the
583 // argument entry.
584 arg.push_back(wp_id_arg);
Johnny Chene9a56272012-08-09 23:09:42 +0000585
Kate Stoneb9c1b512016-09-06 20:57:50 +0000586 // Push the data for the first argument into the m_arguments vector.
587 m_arguments.push_back(arg);
588 }
Johnny Chene9a56272012-08-09 23:09:42 +0000589
Kate Stoneb9c1b512016-09-06 20:57:50 +0000590 ~CommandObjectWatchpointCommandList() override = default;
Johnny Chene9a56272012-08-09 23:09:42 +0000591
592protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000593 bool DoExecute(Args &command, CommandReturnObject &result) override {
594 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
Johnny Chene9a56272012-08-09 23:09:42 +0000595
Kate Stoneb9c1b512016-09-06 20:57:50 +0000596 if (target == nullptr) {
597 result.AppendError("There is not a current executable; there are no "
598 "watchpoints for which to list commands");
599 result.SetStatus(eReturnStatusFailed);
600 return false;
Johnny Chene9a56272012-08-09 23:09:42 +0000601 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000602
603 const WatchpointList &watchpoints = target->GetWatchpointList();
604 size_t num_watchpoints = watchpoints.GetSize();
605
606 if (num_watchpoints == 0) {
607 result.AppendError("No watchpoints exist for which to list commands");
608 result.SetStatus(eReturnStatusFailed);
609 return false;
610 }
611
612 if (command.GetArgumentCount() == 0) {
613 result.AppendError(
614 "No watchpoint specified for which to list the commands");
615 result.SetStatus(eReturnStatusFailed);
616 return false;
617 }
618
619 std::vector<uint32_t> valid_wp_ids;
620 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command,
621 valid_wp_ids)) {
622 result.AppendError("Invalid watchpoints specification.");
623 result.SetStatus(eReturnStatusFailed);
624 return false;
625 }
626
627 result.SetStatus(eReturnStatusSuccessFinishNoResult);
628 const size_t count = valid_wp_ids.size();
629 for (size_t i = 0; i < count; ++i) {
630 uint32_t cur_wp_id = valid_wp_ids.at(i);
631 if (cur_wp_id != LLDB_INVALID_WATCH_ID) {
632 Watchpoint *wp = target->GetWatchpointList().FindByID(cur_wp_id).get();
633
634 if (wp) {
635 const WatchpointOptions *wp_options = wp->GetOptions();
636 if (wp_options) {
637 // Get the callback baton associated with the current watchpoint.
638 const Baton *baton = wp_options->GetBaton();
639 if (baton) {
640 result.GetOutputStream().Printf("Watchpoint %u:\n", cur_wp_id);
641 result.GetOutputStream().IndentMore();
642 baton->GetDescription(&result.GetOutputStream(),
643 eDescriptionLevelFull);
644 result.GetOutputStream().IndentLess();
645 } else {
646 result.AppendMessageWithFormat(
647 "Watchpoint %u does not have an associated command.\n",
648 cur_wp_id);
649 }
650 }
651 result.SetStatus(eReturnStatusSuccessFinishResult);
652 } else {
653 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
654 cur_wp_id);
655 result.SetStatus(eReturnStatusFailed);
656 }
657 }
658 }
659
660 return result.Succeeded();
661 }
Johnny Chene9a56272012-08-09 23:09:42 +0000662};
663
664//-------------------------------------------------------------------------
665// CommandObjectWatchpointCommand
666//-------------------------------------------------------------------------
667
Kate Stoneb9c1b512016-09-06 20:57:50 +0000668CommandObjectWatchpointCommand::CommandObjectWatchpointCommand(
669 CommandInterpreter &interpreter)
670 : CommandObjectMultiword(
671 interpreter, "command",
672 "Commands for adding, removing and examining LLDB commands "
673 "executed when the watchpoint is hit (watchpoint 'commmands').",
674 "command <sub-command> [<sub-command-options>] <watchpoint-id>") {
675 CommandObjectSP add_command_object(
676 new CommandObjectWatchpointCommandAdd(interpreter));
677 CommandObjectSP delete_command_object(
678 new CommandObjectWatchpointCommandDelete(interpreter));
679 CommandObjectSP list_command_object(
680 new CommandObjectWatchpointCommandList(interpreter));
Johnny Chene9a56272012-08-09 23:09:42 +0000681
Kate Stoneb9c1b512016-09-06 20:57:50 +0000682 add_command_object->SetCommandName("watchpoint command add");
683 delete_command_object->SetCommandName("watchpoint command delete");
684 list_command_object->SetCommandName("watchpoint command list");
Johnny Chene9a56272012-08-09 23:09:42 +0000685
Kate Stoneb9c1b512016-09-06 20:57:50 +0000686 LoadSubCommand("add", add_command_object);
687 LoadSubCommand("delete", delete_command_object);
688 LoadSubCommand("list", list_command_object);
Johnny Chene9a56272012-08-09 23:09:42 +0000689}
690
Eugene Zelenko49bcfd82016-02-23 01:43:44 +0000691CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand() = default;