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