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