blob: 49ee1ea15eb6cb7e28a579f19c125d0d3a2ea39e [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 () :
Johnny Chenb81ed0d2010-09-11 00:18:09 +000035 Options (),
36 m_use_commands (false),
37 m_use_script_language (false),
38 m_script_language (eScriptLanguageNone),
39 m_use_one_liner (false),
40 m_one_liner()
Chris Lattner24943d22010-06-08 16:52:24 +000041{
Chris Lattner24943d22010-06-08 16:52:24 +000042}
43
44CommandObjectBreakpointCommandAdd::CommandOptions::~CommandOptions ()
45{
46}
47
48lldb::OptionDefinition
49CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] =
50{
Johnny Chenb81ed0d2010-09-11 00:18:09 +000051 { LLDB_OPT_SET_ALL, false, "one_liner", 'o', required_argument, NULL, 0, "<one-liner>",
52 "Specify a one-liner inline." },
53
Jim Ingham34e9a982010-06-15 18:47:14 +000054 { LLDB_OPT_SET_1, true, "script", 's', no_argument, NULL, 0, NULL,
Chris Lattner24943d22010-06-08 16:52:24 +000055 "Write the breakpoint command script in the default scripting language."},
56
Jim Ingham34e9a982010-06-15 18:47:14 +000057 { LLDB_OPT_SET_2, true, "python", 'p', no_argument, NULL, 0, NULL,
Chris Lattner24943d22010-06-08 16:52:24 +000058 "Write the breakpoint command script in the Python scripting language."},
59
Jim Ingham34e9a982010-06-15 18:47:14 +000060 { LLDB_OPT_SET_3, true, "commands", 'c', no_argument, NULL, 0, NULL,
Caroline Ticeabb507a2010-09-08 21:06:11 +000061 "Write the breakpoint command script using standard debugger commands."},
Chris Lattner24943d22010-06-08 16:52:24 +000062
63 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
64};
65
66const lldb::OptionDefinition*
67CommandObjectBreakpointCommandAdd::CommandOptions::GetDefinitions ()
68{
69 return g_option_table;
70}
71
72
73Error
74CommandObjectBreakpointCommandAdd::CommandOptions::SetOptionValue
75(
76 int option_idx,
77 const char *option_arg
78)
79{
80 Error error;
81 char short_option = (char) m_getopt_table[option_idx].val;
82
83 switch (short_option)
84 {
Johnny Chenb81ed0d2010-09-11 00:18:09 +000085 case 'o':
86 m_use_one_liner = true;
87 m_one_liner = option_arg;
88 break;
Chris Lattner24943d22010-06-08 16:52:24 +000089 case 's':
90 m_use_commands = false;
91 m_use_script_language = true;
92 m_script_language = eScriptLanguageDefault;
93 break;
94 case 'p':
95 m_use_commands = false;
96 m_use_script_language = true;
97 m_script_language = eScriptLanguagePython;
98 break;
99 case 'c':
100 m_use_commands = true;
101 m_use_script_language = false;
102 m_script_language = eScriptLanguageNone;
103 break;
104 default:
105 break;
106 }
107 return error;
108}
109
110void
111CommandObjectBreakpointCommandAdd::CommandOptions::ResetOptionValues ()
112{
113 Options::ResetOptionValues();
114
115 m_use_commands = false;
116 m_use_script_language = false;
117 m_script_language = eScriptLanguageNone;
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000118
119 m_use_one_liner = false;
120 m_one_liner.clear();
Chris Lattner24943d22010-06-08 16:52:24 +0000121}
122
123//-------------------------------------------------------------------------
124// CommandObjectBreakpointCommandAdd
125//-------------------------------------------------------------------------
126
127
128CommandObjectBreakpointCommandAdd::CommandObjectBreakpointCommandAdd () :
129 CommandObject ("add",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000130 "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.",
Chris Lattner24943d22010-06-08 16:52:24 +0000131 "breakpoint command add <cmd-options> <breakpoint-id>")
132{
133 SetHelpLong (
134"\nGeneral information about entering breakpoint commands \n\
135------------------------------------------------------ \n\
136 \n\
137This command will cause you to be prompted to enter the command or set \n\
138of commands you wish to be executed when the specified breakpoint is \n\
139hit. You will be told to enter your command(s), and will see a '> ' \n\
140prompt. Because you can enter one or many commands to be executed when \n\
141a breakpoint is hit, you will continue to be prompted after each \n\
142new-line that you enter, until you enter the word 'DONE', which will \n\
143cause the commands you have entered to be stored with the breakpoint \n\
144and executed when the breakpoint is hit. \n\
145 \n\
146Syntax checking is not necessarily done when breakpoint commands are \n\
147entered. An improperly written breakpoint command will attempt to get \n\
148executed when the breakpoint gets hit, and usually silently fail. If \n\
149your breakpoint command does not appear to be getting executed, go \n\
150back and check your syntax. \n\
151 \n\
152 \n\
153Special information about PYTHON breakpoint commands \n\
154---------------------------------------------------- \n\
155 \n\
156You may enter either one line of Python or multiple lines of Python \n\
157(including defining whole functions, if desired). If you enter a \n\
158single line of Python, that will be passed to the Python interpreter \n\
159'as is' when the breakpoint gets hit. If you enter function \n\
160definitions, they will be passed to the Python interpreter as soon as \n\
161you finish entering the breakpoint command, and they can be called \n\
162later (don't forget to add calls to them, if you want them called when \n\
163the breakpoint is hit). If you enter multiple lines of Python that \n\
164are not function definitions, they will be collected into a new, \n\
165automatically generated Python function, and a call to the newly \n\
166generated function will be attached to the breakpoint. Important \n\
167Note: Because loose Python code gets collected into functions, if you \n\
168want to access global variables in the 'loose' code, you need to \n\
169specify that they are global, using the 'global' keyword. Be sure to \n\
170use correct Python syntax, including indentation, when entering Python \n\
171breakpoint commands. \n\
172 \n\
173Example Python one-line breakpoint command: \n\
174 \n\
175(lldb) breakpoint command add -p 1 \n\
176Enter your Python command(s). Type 'DONE' to end. \n\
177> print \"Hit this breakpoint!\" \n\
178> DONE \n\
179 \n\
Johnny Chen4c1b2182010-09-10 19:34:12 +0000180As a convenience, this also works for a short Python one-liner: \n\
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000181(lldb) breakpoint command add -p 1 -o \"import time; print time.asctime()\" \n\
Johnny Chen4c1b2182010-09-10 19:34:12 +0000182(lldb) run \n\
183Launching '.../a.out' (x86_64) \n\
184(lldb) Fri Sep 10 12:17:45 2010 \n\
185Process 21778 Stopped \n\
186* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread \n\
187 36 \n\
188 37 int c(int val)\n\
189 38 {\n\
190 39 -> return val + 3;\n\
191 40 }\n\
192 41 \n\
193 42 int main (int argc, char const *argv[])\n\
194(lldb) \n\
195 \n\
Chris Lattner24943d22010-06-08 16:52:24 +0000196Example multiple line Python breakpoint command, using function definition: \n\
197 \n\
198(lldb) breakpoint command add -p 1 \n\
199Enter your Python command(s). Type 'DONE' to end. \n\
200> def breakpoint_output (bp_no): \n\
201> out_string = \"Hit breakpoint number \" + repr (bp_no) \n\
202> print out_string \n\
203> return True \n\
204> breakpoint_output (1) \n\
205> DONE \n\
206 \n\
207 \n\
208Example multiple line Python breakpoint command, using 'loose' Python: \n\
209 \n\
210(lldb) breakpoint command add -p 1 \n\
211Enter your Python command(s). Type 'DONE' to end. \n\
212> global bp_count \n\
213> bp_count = bp_count + 1 \n\
214> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\" \n\
215> DONE \n\
216 \n\
217In this case, since there is a reference to a global variable, \n\
218'bp_count', you will also need to make sure 'bp_count' exists and is \n\
219initialized: \n\
220 \n\
221(lldb) script \n\
222>>> bp_count = 0 \n\
223>>> quit() \n\
224 \n\
225(lldb) \n\
226 \n\
Caroline Ticeabb507a2010-09-08 21:06:11 +0000227Special information about debugger command breakpoint commands \n\
228-------------------------------------------------------------- \n\
Chris Lattner24943d22010-06-08 16:52:24 +0000229 \n\
230You may enter any debugger command, exactly as you would at the \n\
231debugger prompt. You may enter as many debugger commands as you like, \n\
232but do NOT enter more than one command per line. \n" );
233}
234
235CommandObjectBreakpointCommandAdd::~CommandObjectBreakpointCommandAdd ()
236{
237}
238
239bool
240CommandObjectBreakpointCommandAdd::Execute
241(
Greg Clayton63094e02010-06-23 01:19:29 +0000242 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000243 Args& command,
Chris Lattner24943d22010-06-08 16:52:24 +0000244 CommandReturnObject &result
245)
246{
Jim Inghamc8332952010-08-26 21:32:51 +0000247 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000248
249 if (target == NULL)
250 {
251 result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands");
252 result.SetStatus (eReturnStatusFailed);
253 return false;
254 }
255
256 const BreakpointList &breakpoints = target->GetBreakpointList();
257 size_t num_breakpoints = breakpoints.GetSize();
258
259 if (num_breakpoints == 0)
260 {
261 result.AppendError ("No breakpoints exist to have commands added");
262 result.SetStatus (eReturnStatusFailed);
263 return false;
264 }
265
266 if (command.GetArgumentCount() == 0)
267 {
268 result.AppendError ("No breakpoint specified to which to add the commands");
269 result.SetStatus (eReturnStatusFailed);
270 return false;
271 }
272
273 BreakpointIDList valid_bp_ids;
274 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
275
276 if (result.Succeeded())
277 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000278 const size_t count = valid_bp_ids.GetSize();
279 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000280 {
281 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
282 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
283 {
284 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000285 BreakpointOptions *bp_options = NULL;
286 if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
287 {
288 // This breakpoint does not have an associated location.
289 bp_options = bp->GetOptions();
290 }
291 else
Chris Lattner24943d22010-06-08 16:52:24 +0000292 {
293 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000294 // This breakpoint does have an associated location.
295 // Get its breakpoint options.
Chris Lattner24943d22010-06-08 16:52:24 +0000296 if (bp_loc_sp)
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000297 bp_options = bp_loc_sp->GetLocationOptions();
298 }
299
300 // Skip this breakpoiont if bp_options is not good.
301 if (bp_options == NULL) continue;
302
303 // If we are using script language, get the script interpreter
304 // in order to set or collect command callback. Otherwise, call
305 // the methods associated with this object.
306 if (m_options.m_use_script_language)
307 {
308 // Special handling for one-liner specified inline.
309 if (m_options.m_use_one_liner)
310 interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (interpreter,
311 bp_options,
312 m_options.m_one_liner.c_str());
313 else
314 interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (interpreter,
315 bp_options,
316 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000317 }
318 else
319 {
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000320 // Special handling for one-liner specified inline.
321 if (m_options.m_use_one_liner)
322 SetBreakpointCommandCallback (interpreter,
323 bp_options,
324 m_options.m_one_liner.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000325 else
Greg Claytonbef15832010-07-14 00:18:15 +0000326 CollectDataForBreakpointCommandCallback (interpreter,
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000327 bp_options,
Greg Claytonbef15832010-07-14 00:18:15 +0000328 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000329 }
330 }
331 }
332 }
333
334 return result.Succeeded();
335}
336
337Options *
338CommandObjectBreakpointCommandAdd::GetOptions ()
339{
340 return &m_options;
341}
342
343const char *g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
344
345void
346CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback
347(
Greg Clayton63094e02010-06-23 01:19:29 +0000348 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000349 BreakpointOptions *bp_options,
350 CommandReturnObject &result
351)
352{
Greg Clayton63094e02010-06-23 01:19:29 +0000353 InputReaderSP reader_sp (new InputReader(interpreter.GetDebugger()));
Chris Lattner24943d22010-06-08 16:52:24 +0000354 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
355 if (reader_sp && data_ap.get())
356 {
357 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
358 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
359
360 Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
361 bp_options, // baton
362 eInputReaderGranularityLine, // token size, to pass to callback function
363 "DONE", // end token
364 "> ", // prompt
365 true)); // echo input
366 if (err.Success())
367 {
Greg Clayton63094e02010-06-23 01:19:29 +0000368 interpreter.GetDebugger().PushInputReader (reader_sp);
Chris Lattner24943d22010-06-08 16:52:24 +0000369 result.SetStatus (eReturnStatusSuccessFinishNoResult);
370 }
371 else
372 {
373 result.AppendError (err.AsCString());
374 result.SetStatus (eReturnStatusFailed);
375 }
376 }
377 else
378 {
379 result.AppendError("out of memory");
380 result.SetStatus (eReturnStatusFailed);
381 }
382
383}
384
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000385// Set a one-liner as the callback for the breakpoint command.
386void
387CommandObjectBreakpointCommandAdd::SetBreakpointCommandCallback (CommandInterpreter &interpreter,
388 BreakpointOptions *bp_options,
389 const char *oneliner)
390{
391 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
392
393 // It's necessary to set both user_source and script_source to the oneliner.
394 // The former is used to generate callback description (as in breakpoint command list)
395 // while the latter is used for Python to interpret during the actual callback.
396 data_ap->user_source.AppendString (oneliner);
397 data_ap->script_source.AppendString (oneliner);
398
399 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
400 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
401
402 return;
403}
404
Chris Lattner24943d22010-06-08 16:52:24 +0000405size_t
406CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback
407(
408 void *baton,
Greg Clayton63094e02010-06-23 01:19:29 +0000409 InputReader &reader,
Chris Lattner24943d22010-06-08 16:52:24 +0000410 lldb::InputReaderAction notification,
411 const char *bytes,
412 size_t bytes_len
413)
414{
Greg Clayton63094e02010-06-23 01:19:29 +0000415 FILE *out_fh = reader.GetDebugger().GetOutputFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000416
417 switch (notification)
418 {
419 case eInputReaderActivate:
420 if (out_fh)
421 {
422 ::fprintf (out_fh, "%s\n", g_reader_instructions);
Greg Clayton63094e02010-06-23 01:19:29 +0000423 if (reader.GetPrompt())
424 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000425 }
426 break;
427
428 case eInputReaderDeactivate:
429 break;
430
431 case eInputReaderReactivate:
Greg Clayton63094e02010-06-23 01:19:29 +0000432 if (out_fh && reader.GetPrompt())
433 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000434 break;
435
436 case eInputReaderGotToken:
437 if (bytes && bytes_len && baton)
438 {
439 BreakpointOptions *bp_options = (BreakpointOptions *) baton;
440 if (bp_options)
441 {
442 Baton *bp_options_baton = bp_options->GetBaton();
443 if (bp_options_baton)
444 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
445 }
446 }
Greg Clayton63094e02010-06-23 01:19:29 +0000447 if (out_fh && !reader.IsDone() && reader.GetPrompt())
448 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000449 break;
450
451 case eInputReaderDone:
452 break;
453 }
454
455 return bytes_len;
456}
457
458
459//-------------------------------------------------------------------------
460// CommandObjectBreakpointCommandRemove
461//-------------------------------------------------------------------------
462
463CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove () :
464 CommandObject ("remove",
465 "Remove the set of commands from a breakpoint.",
466 "breakpoint command remove <breakpoint-id>")
467{
468}
469
470CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove ()
471{
472}
473
474bool
Greg Clayton63094e02010-06-23 01:19:29 +0000475CommandObjectBreakpointCommandRemove::Execute
476(
477 CommandInterpreter &interpreter,
478 Args& command,
479 CommandReturnObject &result
480)
Chris Lattner24943d22010-06-08 16:52:24 +0000481{
Jim Inghamc8332952010-08-26 21:32:51 +0000482 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000483
484 if (target == NULL)
485 {
486 result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands");
487 result.SetStatus (eReturnStatusFailed);
488 return false;
489 }
490
491 const BreakpointList &breakpoints = target->GetBreakpointList();
492 size_t num_breakpoints = breakpoints.GetSize();
493
494 if (num_breakpoints == 0)
495 {
496 result.AppendError ("No breakpoints exist to have commands removed");
497 result.SetStatus (eReturnStatusFailed);
498 return false;
499 }
500
501 if (command.GetArgumentCount() == 0)
502 {
503 result.AppendError ("No breakpoint specified from which to remove the commands");
504 result.SetStatus (eReturnStatusFailed);
505 return false;
506 }
507
508 BreakpointIDList valid_bp_ids;
509 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
510
511 if (result.Succeeded())
512 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000513 const size_t count = valid_bp_ids.GetSize();
514 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000515 {
516 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
517 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
518 {
519 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
520 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
521 {
522 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
523 if (bp_loc_sp)
524 bp_loc_sp->ClearCallback();
525 else
526 {
527 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
528 cur_bp_id.GetBreakpointID(),
529 cur_bp_id.GetLocationID());
530 result.SetStatus (eReturnStatusFailed);
531 return false;
532 }
533 }
534 else
535 {
536 bp->ClearCallback();
537 }
538 }
539 }
540 }
541 return result.Succeeded();
542}
543
544
545//-------------------------------------------------------------------------
546// CommandObjectBreakpointCommandList
547//-------------------------------------------------------------------------
548
549CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList () :
550 CommandObject ("List",
551 "List the script or set of commands to be executed when the breakpoint is hit.",
552 "breakpoint command list <breakpoint-id>")
553{
554}
555
556CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList ()
557{
558}
559
560bool
Greg Clayton63094e02010-06-23 01:19:29 +0000561CommandObjectBreakpointCommandList::Execute
562(
563 CommandInterpreter &interpreter,
564 Args& command,
565 CommandReturnObject &result
566)
Chris Lattner24943d22010-06-08 16:52:24 +0000567{
Jim Inghamc8332952010-08-26 21:32:51 +0000568 Target *target = interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000569
570 if (target == NULL)
571 {
572 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
573 result.SetStatus (eReturnStatusFailed);
574 return false;
575 }
576
577 const BreakpointList &breakpoints = target->GetBreakpointList();
578 size_t num_breakpoints = breakpoints.GetSize();
579
580 if (num_breakpoints == 0)
581 {
582 result.AppendError ("No breakpoints exist for which to list commands");
583 result.SetStatus (eReturnStatusFailed);
584 return false;
585 }
586
587 if (command.GetArgumentCount() == 0)
588 {
589 result.AppendError ("No breakpoint specified for which to list the commands");
590 result.SetStatus (eReturnStatusFailed);
591 return false;
592 }
593
594 BreakpointIDList valid_bp_ids;
595 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
596
597 if (result.Succeeded())
598 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000599 const size_t count = valid_bp_ids.GetSize();
600 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000601 {
602 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
603 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
604 {
605 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
606
607 if (bp)
608 {
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000609 const BreakpointOptions *bp_options = NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000610 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
611 {
612 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
613 if (bp_loc_sp)
Jim Ingham9c6898b2010-06-22 21:12:54 +0000614 bp_options = bp_loc_sp->GetOptionsNoCreate();
Chris Lattner24943d22010-06-08 16:52:24 +0000615 else
616 {
617 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
618 cur_bp_id.GetBreakpointID(),
619 cur_bp_id.GetLocationID());
620 result.SetStatus (eReturnStatusFailed);
621 return false;
622 }
623 }
624 else
625 {
626 bp_options = bp->GetOptions();
627 }
628
629 if (bp_options)
630 {
631 StreamString id_str;
632 BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000633 const Baton *baton = bp_options->GetBaton();
Chris Lattner24943d22010-06-08 16:52:24 +0000634 if (baton)
635 {
636 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
637 result.GetOutputStream().IndentMore ();
638 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
639 result.GetOutputStream().IndentLess ();
640 }
641 else
642 {
643 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData());
644 }
645 }
646 result.SetStatus (eReturnStatusSuccessFinishResult);
647 }
648 else
649 {
650 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
651 result.SetStatus (eReturnStatusFailed);
652 }
653
654 }
655 }
656 }
657
658 return result.Succeeded();
659}
660
661//-------------------------------------------------------------------------
662// CommandObjectBreakpointCommand
663//-------------------------------------------------------------------------
664
Greg Clayton63094e02010-06-23 01:19:29 +0000665CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
Chris Lattner24943d22010-06-08 16:52:24 +0000666 CommandObjectMultiword ("command",
667 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
668 "command <sub-command> [<sub-command-options>] <breakpoint-id>")
669{
670 bool status;
671 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd ());
672 CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove ());
673 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList ());
674
675 add_command_object->SetCommandName ("breakpoint command add");
676 remove_command_object->SetCommandName ("breakpoint command remove");
677 list_command_object->SetCommandName ("breakpoint command list");
678
Greg Clayton63094e02010-06-23 01:19:29 +0000679 status = LoadSubCommand (interpreter, "add", add_command_object);
680 status = LoadSubCommand (interpreter, "remove", remove_command_object);
681 status = LoadSubCommand (interpreter, "list", list_command_object);
Chris Lattner24943d22010-06-08 16:52:24 +0000682}
683
684
685CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
686{
687}
688
689bool
690CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction
691(
692 void *baton,
693 StoppointCallbackContext *context,
694 lldb::user_id_t break_id,
695 lldb::user_id_t break_loc_id
696)
697{
698 bool ret_value = true;
699 if (baton == NULL)
700 return true;
701
702
703 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
704 StringList &commands = data->user_source;
705
706 if (commands.GetSize() > 0)
707 {
708 uint32_t num_commands = commands.GetSize();
Chris Lattner24943d22010-06-08 16:52:24 +0000709 CommandReturnObject result;
Greg Clayton63094e02010-06-23 01:19:29 +0000710 if (context->exe_ctx.target)
Chris Lattner24943d22010-06-08 16:52:24 +0000711 {
Greg Clayton63094e02010-06-23 01:19:29 +0000712
713 Debugger &debugger = context->exe_ctx.target->GetDebugger();
714 CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
715
716 FILE *out_fh = debugger.GetOutputFileHandle();
717 FILE *err_fh = debugger.GetErrorFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000718
Greg Clayton63094e02010-06-23 01:19:29 +0000719 uint32_t i;
720 for (i = 0; i < num_commands; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000721 {
Greg Clayton63094e02010-06-23 01:19:29 +0000722
723 // First time through we use the context from the stoppoint, after that we use whatever
724 // has been set by the previous command.
725
726 if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &context->exe_ctx))
727 break;
728
729 // FIXME: This isn't really the right way to do this. We should be able to peek at the public
730 // to see if there is any new events, but that is racey, since the internal process thread has to run and
731 // deliver the event to the public queue before a run will show up. So for now we check
732 // the internal thread state.
733
734 lldb::StateType internal_state = context->exe_ctx.process->GetPrivateState();
735 if (internal_state != eStateStopped)
Chris Lattner24943d22010-06-08 16:52:24 +0000736 {
Greg Clayton63094e02010-06-23 01:19:29 +0000737 if (i < num_commands - 1)
738 {
739 if (out_fh)
740 ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s."
741 " last command: \"%s\"\n", StateAsCString(internal_state),
742 commands.GetStringAtIndex(i));
743 }
744 break;
Chris Lattner24943d22010-06-08 16:52:24 +0000745 }
Greg Clayton63094e02010-06-23 01:19:29 +0000746
747 if (out_fh)
748 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
749 if (err_fh)
750 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
751 result.Clear();
752 result.SetStatus (eReturnStatusSuccessFinishNoResult);
Chris Lattner24943d22010-06-08 16:52:24 +0000753 }
Chris Lattner24943d22010-06-08 16:52:24 +0000754
Greg Clayton63094e02010-06-23 01:19:29 +0000755 if (err_fh && !result.Succeeded() && i < num_commands)
756 ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i));
757
Chris Lattner24943d22010-06-08 16:52:24 +0000758 if (out_fh)
759 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
Greg Clayton63094e02010-06-23 01:19:29 +0000760
Chris Lattner24943d22010-06-08 16:52:24 +0000761 if (err_fh)
Greg Clayton63094e02010-06-23 01:19:29 +0000762 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
Chris Lattner24943d22010-06-08 16:52:24 +0000763 }
Chris Lattner24943d22010-06-08 16:52:24 +0000764 }
765 return ret_value;
766}
767