blob: c74c2bcdc2c8f0084e90db03dbd6aa7f60d28889 [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\
Johnny Chen4c1b2182010-09-10 19:34:12 +0000165As a convenience, this also works for a short Python one-liner: \n\
166(lldb) breakpoint command add -p 1 \"import time; print time.asctime()\" \n\
167(lldb) run \n\
168Launching '.../a.out' (x86_64) \n\
169(lldb) Fri Sep 10 12:17:45 2010 \n\
170Process 21778 Stopped \n\
171* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread \n\
172 36 \n\
173 37 int c(int val)\n\
174 38 {\n\
175 39 -> return val + 3;\n\
176 40 }\n\
177 41 \n\
178 42 int main (int argc, char const *argv[])\n\
179(lldb) \n\
180 \n\
Chris Lattner24943d22010-06-08 16:52:24 +0000181Example multiple line Python breakpoint command, using function definition: \n\
182 \n\
183(lldb) breakpoint command add -p 1 \n\
184Enter your Python command(s). Type 'DONE' to end. \n\
185> def breakpoint_output (bp_no): \n\
186> out_string = \"Hit breakpoint number \" + repr (bp_no) \n\
187> print out_string \n\
188> return True \n\
189> breakpoint_output (1) \n\
190> DONE \n\
191 \n\
192 \n\
193Example multiple line Python breakpoint command, using 'loose' Python: \n\
194 \n\
195(lldb) breakpoint command add -p 1 \n\
196Enter your Python command(s). Type 'DONE' to end. \n\
197> global bp_count \n\
198> bp_count = bp_count + 1 \n\
199> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\" \n\
200> DONE \n\
201 \n\
202In this case, since there is a reference to a global variable, \n\
203'bp_count', you will also need to make sure 'bp_count' exists and is \n\
204initialized: \n\
205 \n\
206(lldb) script \n\
207>>> bp_count = 0 \n\
208>>> quit() \n\
209 \n\
210(lldb) \n\
211 \n\
Caroline Ticeabb507a2010-09-08 21:06:11 +0000212Special information about debugger command breakpoint commands \n\
213-------------------------------------------------------------- \n\
Chris Lattner24943d22010-06-08 16:52:24 +0000214 \n\
215You may enter any debugger command, exactly as you would at the \n\
216debugger prompt. You may enter as many debugger commands as you like, \n\
217but do NOT enter more than one command per line. \n" );
218}
219
220CommandObjectBreakpointCommandAdd::~CommandObjectBreakpointCommandAdd ()
221{
222}
223
224bool
225CommandObjectBreakpointCommandAdd::Execute
226(
Greg Clayton63094e02010-06-23 01:19:29 +0000227 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000228 Args& command,
Chris Lattner24943d22010-06-08 16:52:24 +0000229 CommandReturnObject &result
230)
231{
Jim Inghamc8332952010-08-26 21:32:51 +0000232 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000233
234 if (target == NULL)
235 {
236 result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands");
237 result.SetStatus (eReturnStatusFailed);
238 return false;
239 }
240
241 const BreakpointList &breakpoints = target->GetBreakpointList();
242 size_t num_breakpoints = breakpoints.GetSize();
243
244 if (num_breakpoints == 0)
245 {
246 result.AppendError ("No breakpoints exist to have commands added");
247 result.SetStatus (eReturnStatusFailed);
248 return false;
249 }
250
251 if (command.GetArgumentCount() == 0)
252 {
253 result.AppendError ("No breakpoint specified to which to add the commands");
254 result.SetStatus (eReturnStatusFailed);
255 return false;
256 }
257
258 BreakpointIDList valid_bp_ids;
259 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
260
261 if (result.Succeeded())
262 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000263 const size_t count = valid_bp_ids.GetSize();
264 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000265 {
266 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
267 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
268 {
269 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
270 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
271 {
272 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
273 if (bp_loc_sp)
274 {
275 if (m_options.m_use_script_language)
276 {
Johnny Chend1c2dca2010-09-10 18:21:10 +0000277 // Special handling for one-liner.
Johnny Chenc328d212010-09-10 20:15:13 +0000278 if (command.GetArgumentCount() == 2 && count == 1)
Johnny Chend1c2dca2010-09-10 18:21:10 +0000279 interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (interpreter,
280 bp_loc_sp->GetLocationOptions(),
281 command.GetArgumentAtIndex(1));
282 else
283 interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (interpreter,
284 bp_loc_sp->GetLocationOptions(),
285 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000286 }
287 else
288 {
Greg Claytonbef15832010-07-14 00:18:15 +0000289 CollectDataForBreakpointCommandCallback (interpreter,
290 bp_loc_sp->GetLocationOptions(),
291 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000292 }
293 }
294 }
295 else
296 {
297 if (m_options.m_use_script_language)
298 {
Johnny Chend1c2dca2010-09-10 18:21:10 +0000299 // Special handling for one-liner.
Johnny Chenc328d212010-09-10 20:15:13 +0000300 if (command.GetArgumentCount() == 2 && count == 1)
Johnny Chend1c2dca2010-09-10 18:21:10 +0000301 interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (interpreter,
302 bp->GetOptions(),
303 command.GetArgumentAtIndex(1));
304 else
305 interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (interpreter,
306 bp->GetOptions(),
307 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000308 }
309 else
310 {
Greg Claytonbef15832010-07-14 00:18:15 +0000311 CollectDataForBreakpointCommandCallback (interpreter,
312 bp->GetOptions(),
313 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000314 }
315 }
316 }
317 }
318 }
319
320 return result.Succeeded();
321}
322
323Options *
324CommandObjectBreakpointCommandAdd::GetOptions ()
325{
326 return &m_options;
327}
328
329const char *g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
330
331void
332CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback
333(
Greg Clayton63094e02010-06-23 01:19:29 +0000334 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000335 BreakpointOptions *bp_options,
336 CommandReturnObject &result
337)
338{
Greg Clayton63094e02010-06-23 01:19:29 +0000339 InputReaderSP reader_sp (new InputReader(interpreter.GetDebugger()));
Chris Lattner24943d22010-06-08 16:52:24 +0000340 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
341 if (reader_sp && data_ap.get())
342 {
343 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
344 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
345
346 Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
347 bp_options, // baton
348 eInputReaderGranularityLine, // token size, to pass to callback function
349 "DONE", // end token
350 "> ", // prompt
351 true)); // echo input
352 if (err.Success())
353 {
Greg Clayton63094e02010-06-23 01:19:29 +0000354 interpreter.GetDebugger().PushInputReader (reader_sp);
Chris Lattner24943d22010-06-08 16:52:24 +0000355 result.SetStatus (eReturnStatusSuccessFinishNoResult);
356 }
357 else
358 {
359 result.AppendError (err.AsCString());
360 result.SetStatus (eReturnStatusFailed);
361 }
362 }
363 else
364 {
365 result.AppendError("out of memory");
366 result.SetStatus (eReturnStatusFailed);
367 }
368
369}
370
371size_t
372CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback
373(
374 void *baton,
Greg Clayton63094e02010-06-23 01:19:29 +0000375 InputReader &reader,
Chris Lattner24943d22010-06-08 16:52:24 +0000376 lldb::InputReaderAction notification,
377 const char *bytes,
378 size_t bytes_len
379)
380{
Greg Clayton63094e02010-06-23 01:19:29 +0000381 FILE *out_fh = reader.GetDebugger().GetOutputFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000382
383 switch (notification)
384 {
385 case eInputReaderActivate:
386 if (out_fh)
387 {
388 ::fprintf (out_fh, "%s\n", g_reader_instructions);
Greg Clayton63094e02010-06-23 01:19:29 +0000389 if (reader.GetPrompt())
390 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000391 }
392 break;
393
394 case eInputReaderDeactivate:
395 break;
396
397 case eInputReaderReactivate:
Greg Clayton63094e02010-06-23 01:19:29 +0000398 if (out_fh && reader.GetPrompt())
399 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000400 break;
401
402 case eInputReaderGotToken:
403 if (bytes && bytes_len && baton)
404 {
405 BreakpointOptions *bp_options = (BreakpointOptions *) baton;
406 if (bp_options)
407 {
408 Baton *bp_options_baton = bp_options->GetBaton();
409 if (bp_options_baton)
410 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
411 }
412 }
Greg Clayton63094e02010-06-23 01:19:29 +0000413 if (out_fh && !reader.IsDone() && reader.GetPrompt())
414 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000415 break;
416
417 case eInputReaderDone:
418 break;
419 }
420
421 return bytes_len;
422}
423
424
425//-------------------------------------------------------------------------
426// CommandObjectBreakpointCommandRemove
427//-------------------------------------------------------------------------
428
429CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove () :
430 CommandObject ("remove",
431 "Remove the set of commands from a breakpoint.",
432 "breakpoint command remove <breakpoint-id>")
433{
434}
435
436CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove ()
437{
438}
439
440bool
Greg Clayton63094e02010-06-23 01:19:29 +0000441CommandObjectBreakpointCommandRemove::Execute
442(
443 CommandInterpreter &interpreter,
444 Args& command,
445 CommandReturnObject &result
446)
Chris Lattner24943d22010-06-08 16:52:24 +0000447{
Jim Inghamc8332952010-08-26 21:32:51 +0000448 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000449
450 if (target == NULL)
451 {
452 result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands");
453 result.SetStatus (eReturnStatusFailed);
454 return false;
455 }
456
457 const BreakpointList &breakpoints = target->GetBreakpointList();
458 size_t num_breakpoints = breakpoints.GetSize();
459
460 if (num_breakpoints == 0)
461 {
462 result.AppendError ("No breakpoints exist to have commands removed");
463 result.SetStatus (eReturnStatusFailed);
464 return false;
465 }
466
467 if (command.GetArgumentCount() == 0)
468 {
469 result.AppendError ("No breakpoint specified from which to remove the commands");
470 result.SetStatus (eReturnStatusFailed);
471 return false;
472 }
473
474 BreakpointIDList valid_bp_ids;
475 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
476
477 if (result.Succeeded())
478 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000479 const size_t count = valid_bp_ids.GetSize();
480 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000481 {
482 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
483 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
484 {
485 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
486 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
487 {
488 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
489 if (bp_loc_sp)
490 bp_loc_sp->ClearCallback();
491 else
492 {
493 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
494 cur_bp_id.GetBreakpointID(),
495 cur_bp_id.GetLocationID());
496 result.SetStatus (eReturnStatusFailed);
497 return false;
498 }
499 }
500 else
501 {
502 bp->ClearCallback();
503 }
504 }
505 }
506 }
507 return result.Succeeded();
508}
509
510
511//-------------------------------------------------------------------------
512// CommandObjectBreakpointCommandList
513//-------------------------------------------------------------------------
514
515CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList () :
516 CommandObject ("List",
517 "List the script or set of commands to be executed when the breakpoint is hit.",
518 "breakpoint command list <breakpoint-id>")
519{
520}
521
522CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList ()
523{
524}
525
526bool
Greg Clayton63094e02010-06-23 01:19:29 +0000527CommandObjectBreakpointCommandList::Execute
528(
529 CommandInterpreter &interpreter,
530 Args& command,
531 CommandReturnObject &result
532)
Chris Lattner24943d22010-06-08 16:52:24 +0000533{
Jim Inghamc8332952010-08-26 21:32:51 +0000534 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000535
536 if (target == NULL)
537 {
538 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
539 result.SetStatus (eReturnStatusFailed);
540 return false;
541 }
542
543 const BreakpointList &breakpoints = target->GetBreakpointList();
544 size_t num_breakpoints = breakpoints.GetSize();
545
546 if (num_breakpoints == 0)
547 {
548 result.AppendError ("No breakpoints exist for which to list commands");
549 result.SetStatus (eReturnStatusFailed);
550 return false;
551 }
552
553 if (command.GetArgumentCount() == 0)
554 {
555 result.AppendError ("No breakpoint specified for which to list the commands");
556 result.SetStatus (eReturnStatusFailed);
557 return false;
558 }
559
560 BreakpointIDList valid_bp_ids;
561 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
562
563 if (result.Succeeded())
564 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000565 const size_t count = valid_bp_ids.GetSize();
566 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000567 {
568 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
569 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
570 {
571 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
572
573 if (bp)
574 {
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000575 const BreakpointOptions *bp_options = NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000576 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
577 {
578 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
579 if (bp_loc_sp)
Jim Ingham9c6898b2010-06-22 21:12:54 +0000580 bp_options = bp_loc_sp->GetOptionsNoCreate();
Chris Lattner24943d22010-06-08 16:52:24 +0000581 else
582 {
583 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
584 cur_bp_id.GetBreakpointID(),
585 cur_bp_id.GetLocationID());
586 result.SetStatus (eReturnStatusFailed);
587 return false;
588 }
589 }
590 else
591 {
592 bp_options = bp->GetOptions();
593 }
594
595 if (bp_options)
596 {
597 StreamString id_str;
598 BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000599 const Baton *baton = bp_options->GetBaton();
Chris Lattner24943d22010-06-08 16:52:24 +0000600 if (baton)
601 {
602 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
603 result.GetOutputStream().IndentMore ();
604 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
605 result.GetOutputStream().IndentLess ();
606 }
607 else
608 {
609 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData());
610 }
611 }
612 result.SetStatus (eReturnStatusSuccessFinishResult);
613 }
614 else
615 {
616 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
617 result.SetStatus (eReturnStatusFailed);
618 }
619
620 }
621 }
622 }
623
624 return result.Succeeded();
625}
626
627//-------------------------------------------------------------------------
628// CommandObjectBreakpointCommand
629//-------------------------------------------------------------------------
630
Greg Clayton63094e02010-06-23 01:19:29 +0000631CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
Chris Lattner24943d22010-06-08 16:52:24 +0000632 CommandObjectMultiword ("command",
633 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
634 "command <sub-command> [<sub-command-options>] <breakpoint-id>")
635{
636 bool status;
637 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd ());
638 CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove ());
639 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList ());
640
641 add_command_object->SetCommandName ("breakpoint command add");
642 remove_command_object->SetCommandName ("breakpoint command remove");
643 list_command_object->SetCommandName ("breakpoint command list");
644
Greg Clayton63094e02010-06-23 01:19:29 +0000645 status = LoadSubCommand (interpreter, "add", add_command_object);
646 status = LoadSubCommand (interpreter, "remove", remove_command_object);
647 status = LoadSubCommand (interpreter, "list", list_command_object);
Chris Lattner24943d22010-06-08 16:52:24 +0000648}
649
650
651CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
652{
653}
654
655bool
656CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction
657(
658 void *baton,
659 StoppointCallbackContext *context,
660 lldb::user_id_t break_id,
661 lldb::user_id_t break_loc_id
662)
663{
664 bool ret_value = true;
665 if (baton == NULL)
666 return true;
667
668
669 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
670 StringList &commands = data->user_source;
671
672 if (commands.GetSize() > 0)
673 {
674 uint32_t num_commands = commands.GetSize();
Chris Lattner24943d22010-06-08 16:52:24 +0000675 CommandReturnObject result;
Greg Clayton63094e02010-06-23 01:19:29 +0000676 if (context->exe_ctx.target)
Chris Lattner24943d22010-06-08 16:52:24 +0000677 {
Greg Clayton63094e02010-06-23 01:19:29 +0000678
679 Debugger &debugger = context->exe_ctx.target->GetDebugger();
680 CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
681
682 FILE *out_fh = debugger.GetOutputFileHandle();
683 FILE *err_fh = debugger.GetErrorFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000684
Greg Clayton63094e02010-06-23 01:19:29 +0000685 uint32_t i;
686 for (i = 0; i < num_commands; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000687 {
Greg Clayton63094e02010-06-23 01:19:29 +0000688
689 // First time through we use the context from the stoppoint, after that we use whatever
690 // has been set by the previous command.
691
692 if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &context->exe_ctx))
693 break;
694
695 // FIXME: This isn't really the right way to do this. We should be able to peek at the public
696 // to see if there is any new events, but that is racey, since the internal process thread has to run and
697 // deliver the event to the public queue before a run will show up. So for now we check
698 // the internal thread state.
699
700 lldb::StateType internal_state = context->exe_ctx.process->GetPrivateState();
701 if (internal_state != eStateStopped)
Chris Lattner24943d22010-06-08 16:52:24 +0000702 {
Greg Clayton63094e02010-06-23 01:19:29 +0000703 if (i < num_commands - 1)
704 {
705 if (out_fh)
706 ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s."
707 " last command: \"%s\"\n", StateAsCString(internal_state),
708 commands.GetStringAtIndex(i));
709 }
710 break;
Chris Lattner24943d22010-06-08 16:52:24 +0000711 }
Greg Clayton63094e02010-06-23 01:19:29 +0000712
713 if (out_fh)
714 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
715 if (err_fh)
716 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
717 result.Clear();
718 result.SetStatus (eReturnStatusSuccessFinishNoResult);
Chris Lattner24943d22010-06-08 16:52:24 +0000719 }
Chris Lattner24943d22010-06-08 16:52:24 +0000720
Greg Clayton63094e02010-06-23 01:19:29 +0000721 if (err_fh && !result.Succeeded() && i < num_commands)
722 ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i));
723
Chris Lattner24943d22010-06-08 16:52:24 +0000724 if (out_fh)
725 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
Greg Clayton63094e02010-06-23 01:19:29 +0000726
Chris Lattner24943d22010-06-08 16:52:24 +0000727 if (err_fh)
Greg Clayton63094e02010-06-23 01:19:29 +0000728 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
Chris Lattner24943d22010-06-08 16:52:24 +0000729 }
Chris Lattner24943d22010-06-08 16:52:24 +0000730 }
731 return ret_value;
732}
733