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
CommandObjectBreakpointCommandAdd(CommandInterpreter & interpreter)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
~CommandObjectBreakpointCommandAdd()202 ~CommandObjectBreakpointCommandAdd () {}
203
204 virtual Options *
GetOptions()205 GetOptions ()
206 {
207 return &m_options;
208 }
209
210 void
CollectDataForBreakpointCommandCallback(BreakpointOptions * bp_options,CommandReturnObject & result)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
SetBreakpointCommandCallback(BreakpointOptions * bp_options,const char * oneliner)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
GenerateBreakpointCommandCallback(void * baton,InputReader & reader,lldb::InputReaderAction notification,const char * bytes,size_t bytes_len)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
BreakpointOptionsCallbackFunction(void * baton,StoppointCallbackContext * context,lldb::user_id_t break_id,lldb::user_id_t break_loc_id)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
CommandOptions(CommandInterpreter & interpreter)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
~CommandOptions()418 ~CommandOptions () {}
419
420 virtual Error
SetOptionValue(uint32_t option_idx,const char * option_arg)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
OptionParsingStarting()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*
GetDefinitions()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
DoExecute(Args & command,CommandReturnObject & result)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:
CommandObjectBreakpointCommandDelete(CommandInterpreter & interpreter)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
~CommandObjectBreakpointCommandDelete()687 ~CommandObjectBreakpointCommandDelete () {}
688
689 protected:
690 virtual bool
DoExecute(Args & command,CommandReturnObject & result)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:
CommandObjectBreakpointCommandList(CommandInterpreter & interpreter)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
~CommandObjectBreakpointCommandList()784 ~CommandObjectBreakpointCommandList () {}
785
786 protected:
787 virtual bool
DoExecute(Args & command,CommandReturnObject & result)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
CommandObjectBreakpointCommand(CommandInterpreter & interpreter)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
~CommandObjectBreakpointCommand()911 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
912 {
913 }
914
915
916