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