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