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