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 eInputReaderGotToken:
470         if (bytes && bytes_len && baton)
471         {
472             BreakpointOptions *bp_options = (BreakpointOptions *) baton;
473             if (bp_options)
474             {
475                 Baton *bp_options_baton = bp_options->GetBaton();
476                 if (bp_options_baton)
477                     ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
478             }
479         }
480         if (!reader.IsDone() && reader.GetPrompt())
481         {
482             out_file.Printf ("%s", reader.GetPrompt());
483             out_file.Flush();
484         }
485         break;
486 
487     case eInputReaderInterrupt:
488         {
489             // Finish, and cancel the breakpoint command.
490             reader.SetIsDone (true);
491             BreakpointOptions *bp_options = (BreakpointOptions *) baton;
492             if (bp_options)
493             {
494                 Baton *bp_options_baton = bp_options->GetBaton ();
495                 if (bp_options_baton)
496                 {
497                     ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear();
498                     ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.Clear();
499                 }
500             }
501             out_file.Printf ("Warning: No command attached to breakpoint.\n");
502             out_file.Flush();
503         }
504         break;
505 
506     case eInputReaderEndOfFile:
507         reader.SetIsDone (true);
508         break;
509 
510     case eInputReaderDone:
511         break;
512     }
513 
514     return bytes_len;
515 }
516 
517 
518 //-------------------------------------------------------------------------
519 // CommandObjectBreakpointCommandRemove
520 //-------------------------------------------------------------------------
521 
522 CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove (CommandInterpreter &interpreter) :
523     CommandObject (interpreter,
524                    "remove",
525                    "Remove the set of commands from a breakpoint.",
526                    NULL)
527 {
528     CommandArgumentEntry arg;
529     CommandArgumentData bp_id_arg;
530 
531     // Define the first (and only) variant of this arg.
532     bp_id_arg.arg_type = eArgTypeBreakpointID;
533     bp_id_arg.arg_repetition = eArgRepeatPlain;
534 
535     // There is only one variant this argument could be; put it into the argument entry.
536     arg.push_back (bp_id_arg);
537 
538     // Push the data for the first argument into the m_arguments vector.
539     m_arguments.push_back (arg);
540 }
541 
542 CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove ()
543 {
544 }
545 
546 bool
547 CommandObjectBreakpointCommandRemove::Execute
548 (
549     Args& command,
550     CommandReturnObject &result
551 )
552 {
553     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
554 
555     if (target == NULL)
556     {
557         result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands");
558         result.SetStatus (eReturnStatusFailed);
559         return false;
560     }
561 
562     const BreakpointList &breakpoints = target->GetBreakpointList();
563     size_t num_breakpoints = breakpoints.GetSize();
564 
565     if (num_breakpoints == 0)
566     {
567         result.AppendError ("No breakpoints exist to have commands removed");
568         result.SetStatus (eReturnStatusFailed);
569         return false;
570     }
571 
572     if (command.GetArgumentCount() == 0)
573     {
574         result.AppendError ("No breakpoint specified from which to remove the commands");
575         result.SetStatus (eReturnStatusFailed);
576         return false;
577     }
578 
579     BreakpointIDList valid_bp_ids;
580     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
581 
582     if (result.Succeeded())
583     {
584         const size_t count = valid_bp_ids.GetSize();
585         for (size_t i = 0; i < count; ++i)
586         {
587             BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
588             if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
589             {
590                 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
591                 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
592                 {
593                     BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
594                     if (bp_loc_sp)
595                         bp_loc_sp->ClearCallback();
596                     else
597                     {
598                         result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
599                                                      cur_bp_id.GetBreakpointID(),
600                                                      cur_bp_id.GetLocationID());
601                         result.SetStatus (eReturnStatusFailed);
602                         return false;
603                     }
604                 }
605                 else
606                 {
607                     bp->ClearCallback();
608                 }
609             }
610         }
611     }
612     return result.Succeeded();
613 }
614 
615 
616 //-------------------------------------------------------------------------
617 // CommandObjectBreakpointCommandList
618 //-------------------------------------------------------------------------
619 
620 CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) :
621     CommandObject (interpreter,
622                    "list",
623                    "List the script or set of commands to be executed when the breakpoint is hit.",
624                     NULL)
625 {
626     CommandArgumentEntry arg;
627     CommandArgumentData bp_id_arg;
628 
629     // Define the first (and only) variant of this arg.
630     bp_id_arg.arg_type = eArgTypeBreakpointID;
631     bp_id_arg.arg_repetition = eArgRepeatPlain;
632 
633     // There is only one variant this argument could be; put it into the argument entry.
634     arg.push_back (bp_id_arg);
635 
636     // Push the data for the first argument into the m_arguments vector.
637     m_arguments.push_back (arg);
638 }
639 
640 CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList ()
641 {
642 }
643 
644 bool
645 CommandObjectBreakpointCommandList::Execute
646 (
647     Args& command,
648     CommandReturnObject &result
649 )
650 {
651     Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
652 
653     if (target == NULL)
654     {
655         result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
656         result.SetStatus (eReturnStatusFailed);
657         return false;
658     }
659 
660     const BreakpointList &breakpoints = target->GetBreakpointList();
661     size_t num_breakpoints = breakpoints.GetSize();
662 
663     if (num_breakpoints == 0)
664     {
665         result.AppendError ("No breakpoints exist for which to list commands");
666         result.SetStatus (eReturnStatusFailed);
667         return false;
668     }
669 
670     if (command.GetArgumentCount() == 0)
671     {
672         result.AppendError ("No breakpoint specified for which to list the commands");
673         result.SetStatus (eReturnStatusFailed);
674         return false;
675     }
676 
677     BreakpointIDList valid_bp_ids;
678     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
679 
680     if (result.Succeeded())
681     {
682         const size_t count = valid_bp_ids.GetSize();
683         for (size_t i = 0; i < count; ++i)
684         {
685             BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
686             if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
687             {
688                 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
689 
690                 if (bp)
691                 {
692                     const BreakpointOptions *bp_options = NULL;
693                     if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
694                     {
695                         BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
696                         if (bp_loc_sp)
697                             bp_options = bp_loc_sp->GetOptionsNoCreate();
698                         else
699                         {
700                             result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
701                                                          cur_bp_id.GetBreakpointID(),
702                                                          cur_bp_id.GetLocationID());
703                             result.SetStatus (eReturnStatusFailed);
704                             return false;
705                         }
706                     }
707                     else
708                     {
709                         bp_options = bp->GetOptions();
710                     }
711 
712                     if (bp_options)
713                     {
714                         StreamString id_str;
715                         BreakpointID::GetCanonicalReference (&id_str,
716                                                              cur_bp_id.GetBreakpointID(),
717                                                              cur_bp_id.GetLocationID());
718                         const Baton *baton = bp_options->GetBaton();
719                         if (baton)
720                         {
721                             result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
722                             result.GetOutputStream().IndentMore ();
723                             baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
724                             result.GetOutputStream().IndentLess ();
725                         }
726                         else
727                         {
728                             result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n",
729                                                             id_str.GetData());
730                         }
731                     }
732                     result.SetStatus (eReturnStatusSuccessFinishResult);
733                 }
734                 else
735                 {
736                     result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
737                     result.SetStatus (eReturnStatusFailed);
738                 }
739 
740             }
741         }
742     }
743 
744     return result.Succeeded();
745 }
746 
747 //-------------------------------------------------------------------------
748 // CommandObjectBreakpointCommand
749 //-------------------------------------------------------------------------
750 
751 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
752     CommandObjectMultiword (interpreter,
753                             "command",
754                             "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
755                             "command <sub-command> [<sub-command-options>] <breakpoint-id>")
756 {
757     bool status;
758     CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
759     CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove (interpreter));
760     CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter));
761 
762     add_command_object->SetCommandName ("breakpoint command add");
763     remove_command_object->SetCommandName ("breakpoint command remove");
764     list_command_object->SetCommandName ("breakpoint command list");
765 
766     status = LoadSubCommand ("add",    add_command_object);
767     status = LoadSubCommand ("remove", remove_command_object);
768     status = LoadSubCommand ("list",   list_command_object);
769 }
770 
771 
772 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
773 {
774 }
775 
776 bool
777 CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction
778 (
779     void *baton,
780     StoppointCallbackContext *context,
781     lldb::user_id_t break_id,
782     lldb::user_id_t break_loc_id
783 )
784 {
785     bool ret_value = true;
786     if (baton == NULL)
787         return true;
788 
789 
790     BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
791     StringList &commands = data->user_source;
792 
793     if (commands.GetSize() > 0)
794     {
795         if (context->exe_ctx.target)
796         {
797             CommandReturnObject result;
798             Debugger &debugger = context->exe_ctx.target->GetDebugger();
799             // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
800             // if the debugger is set up that way.
801 
802             result.SetImmediateOutputFile (debugger.GetOutputFile().GetStream());
803             result.SetImmediateErrorFile (debugger.GetErrorFile().GetStream());
804 
805             bool stop_on_continue = true;
806             bool echo_commands    = false;
807             bool print_results    = true;
808 
809             debugger.GetCommandInterpreter().HandleCommands (commands,
810                                                              &(context->exe_ctx),
811                                                              stop_on_continue,
812                                                              data->stop_on_error,
813                                                              echo_commands,
814                                                              print_results,
815                                                              result);
816         }
817     }
818     return ret_value;
819 }
820 
821