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