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