1 //===-- 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 #include "lldb/lldb-python.h"
11
12 // C Includes
13 // C++ Includes
14
15
16 #include "CommandObjectWatchpointCommand.h"
17 #include "CommandObjectWatchpoint.h"
18
19 #include "lldb/Interpreter/CommandInterpreter.h"
20 #include "lldb/Interpreter/CommandReturnObject.h"
21 #include "lldb/Target/Target.h"
22 #include "lldb/Target/Thread.h"
23 #include "lldb/Breakpoint/Watchpoint.h"
24 #include "lldb/Breakpoint/StoppointCallbackContext.h"
25 #include "lldb/Core/State.h"
26
27 #include <vector>
28
29 using namespace lldb;
30 using namespace lldb_private;
31
32 //-------------------------------------------------------------------------
33 // CommandObjectWatchpointCommandAdd
34 //-------------------------------------------------------------------------
35
36
37 class CommandObjectWatchpointCommandAdd : public CommandObjectParsed
38 {
39 public:
40
CommandObjectWatchpointCommandAdd(CommandInterpreter & interpreter)41 CommandObjectWatchpointCommandAdd (CommandInterpreter &interpreter) :
42 CommandObjectParsed (interpreter,
43 "add",
44 "Add a set of commands to a watchpoint, to be executed whenever the watchpoint is hit.",
45 NULL),
46 m_options (interpreter)
47 {
48 SetHelpLong (
49 "\nGeneral information about entering watchpoint commands \n\
50 ------------------------------------------------------ \n\
51 \n\
52 This command will cause you to be prompted to enter the command or set \n\
53 of commands you wish to be executed when the specified watchpoint is \n\
54 hit. You will be told to enter your command(s), and will see a '> ' \n\
55 prompt. Because you can enter one or many commands to be executed when \n\
56 a watchpoint is hit, you will continue to be prompted after each \n\
57 new-line that you enter, until you enter the word 'DONE', which will \n\
58 cause the commands you have entered to be stored with the watchpoint \n\
59 and executed when the watchpoint is hit. \n\
60 \n\
61 Syntax checking is not necessarily done when watchpoint commands are \n\
62 entered. An improperly written watchpoint command will attempt to get \n\
63 executed when the watchpoint gets hit, and usually silently fail. If \n\
64 your watchpoint command does not appear to be getting executed, go \n\
65 back and check your syntax. \n\
66 \n\
67 \n\
68 Special information about PYTHON watchpoint commands \n\
69 ---------------------------------------------------- \n\
70 \n\
71 You may enter either one line of Python or multiple lines of Python \n\
72 (including defining whole functions, if desired). If you enter a \n\
73 single line of Python, that will be passed to the Python interpreter \n\
74 'as is' when the watchpoint gets hit. If you enter function \n\
75 definitions, they will be passed to the Python interpreter as soon as \n\
76 you finish entering the watchpoint command, and they can be called \n\
77 later (don't forget to add calls to them, if you want them called when \n\
78 the watchpoint is hit). If you enter multiple lines of Python that \n\
79 are not function definitions, they will be collected into a new, \n\
80 automatically generated Python function, and a call to the newly \n\
81 generated function will be attached to the watchpoint. \n\
82 \n\
83 This auto-generated function is passed in two arguments: \n\
84 \n\
85 frame: an SBFrame object representing the frame which hit the watchpoint. \n\
86 From the frame you can get back to the thread and process. \n\
87 wp: the watchpoint that was hit. \n\
88 \n\
89 Important Note: Because loose Python code gets collected into functions, \n\
90 if you want to access global variables in the 'loose' code, you need to \n\
91 specify that they are global, using the 'global' keyword. Be sure to \n\
92 use correct Python syntax, including indentation, when entering Python \n\
93 watchpoint commands. \n\
94 \n\
95 As a third option, you can pass the name of an already existing Python function \n\
96 and that function will be attached to the watchpoint. It will get passed the \n\
97 frame and wp_loc arguments mentioned above. \n\
98 \n\
99 Example Python one-line watchpoint command: \n\
100 \n\
101 (lldb) watchpoint command add -s python 1 \n\
102 Enter your Python command(s). Type 'DONE' to end. \n\
103 > print \"Hit this watchpoint!\" \n\
104 > DONE \n\
105 \n\
106 As a convenience, this also works for a short Python one-liner: \n\
107 (lldb) watchpoint command add -s python 1 -o \"import time; print time.asctime()\" \n\
108 (lldb) run \n\
109 Launching '.../a.out' (x86_64) \n\
110 (lldb) Fri Sep 10 12:17:45 2010 \n\
111 Process 21778 Stopped \n\
112 * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread \n\
113 36 \n\
114 37 int c(int val)\n\
115 38 {\n\
116 39 -> return val + 3;\n\
117 40 }\n\
118 41 \n\
119 42 int main (int argc, char const *argv[])\n\
120 (lldb) \n\
121 \n\
122 Example multiple line Python watchpoint command, using function definition: \n\
123 \n\
124 (lldb) watchpoint command add -s python 1 \n\
125 Enter your Python command(s). Type 'DONE' to end. \n\
126 > def watchpoint_output (wp_no): \n\
127 > out_string = \"Hit watchpoint number \" + repr (wp_no) \n\
128 > print out_string \n\
129 > return True \n\
130 > watchpoint_output (1) \n\
131 > DONE \n\
132 \n\
133 \n\
134 Example multiple line Python watchpoint command, using 'loose' Python: \n\
135 \n\
136 (lldb) watchpoint command add -s p 1 \n\
137 Enter your Python command(s). Type 'DONE' to end. \n\
138 > global wp_count \n\
139 > wp_count = wp_count + 1 \n\
140 > print \"Hit this watchpoint \" + repr(wp_count) + \" times!\" \n\
141 > DONE \n\
142 \n\
143 In this case, since there is a reference to a global variable, \n\
144 'wp_count', you will also need to make sure 'wp_count' exists and is \n\
145 initialized: \n\
146 \n\
147 (lldb) script \n\
148 >>> wp_count = 0 \n\
149 >>> quit() \n\
150 \n\
151 (lldb) \n\
152 \n\
153 \n\
154 Final Note: If you get a warning that no watchpoint command was generated, \n\
155 but you did not get any syntax errors, you probably forgot to add a call \n\
156 to your functions. \n\
157 \n\
158 Special information about debugger command watchpoint commands \n\
159 -------------------------------------------------------------- \n\
160 \n\
161 You may enter any debugger command, exactly as you would at the \n\
162 debugger prompt. You may enter as many debugger commands as you like, \n\
163 but do NOT enter more than one command per line. \n" );
164
165 CommandArgumentEntry arg;
166 CommandArgumentData wp_id_arg;
167
168 // Define the first (and only) variant of this arg.
169 wp_id_arg.arg_type = eArgTypeWatchpointID;
170 wp_id_arg.arg_repetition = eArgRepeatPlain;
171
172 // There is only one variant this argument could be; put it into the argument entry.
173 arg.push_back (wp_id_arg);
174
175 // Push the data for the first argument into the m_arguments vector.
176 m_arguments.push_back (arg);
177 }
178
179 virtual
~CommandObjectWatchpointCommandAdd()180 ~CommandObjectWatchpointCommandAdd () {}
181
182 virtual Options *
GetOptions()183 GetOptions ()
184 {
185 return &m_options;
186 }
187
188 void
CollectDataForWatchpointCommandCallback(WatchpointOptions * wp_options,CommandReturnObject & result)189 CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
190 CommandReturnObject &result)
191 {
192 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
193 std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
194 if (reader_sp && data_ap.get())
195 {
196 BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
197 wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
198
199 Error err (reader_sp->Initialize (CommandObjectWatchpointCommandAdd::GenerateWatchpointCommandCallback,
200 wp_options, // callback_data
201 eInputReaderGranularityLine, // token size, to pass to callback function
202 "DONE", // end token
203 "> ", // prompt
204 true)); // echo input
205 if (err.Success())
206 {
207 m_interpreter.GetDebugger().PushInputReader (reader_sp);
208 result.SetStatus (eReturnStatusSuccessFinishNoResult);
209 }
210 else
211 {
212 result.AppendError (err.AsCString());
213 result.SetStatus (eReturnStatusFailed);
214 }
215 }
216 else
217 {
218 result.AppendError("out of memory");
219 result.SetStatus (eReturnStatusFailed);
220 }
221
222 }
223
224 /// Set a one-liner as the callback for the watchpoint.
225 void
SetWatchpointCommandCallback(WatchpointOptions * wp_options,const char * oneliner)226 SetWatchpointCommandCallback (WatchpointOptions *wp_options,
227 const char *oneliner)
228 {
229 std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
230
231 // It's necessary to set both user_source and script_source to the oneliner.
232 // The former is used to generate callback description (as in watchpoint command list)
233 // while the latter is used for Python to interpret during the actual callback.
234 data_ap->user_source.AppendString (oneliner);
235 data_ap->script_source.assign (oneliner);
236 data_ap->stop_on_error = m_options.m_stop_on_error;
237
238 BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
239 wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
240
241 return;
242 }
243
244 static size_t
GenerateWatchpointCommandCallback(void * callback_data,InputReader & reader,lldb::InputReaderAction notification,const char * bytes,size_t bytes_len)245 GenerateWatchpointCommandCallback (void *callback_data,
246 InputReader &reader,
247 lldb::InputReaderAction notification,
248 const char *bytes,
249 size_t bytes_len)
250 {
251 StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
252 bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
253
254 switch (notification)
255 {
256 case eInputReaderActivate:
257 if (!batch_mode)
258 {
259 out_stream->Printf ("%s\n", g_reader_instructions);
260 if (reader.GetPrompt())
261 out_stream->Printf ("%s", reader.GetPrompt());
262 out_stream->Flush();
263 }
264 break;
265
266 case eInputReaderDeactivate:
267 break;
268
269 case eInputReaderReactivate:
270 if (reader.GetPrompt() && !batch_mode)
271 {
272 out_stream->Printf ("%s", reader.GetPrompt());
273 out_stream->Flush();
274 }
275 break;
276
277 case eInputReaderAsynchronousOutputWritten:
278 break;
279
280 case eInputReaderGotToken:
281 if (bytes && bytes_len && callback_data)
282 {
283 WatchpointOptions *wp_options = (WatchpointOptions *) callback_data;
284 if (wp_options)
285 {
286 Baton *wp_options_baton = wp_options->GetBaton();
287 if (wp_options_baton)
288 ((WatchpointOptions::CommandData *)wp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
289 }
290 }
291 if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
292 {
293 out_stream->Printf ("%s", reader.GetPrompt());
294 out_stream->Flush();
295 }
296 break;
297
298 case eInputReaderInterrupt:
299 {
300 // Finish, and cancel the watchpoint command.
301 reader.SetIsDone (true);
302 WatchpointOptions *wp_options = (WatchpointOptions *) callback_data;
303 if (wp_options)
304 {
305 Baton *wp_options_baton = wp_options->GetBaton ();
306 if (wp_options_baton)
307 {
308 ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->user_source.Clear();
309 ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->script_source.clear();
310 }
311 }
312 if (!batch_mode)
313 {
314 out_stream->Printf ("Warning: No command attached to watchpoint.\n");
315 out_stream->Flush();
316 }
317 }
318 break;
319
320 case eInputReaderEndOfFile:
321 reader.SetIsDone (true);
322 break;
323
324 case eInputReaderDone:
325 break;
326 }
327
328 return bytes_len;
329 }
330
331 static bool
WatchpointOptionsCallbackFunction(void * baton,StoppointCallbackContext * context,lldb::user_id_t watch_id)332 WatchpointOptionsCallbackFunction (void *baton,
333 StoppointCallbackContext *context,
334 lldb::user_id_t watch_id)
335 {
336 bool ret_value = true;
337 if (baton == NULL)
338 return true;
339
340
341 WatchpointOptions::CommandData *data = (WatchpointOptions::CommandData *) baton;
342 StringList &commands = data->user_source;
343
344 if (commands.GetSize() > 0)
345 {
346 ExecutionContext exe_ctx (context->exe_ctx_ref);
347 Target *target = exe_ctx.GetTargetPtr();
348 if (target)
349 {
350 CommandReturnObject result;
351 Debugger &debugger = target->GetDebugger();
352 // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
353 // if the debugger is set up that way.
354
355 StreamSP output_stream (debugger.GetAsyncOutputStream());
356 StreamSP error_stream (debugger.GetAsyncErrorStream());
357 result.SetImmediateOutputStream (output_stream);
358 result.SetImmediateErrorStream (error_stream);
359
360 bool stop_on_continue = true;
361 bool echo_commands = false;
362 bool print_results = true;
363
364 debugger.GetCommandInterpreter().HandleCommands (commands,
365 &exe_ctx,
366 stop_on_continue,
367 data->stop_on_error,
368 echo_commands,
369 print_results,
370 eLazyBoolNo,
371 result);
372 result.GetImmediateOutputStream()->Flush();
373 result.GetImmediateErrorStream()->Flush();
374 }
375 }
376 return ret_value;
377 }
378
379 class CommandOptions : public Options
380 {
381 public:
382
CommandOptions(CommandInterpreter & interpreter)383 CommandOptions (CommandInterpreter &interpreter) :
384 Options (interpreter),
385 m_use_commands (false),
386 m_use_script_language (false),
387 m_script_language (eScriptLanguageNone),
388 m_use_one_liner (false),
389 m_one_liner(),
390 m_function_name()
391 {
392 }
393
394 virtual
~CommandOptions()395 ~CommandOptions () {}
396
397 virtual Error
SetOptionValue(uint32_t option_idx,const char * option_arg)398 SetOptionValue (uint32_t option_idx, const char *option_arg)
399 {
400 Error error;
401 const int short_option = m_getopt_table[option_idx].val;
402
403 switch (short_option)
404 {
405 case 'o':
406 m_use_one_liner = true;
407 m_one_liner = option_arg;
408 break;
409
410 case 's':
411 m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
412 g_option_table[option_idx].enum_values,
413 eScriptLanguageNone,
414 error);
415
416 if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
417 {
418 m_use_script_language = true;
419 }
420 else
421 {
422 m_use_script_language = false;
423 }
424 break;
425
426 case 'e':
427 {
428 bool success = false;
429 m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
430 if (!success)
431 error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
432 }
433 break;
434
435 case 'F':
436 {
437 m_use_one_liner = false;
438 m_use_script_language = true;
439 m_function_name.assign(option_arg);
440 }
441 break;
442
443 default:
444 break;
445 }
446 return error;
447 }
448 void
OptionParsingStarting()449 OptionParsingStarting ()
450 {
451 m_use_commands = true;
452 m_use_script_language = false;
453 m_script_language = eScriptLanguageNone;
454
455 m_use_one_liner = false;
456 m_stop_on_error = true;
457 m_one_liner.clear();
458 m_function_name.clear();
459 }
460
461 const OptionDefinition*
GetDefinitions()462 GetDefinitions ()
463 {
464 return g_option_table;
465 }
466
467 // Options table: Required for subclasses of Options.
468
469 static OptionDefinition g_option_table[];
470
471 // Instance variables to hold the values for command options.
472
473 bool m_use_commands;
474 bool m_use_script_language;
475 lldb::ScriptLanguage m_script_language;
476
477 // Instance variables to hold the values for one_liner options.
478 bool m_use_one_liner;
479 std::string m_one_liner;
480 bool m_stop_on_error;
481 std::string m_function_name;
482 };
483
484 protected:
485 virtual bool
DoExecute(Args & command,CommandReturnObject & result)486 DoExecute (Args& command, CommandReturnObject &result)
487 {
488 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
489
490 if (target == NULL)
491 {
492 result.AppendError ("There is not a current executable; there are no watchpoints to which to add commands");
493 result.SetStatus (eReturnStatusFailed);
494 return false;
495 }
496
497 const WatchpointList &watchpoints = target->GetWatchpointList();
498 size_t num_watchpoints = watchpoints.GetSize();
499
500 if (num_watchpoints == 0)
501 {
502 result.AppendError ("No watchpoints exist to have commands added");
503 result.SetStatus (eReturnStatusFailed);
504 return false;
505 }
506
507 if (m_options.m_use_script_language == false && m_options.m_function_name.size())
508 {
509 result.AppendError ("need to enable scripting to have a function run as a watchpoint command");
510 result.SetStatus (eReturnStatusFailed);
511 return false;
512 }
513
514 std::vector<uint32_t> valid_wp_ids;
515 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
516 {
517 result.AppendError("Invalid watchpoints specification.");
518 result.SetStatus(eReturnStatusFailed);
519 return false;
520 }
521
522 result.SetStatus(eReturnStatusSuccessFinishNoResult);
523 const size_t count = valid_wp_ids.size();
524 for (size_t i = 0; i < count; ++i)
525 {
526 uint32_t cur_wp_id = valid_wp_ids.at (i);
527 if (cur_wp_id != LLDB_INVALID_WATCH_ID)
528 {
529 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
530 // Sanity check wp first.
531 if (wp == NULL) continue;
532
533 WatchpointOptions *wp_options = wp->GetOptions();
534 // Skip this watchpoint if wp_options is not good.
535 if (wp_options == NULL) continue;
536
537 // If we are using script language, get the script interpreter
538 // in order to set or collect command callback. Otherwise, call
539 // the methods associated with this object.
540 if (m_options.m_use_script_language)
541 {
542 // Special handling for one-liner specified inline.
543 if (m_options.m_use_one_liner)
544 {
545 m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
546 m_options.m_one_liner.c_str());
547 }
548 // Special handling for using a Python function by name
549 // instead of extending the watchpoint callback data structures, we just automatize
550 // what the user would do manually: make their watchpoint command be a function call
551 else if (m_options.m_function_name.size())
552 {
553 std::string oneliner(m_options.m_function_name);
554 oneliner += "(frame, wp, internal_dict)";
555 m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
556 oneliner.c_str());
557 }
558 else
559 {
560 m_interpreter.GetScriptInterpreter()->CollectDataForWatchpointCommandCallback (wp_options,
561 result);
562 }
563 }
564 else
565 {
566 // Special handling for one-liner specified inline.
567 if (m_options.m_use_one_liner)
568 SetWatchpointCommandCallback (wp_options,
569 m_options.m_one_liner.c_str());
570 else
571 CollectDataForWatchpointCommandCallback (wp_options,
572 result);
573 }
574 }
575 }
576
577 return result.Succeeded();
578 }
579
580 private:
581 CommandOptions m_options;
582 static const char *g_reader_instructions;
583
584 };
585
586 const char *
587 CommandObjectWatchpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
588
589 // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
590 // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
591
592 static OptionEnumValueElement
593 g_script_option_enumeration[4] =
594 {
595 { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"},
596 { eScriptLanguagePython, "python", "Commands are in the Python language."},
597 { eSortOrderByName, "default-script", "Commands are in the default scripting language."},
598 { 0, NULL, NULL }
599 };
600
601 OptionDefinition
602 CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] =
603 {
604 { LLDB_OPT_SET_1, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeOneLiner,
605 "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." },
606
607 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean,
608 "Specify whether watchpoint command execution should terminate on error." },
609
610 { LLDB_OPT_SET_ALL, false, "script-type", 's', required_argument, g_script_option_enumeration, 0, eArgTypeNone,
611 "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
612
613 { LLDB_OPT_SET_2, false, "python-function", 'F', required_argument, NULL, 0, eArgTypePythonFunction,
614 "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."},
615
616 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
617 };
618
619 //-------------------------------------------------------------------------
620 // CommandObjectWatchpointCommandDelete
621 //-------------------------------------------------------------------------
622
623 class CommandObjectWatchpointCommandDelete : public CommandObjectParsed
624 {
625 public:
CommandObjectWatchpointCommandDelete(CommandInterpreter & interpreter)626 CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) :
627 CommandObjectParsed (interpreter,
628 "delete",
629 "Delete the set of commands from a watchpoint.",
630 NULL)
631 {
632 CommandArgumentEntry arg;
633 CommandArgumentData wp_id_arg;
634
635 // Define the first (and only) variant of this arg.
636 wp_id_arg.arg_type = eArgTypeWatchpointID;
637 wp_id_arg.arg_repetition = eArgRepeatPlain;
638
639 // There is only one variant this argument could be; put it into the argument entry.
640 arg.push_back (wp_id_arg);
641
642 // Push the data for the first argument into the m_arguments vector.
643 m_arguments.push_back (arg);
644 }
645
646
647 virtual
~CommandObjectWatchpointCommandDelete()648 ~CommandObjectWatchpointCommandDelete () {}
649
650 protected:
651 virtual bool
DoExecute(Args & command,CommandReturnObject & result)652 DoExecute (Args& command, CommandReturnObject &result)
653 {
654 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
655
656 if (target == NULL)
657 {
658 result.AppendError ("There is not a current executable; there are no watchpoints from which to delete commands");
659 result.SetStatus (eReturnStatusFailed);
660 return false;
661 }
662
663 const WatchpointList &watchpoints = target->GetWatchpointList();
664 size_t num_watchpoints = watchpoints.GetSize();
665
666 if (num_watchpoints == 0)
667 {
668 result.AppendError ("No watchpoints exist to have commands deleted");
669 result.SetStatus (eReturnStatusFailed);
670 return false;
671 }
672
673 if (command.GetArgumentCount() == 0)
674 {
675 result.AppendError ("No watchpoint specified from which to delete the commands");
676 result.SetStatus (eReturnStatusFailed);
677 return false;
678 }
679
680 std::vector<uint32_t> valid_wp_ids;
681 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
682 {
683 result.AppendError("Invalid watchpoints specification.");
684 result.SetStatus(eReturnStatusFailed);
685 return false;
686 }
687
688 result.SetStatus(eReturnStatusSuccessFinishNoResult);
689 const size_t count = valid_wp_ids.size();
690 for (size_t i = 0; i < count; ++i)
691 {
692 uint32_t cur_wp_id = valid_wp_ids.at (i);
693 if (cur_wp_id != LLDB_INVALID_WATCH_ID)
694 {
695 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
696 if (wp)
697 wp->ClearCallback();
698 }
699 else
700 {
701 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
702 cur_wp_id);
703 result.SetStatus (eReturnStatusFailed);
704 return false;
705 }
706 }
707 return result.Succeeded();
708 }
709 };
710
711 //-------------------------------------------------------------------------
712 // CommandObjectWatchpointCommandList
713 //-------------------------------------------------------------------------
714
715 class CommandObjectWatchpointCommandList : public CommandObjectParsed
716 {
717 public:
CommandObjectWatchpointCommandList(CommandInterpreter & interpreter)718 CommandObjectWatchpointCommandList (CommandInterpreter &interpreter) :
719 CommandObjectParsed (interpreter,
720 "list",
721 "List the script or set of commands to be executed when the watchpoint is hit.",
722 NULL)
723 {
724 CommandArgumentEntry arg;
725 CommandArgumentData wp_id_arg;
726
727 // Define the first (and only) variant of this arg.
728 wp_id_arg.arg_type = eArgTypeWatchpointID;
729 wp_id_arg.arg_repetition = eArgRepeatPlain;
730
731 // There is only one variant this argument could be; put it into the argument entry.
732 arg.push_back (wp_id_arg);
733
734 // Push the data for the first argument into the m_arguments vector.
735 m_arguments.push_back (arg);
736 }
737
738 virtual
~CommandObjectWatchpointCommandList()739 ~CommandObjectWatchpointCommandList () {}
740
741 protected:
742 virtual bool
DoExecute(Args & command,CommandReturnObject & result)743 DoExecute (Args& command,
744 CommandReturnObject &result)
745 {
746 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
747
748 if (target == NULL)
749 {
750 result.AppendError ("There is not a current executable; there are no watchpoints for which to list commands");
751 result.SetStatus (eReturnStatusFailed);
752 return false;
753 }
754
755 const WatchpointList &watchpoints = target->GetWatchpointList();
756 size_t num_watchpoints = watchpoints.GetSize();
757
758 if (num_watchpoints == 0)
759 {
760 result.AppendError ("No watchpoints exist for which to list commands");
761 result.SetStatus (eReturnStatusFailed);
762 return false;
763 }
764
765 if (command.GetArgumentCount() == 0)
766 {
767 result.AppendError ("No watchpoint specified for which to list the commands");
768 result.SetStatus (eReturnStatusFailed);
769 return false;
770 }
771
772 std::vector<uint32_t> valid_wp_ids;
773 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
774 {
775 result.AppendError("Invalid watchpoints specification.");
776 result.SetStatus(eReturnStatusFailed);
777 return false;
778 }
779
780 result.SetStatus(eReturnStatusSuccessFinishNoResult);
781 const size_t count = valid_wp_ids.size();
782 for (size_t i = 0; i < count; ++i)
783 {
784 uint32_t cur_wp_id = valid_wp_ids.at (i);
785 if (cur_wp_id != LLDB_INVALID_WATCH_ID)
786 {
787 Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
788
789 if (wp)
790 {
791 const WatchpointOptions *wp_options = wp->GetOptions();
792 if (wp_options)
793 {
794 // Get the callback baton associated with the current watchpoint.
795 const Baton *baton = wp_options->GetBaton();
796 if (baton)
797 {
798 result.GetOutputStream().Printf ("Watchpoint %u:\n", cur_wp_id);
799 result.GetOutputStream().IndentMore ();
800 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
801 result.GetOutputStream().IndentLess ();
802 }
803 else
804 {
805 result.AppendMessageWithFormat ("Watchpoint %u does not have an associated command.\n",
806 cur_wp_id);
807 }
808 }
809 result.SetStatus (eReturnStatusSuccessFinishResult);
810 }
811 else
812 {
813 result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
814 result.SetStatus (eReturnStatusFailed);
815 }
816 }
817 }
818
819 return result.Succeeded();
820 }
821 };
822
823 //-------------------------------------------------------------------------
824 // CommandObjectWatchpointCommand
825 //-------------------------------------------------------------------------
826
CommandObjectWatchpointCommand(CommandInterpreter & interpreter)827 CommandObjectWatchpointCommand::CommandObjectWatchpointCommand (CommandInterpreter &interpreter) :
828 CommandObjectMultiword (interpreter,
829 "command",
830 "A set of commands for adding, removing and examining bits of code to be executed when the watchpoint is hit (watchpoint 'commmands').",
831 "command <sub-command> [<sub-command-options>] <watchpoint-id>")
832 {
833 CommandObjectSP add_command_object (new CommandObjectWatchpointCommandAdd (interpreter));
834 CommandObjectSP delete_command_object (new CommandObjectWatchpointCommandDelete (interpreter));
835 CommandObjectSP list_command_object (new CommandObjectWatchpointCommandList (interpreter));
836
837 add_command_object->SetCommandName ("watchpoint command add");
838 delete_command_object->SetCommandName ("watchpoint command delete");
839 list_command_object->SetCommandName ("watchpoint command list");
840
841 LoadSubCommand ("add", add_command_object);
842 LoadSubCommand ("delete", delete_command_object);
843 LoadSubCommand ("list", list_command_object);
844 }
845
~CommandObjectWatchpointCommand()846 CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand ()
847 {
848 }
849
850
851