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