blob: 60c7d8fef5ed46310d2a6024f3b2db0714974c0e [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- 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
27using namespace lldb;
28using namespace lldb_private;
29
30//-------------------------------------------------------------------------
31// CommandObjectBreakpointCommandAdd::CommandOptions
32//-------------------------------------------------------------------------
33
34CommandObjectBreakpointCommandAdd::CommandOptions::CommandOptions () :
35 Options ()
36{
Chris Lattner24943d22010-06-08 16:52:24 +000037}
38
39CommandObjectBreakpointCommandAdd::CommandOptions::~CommandOptions ()
40{
41}
42
43lldb::OptionDefinition
44CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] =
45{
Jim Ingham34e9a982010-06-15 18:47:14 +000046 { LLDB_OPT_SET_1, true, "script", 's', no_argument, NULL, 0, NULL,
Chris Lattner24943d22010-06-08 16:52:24 +000047 "Write the breakpoint command script in the default scripting language."},
48
Jim Ingham34e9a982010-06-15 18:47:14 +000049 { LLDB_OPT_SET_2, true, "python", 'p', no_argument, NULL, 0, NULL,
Chris Lattner24943d22010-06-08 16:52:24 +000050 "Write the breakpoint command script in the Python scripting language."},
51
Jim Ingham34e9a982010-06-15 18:47:14 +000052 { LLDB_OPT_SET_3, true, "commands", 'c', no_argument, NULL, 0, NULL,
Caroline Ticeabb507a2010-09-08 21:06:11 +000053 "Write the breakpoint command script using standard debugger commands."},
Chris Lattner24943d22010-06-08 16:52:24 +000054
55 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
56};
57
58const lldb::OptionDefinition*
59CommandObjectBreakpointCommandAdd::CommandOptions::GetDefinitions ()
60{
61 return g_option_table;
62}
63
64
65Error
66CommandObjectBreakpointCommandAdd::CommandOptions::SetOptionValue
67(
68 int option_idx,
69 const char *option_arg
70)
71{
72 Error error;
73 char short_option = (char) m_getopt_table[option_idx].val;
74
75 switch (short_option)
76 {
77 case 's':
78 m_use_commands = false;
79 m_use_script_language = true;
80 m_script_language = eScriptLanguageDefault;
81 break;
82 case 'p':
83 m_use_commands = false;
84 m_use_script_language = true;
85 m_script_language = eScriptLanguagePython;
86 break;
87 case 'c':
88 m_use_commands = true;
89 m_use_script_language = false;
90 m_script_language = eScriptLanguageNone;
91 break;
92 default:
93 break;
94 }
95 return error;
96}
97
98void
99CommandObjectBreakpointCommandAdd::CommandOptions::ResetOptionValues ()
100{
101 Options::ResetOptionValues();
102
103 m_use_commands = false;
104 m_use_script_language = false;
105 m_script_language = eScriptLanguageNone;
106}
107
108//-------------------------------------------------------------------------
109// CommandObjectBreakpointCommandAdd
110//-------------------------------------------------------------------------
111
112
113CommandObjectBreakpointCommandAdd::CommandObjectBreakpointCommandAdd () :
114 CommandObject ("add",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000115 "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.",
Chris Lattner24943d22010-06-08 16:52:24 +0000116 "breakpoint command add <cmd-options> <breakpoint-id>")
117{
118 SetHelpLong (
119"\nGeneral information about entering breakpoint commands \n\
120------------------------------------------------------ \n\
121 \n\
122This command will cause you to be prompted to enter the command or set \n\
123of commands you wish to be executed when the specified breakpoint is \n\
124hit. You will be told to enter your command(s), and will see a '> ' \n\
125prompt. Because you can enter one or many commands to be executed when \n\
126a breakpoint is hit, you will continue to be prompted after each \n\
127new-line that you enter, until you enter the word 'DONE', which will \n\
128cause the commands you have entered to be stored with the breakpoint \n\
129and executed when the breakpoint is hit. \n\
130 \n\
131Syntax checking is not necessarily done when breakpoint commands are \n\
132entered. An improperly written breakpoint command will attempt to get \n\
133executed when the breakpoint gets hit, and usually silently fail. If \n\
134your breakpoint command does not appear to be getting executed, go \n\
135back and check your syntax. \n\
136 \n\
137 \n\
138Special information about PYTHON breakpoint commands \n\
139---------------------------------------------------- \n\
140 \n\
141You may enter either one line of Python or multiple lines of Python \n\
142(including defining whole functions, if desired). If you enter a \n\
143single line of Python, that will be passed to the Python interpreter \n\
144'as is' when the breakpoint gets hit. If you enter function \n\
145definitions, they will be passed to the Python interpreter as soon as \n\
146you finish entering the breakpoint command, and they can be called \n\
147later (don't forget to add calls to them, if you want them called when \n\
148the breakpoint is hit). If you enter multiple lines of Python that \n\
149are not function definitions, they will be collected into a new, \n\
150automatically generated Python function, and a call to the newly \n\
151generated function will be attached to the breakpoint. Important \n\
152Note: Because loose Python code gets collected into functions, if you \n\
153want to access global variables in the 'loose' code, you need to \n\
154specify that they are global, using the 'global' keyword. Be sure to \n\
155use correct Python syntax, including indentation, when entering Python \n\
156breakpoint commands. \n\
157 \n\
158Example Python one-line breakpoint command: \n\
159 \n\
160(lldb) breakpoint command add -p 1 \n\
161Enter your Python command(s). Type 'DONE' to end. \n\
162> print \"Hit this breakpoint!\" \n\
163> DONE \n\
164 \n\
165Example multiple line Python breakpoint command, using function definition: \n\
166 \n\
167(lldb) breakpoint command add -p 1 \n\
168Enter your Python command(s). Type 'DONE' to end. \n\
169> def breakpoint_output (bp_no): \n\
170> out_string = \"Hit breakpoint number \" + repr (bp_no) \n\
171> print out_string \n\
172> return True \n\
173> breakpoint_output (1) \n\
174> DONE \n\
175 \n\
176 \n\
177Example multiple line Python breakpoint command, using 'loose' Python: \n\
178 \n\
179(lldb) breakpoint command add -p 1 \n\
180Enter your Python command(s). Type 'DONE' to end. \n\
181> global bp_count \n\
182> bp_count = bp_count + 1 \n\
183> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\" \n\
184> DONE \n\
185 \n\
186In this case, since there is a reference to a global variable, \n\
187'bp_count', you will also need to make sure 'bp_count' exists and is \n\
188initialized: \n\
189 \n\
190(lldb) script \n\
191>>> bp_count = 0 \n\
192>>> quit() \n\
193 \n\
194(lldb) \n\
195 \n\
Caroline Ticeabb507a2010-09-08 21:06:11 +0000196Special information about debugger command breakpoint commands \n\
197-------------------------------------------------------------- \n\
Chris Lattner24943d22010-06-08 16:52:24 +0000198 \n\
199You may enter any debugger command, exactly as you would at the \n\
200debugger prompt. You may enter as many debugger commands as you like, \n\
201but do NOT enter more than one command per line. \n" );
202}
203
204CommandObjectBreakpointCommandAdd::~CommandObjectBreakpointCommandAdd ()
205{
206}
207
208bool
209CommandObjectBreakpointCommandAdd::Execute
210(
Greg Clayton63094e02010-06-23 01:19:29 +0000211 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000212 Args& command,
Chris Lattner24943d22010-06-08 16:52:24 +0000213 CommandReturnObject &result
214)
215{
Jim Inghamc8332952010-08-26 21:32:51 +0000216 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000217
218 if (target == NULL)
219 {
220 result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands");
221 result.SetStatus (eReturnStatusFailed);
222 return false;
223 }
224
225 const BreakpointList &breakpoints = target->GetBreakpointList();
226 size_t num_breakpoints = breakpoints.GetSize();
227
228 if (num_breakpoints == 0)
229 {
230 result.AppendError ("No breakpoints exist to have commands added");
231 result.SetStatus (eReturnStatusFailed);
232 return false;
233 }
234
235 if (command.GetArgumentCount() == 0)
236 {
237 result.AppendError ("No breakpoint specified to which to add the commands");
238 result.SetStatus (eReturnStatusFailed);
239 return false;
240 }
241
242 BreakpointIDList valid_bp_ids;
243 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
244
245 if (result.Succeeded())
246 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000247 const size_t count = valid_bp_ids.GetSize();
248 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000249 {
250 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
251 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
252 {
253 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
254 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
255 {
256 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
257 if (bp_loc_sp)
258 {
259 if (m_options.m_use_script_language)
260 {
Greg Claytonbef15832010-07-14 00:18:15 +0000261 interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (interpreter,
262 bp_loc_sp->GetLocationOptions(),
263 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000264 }
265 else
266 {
Greg Claytonbef15832010-07-14 00:18:15 +0000267 CollectDataForBreakpointCommandCallback (interpreter,
268 bp_loc_sp->GetLocationOptions(),
269 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000270 }
271 }
272 }
273 else
274 {
275 if (m_options.m_use_script_language)
276 {
Greg Claytonbef15832010-07-14 00:18:15 +0000277 interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (interpreter,
278 bp->GetOptions(),
279 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000280 }
281 else
282 {
Greg Claytonbef15832010-07-14 00:18:15 +0000283 CollectDataForBreakpointCommandCallback (interpreter,
284 bp->GetOptions(),
285 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000286 }
287 }
288 }
289 }
290 }
291
292 return result.Succeeded();
293}
294
295Options *
296CommandObjectBreakpointCommandAdd::GetOptions ()
297{
298 return &m_options;
299}
300
301const char *g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
302
303void
304CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback
305(
Greg Clayton63094e02010-06-23 01:19:29 +0000306 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000307 BreakpointOptions *bp_options,
308 CommandReturnObject &result
309)
310{
Greg Clayton63094e02010-06-23 01:19:29 +0000311 InputReaderSP reader_sp (new InputReader(interpreter.GetDebugger()));
Chris Lattner24943d22010-06-08 16:52:24 +0000312 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
313 if (reader_sp && data_ap.get())
314 {
315 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
316 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
317
318 Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
319 bp_options, // baton
320 eInputReaderGranularityLine, // token size, to pass to callback function
321 "DONE", // end token
322 "> ", // prompt
323 true)); // echo input
324 if (err.Success())
325 {
Greg Clayton63094e02010-06-23 01:19:29 +0000326 interpreter.GetDebugger().PushInputReader (reader_sp);
Chris Lattner24943d22010-06-08 16:52:24 +0000327 result.SetStatus (eReturnStatusSuccessFinishNoResult);
328 }
329 else
330 {
331 result.AppendError (err.AsCString());
332 result.SetStatus (eReturnStatusFailed);
333 }
334 }
335 else
336 {
337 result.AppendError("out of memory");
338 result.SetStatus (eReturnStatusFailed);
339 }
340
341}
342
343size_t
344CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback
345(
346 void *baton,
Greg Clayton63094e02010-06-23 01:19:29 +0000347 InputReader &reader,
Chris Lattner24943d22010-06-08 16:52:24 +0000348 lldb::InputReaderAction notification,
349 const char *bytes,
350 size_t bytes_len
351)
352{
Greg Clayton63094e02010-06-23 01:19:29 +0000353 FILE *out_fh = reader.GetDebugger().GetOutputFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000354
355 switch (notification)
356 {
357 case eInputReaderActivate:
358 if (out_fh)
359 {
360 ::fprintf (out_fh, "%s\n", g_reader_instructions);
Greg Clayton63094e02010-06-23 01:19:29 +0000361 if (reader.GetPrompt())
362 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000363 }
364 break;
365
366 case eInputReaderDeactivate:
367 break;
368
369 case eInputReaderReactivate:
Greg Clayton63094e02010-06-23 01:19:29 +0000370 if (out_fh && reader.GetPrompt())
371 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000372 break;
373
374 case eInputReaderGotToken:
375 if (bytes && bytes_len && baton)
376 {
377 BreakpointOptions *bp_options = (BreakpointOptions *) baton;
378 if (bp_options)
379 {
380 Baton *bp_options_baton = bp_options->GetBaton();
381 if (bp_options_baton)
382 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
383 }
384 }
Greg Clayton63094e02010-06-23 01:19:29 +0000385 if (out_fh && !reader.IsDone() && reader.GetPrompt())
386 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000387 break;
388
389 case eInputReaderDone:
390 break;
391 }
392
393 return bytes_len;
394}
395
396
397//-------------------------------------------------------------------------
398// CommandObjectBreakpointCommandRemove
399//-------------------------------------------------------------------------
400
401CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove () :
402 CommandObject ("remove",
403 "Remove the set of commands from a breakpoint.",
404 "breakpoint command remove <breakpoint-id>")
405{
406}
407
408CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove ()
409{
410}
411
412bool
Greg Clayton63094e02010-06-23 01:19:29 +0000413CommandObjectBreakpointCommandRemove::Execute
414(
415 CommandInterpreter &interpreter,
416 Args& command,
417 CommandReturnObject &result
418)
Chris Lattner24943d22010-06-08 16:52:24 +0000419{
Jim Inghamc8332952010-08-26 21:32:51 +0000420 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000421
422 if (target == NULL)
423 {
424 result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands");
425 result.SetStatus (eReturnStatusFailed);
426 return false;
427 }
428
429 const BreakpointList &breakpoints = target->GetBreakpointList();
430 size_t num_breakpoints = breakpoints.GetSize();
431
432 if (num_breakpoints == 0)
433 {
434 result.AppendError ("No breakpoints exist to have commands removed");
435 result.SetStatus (eReturnStatusFailed);
436 return false;
437 }
438
439 if (command.GetArgumentCount() == 0)
440 {
441 result.AppendError ("No breakpoint specified from which to remove the commands");
442 result.SetStatus (eReturnStatusFailed);
443 return false;
444 }
445
446 BreakpointIDList valid_bp_ids;
447 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
448
449 if (result.Succeeded())
450 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000451 const size_t count = valid_bp_ids.GetSize();
452 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000453 {
454 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
455 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
456 {
457 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
458 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
459 {
460 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
461 if (bp_loc_sp)
462 bp_loc_sp->ClearCallback();
463 else
464 {
465 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
466 cur_bp_id.GetBreakpointID(),
467 cur_bp_id.GetLocationID());
468 result.SetStatus (eReturnStatusFailed);
469 return false;
470 }
471 }
472 else
473 {
474 bp->ClearCallback();
475 }
476 }
477 }
478 }
479 return result.Succeeded();
480}
481
482
483//-------------------------------------------------------------------------
484// CommandObjectBreakpointCommandList
485//-------------------------------------------------------------------------
486
487CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList () :
488 CommandObject ("List",
489 "List the script or set of commands to be executed when the breakpoint is hit.",
490 "breakpoint command list <breakpoint-id>")
491{
492}
493
494CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList ()
495{
496}
497
498bool
Greg Clayton63094e02010-06-23 01:19:29 +0000499CommandObjectBreakpointCommandList::Execute
500(
501 CommandInterpreter &interpreter,
502 Args& command,
503 CommandReturnObject &result
504)
Chris Lattner24943d22010-06-08 16:52:24 +0000505{
Jim Inghamc8332952010-08-26 21:32:51 +0000506 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000507
508 if (target == NULL)
509 {
510 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
511 result.SetStatus (eReturnStatusFailed);
512 return false;
513 }
514
515 const BreakpointList &breakpoints = target->GetBreakpointList();
516 size_t num_breakpoints = breakpoints.GetSize();
517
518 if (num_breakpoints == 0)
519 {
520 result.AppendError ("No breakpoints exist for which to list commands");
521 result.SetStatus (eReturnStatusFailed);
522 return false;
523 }
524
525 if (command.GetArgumentCount() == 0)
526 {
527 result.AppendError ("No breakpoint specified for which to list the commands");
528 result.SetStatus (eReturnStatusFailed);
529 return false;
530 }
531
532 BreakpointIDList valid_bp_ids;
533 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
534
535 if (result.Succeeded())
536 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000537 const size_t count = valid_bp_ids.GetSize();
538 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000539 {
540 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
541 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
542 {
543 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
544
545 if (bp)
546 {
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000547 const BreakpointOptions *bp_options = NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000548 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
549 {
550 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
551 if (bp_loc_sp)
Jim Ingham9c6898b2010-06-22 21:12:54 +0000552 bp_options = bp_loc_sp->GetOptionsNoCreate();
Chris Lattner24943d22010-06-08 16:52:24 +0000553 else
554 {
555 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
556 cur_bp_id.GetBreakpointID(),
557 cur_bp_id.GetLocationID());
558 result.SetStatus (eReturnStatusFailed);
559 return false;
560 }
561 }
562 else
563 {
564 bp_options = bp->GetOptions();
565 }
566
567 if (bp_options)
568 {
569 StreamString id_str;
570 BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000571 const Baton *baton = bp_options->GetBaton();
Chris Lattner24943d22010-06-08 16:52:24 +0000572 if (baton)
573 {
574 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
575 result.GetOutputStream().IndentMore ();
576 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
577 result.GetOutputStream().IndentLess ();
578 }
579 else
580 {
581 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData());
582 }
583 }
584 result.SetStatus (eReturnStatusSuccessFinishResult);
585 }
586 else
587 {
588 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
589 result.SetStatus (eReturnStatusFailed);
590 }
591
592 }
593 }
594 }
595
596 return result.Succeeded();
597}
598
599//-------------------------------------------------------------------------
600// CommandObjectBreakpointCommand
601//-------------------------------------------------------------------------
602
Greg Clayton63094e02010-06-23 01:19:29 +0000603CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
Chris Lattner24943d22010-06-08 16:52:24 +0000604 CommandObjectMultiword ("command",
605 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
606 "command <sub-command> [<sub-command-options>] <breakpoint-id>")
607{
608 bool status;
609 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd ());
610 CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove ());
611 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList ());
612
613 add_command_object->SetCommandName ("breakpoint command add");
614 remove_command_object->SetCommandName ("breakpoint command remove");
615 list_command_object->SetCommandName ("breakpoint command list");
616
Greg Clayton63094e02010-06-23 01:19:29 +0000617 status = LoadSubCommand (interpreter, "add", add_command_object);
618 status = LoadSubCommand (interpreter, "remove", remove_command_object);
619 status = LoadSubCommand (interpreter, "list", list_command_object);
Chris Lattner24943d22010-06-08 16:52:24 +0000620}
621
622
623CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
624{
625}
626
627bool
628CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction
629(
630 void *baton,
631 StoppointCallbackContext *context,
632 lldb::user_id_t break_id,
633 lldb::user_id_t break_loc_id
634)
635{
636 bool ret_value = true;
637 if (baton == NULL)
638 return true;
639
640
641 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
642 StringList &commands = data->user_source;
643
644 if (commands.GetSize() > 0)
645 {
646 uint32_t num_commands = commands.GetSize();
Chris Lattner24943d22010-06-08 16:52:24 +0000647 CommandReturnObject result;
Greg Clayton63094e02010-06-23 01:19:29 +0000648 if (context->exe_ctx.target)
Chris Lattner24943d22010-06-08 16:52:24 +0000649 {
Greg Clayton63094e02010-06-23 01:19:29 +0000650
651 Debugger &debugger = context->exe_ctx.target->GetDebugger();
652 CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
653
654 FILE *out_fh = debugger.GetOutputFileHandle();
655 FILE *err_fh = debugger.GetErrorFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000656
Greg Clayton63094e02010-06-23 01:19:29 +0000657 uint32_t i;
658 for (i = 0; i < num_commands; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000659 {
Greg Clayton63094e02010-06-23 01:19:29 +0000660
661 // First time through we use the context from the stoppoint, after that we use whatever
662 // has been set by the previous command.
663
664 if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &context->exe_ctx))
665 break;
666
667 // FIXME: This isn't really the right way to do this. We should be able to peek at the public
668 // to see if there is any new events, but that is racey, since the internal process thread has to run and
669 // deliver the event to the public queue before a run will show up. So for now we check
670 // the internal thread state.
671
672 lldb::StateType internal_state = context->exe_ctx.process->GetPrivateState();
673 if (internal_state != eStateStopped)
Chris Lattner24943d22010-06-08 16:52:24 +0000674 {
Greg Clayton63094e02010-06-23 01:19:29 +0000675 if (i < num_commands - 1)
676 {
677 if (out_fh)
678 ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s."
679 " last command: \"%s\"\n", StateAsCString(internal_state),
680 commands.GetStringAtIndex(i));
681 }
682 break;
Chris Lattner24943d22010-06-08 16:52:24 +0000683 }
Greg Clayton63094e02010-06-23 01:19:29 +0000684
685 if (out_fh)
686 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
687 if (err_fh)
688 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
689 result.Clear();
690 result.SetStatus (eReturnStatusSuccessFinishNoResult);
Chris Lattner24943d22010-06-08 16:52:24 +0000691 }
Chris Lattner24943d22010-06-08 16:52:24 +0000692
Greg Clayton63094e02010-06-23 01:19:29 +0000693 if (err_fh && !result.Succeeded() && i < num_commands)
694 ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i));
695
Chris Lattner24943d22010-06-08 16:52:24 +0000696 if (out_fh)
697 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
Greg Clayton63094e02010-06-23 01:19:29 +0000698
Chris Lattner24943d22010-06-08 16:52:24 +0000699 if (err_fh)
Greg Clayton63094e02010-06-23 01:19:29 +0000700 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
Chris Lattner24943d22010-06-08 16:52:24 +0000701 }
Chris Lattner24943d22010-06-08 16:52:24 +0000702 }
703 return ret_value;
704}
705