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