blob: a3c62ebd394189bae24d24db591f78ceb1162a34 [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{
Greg Claytonfe424a92010-09-18 03:37:20 +000051 { LLDB_OPT_SET_ALL, false, "one-liner", 'o', required_argument, NULL, 0, "<one-liner>",
Johnny Chenb81ed0d2010-09-11 00:18:09 +000052 "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
Greg Clayton238c0a12010-09-18 01:14:36 +0000128CommandObjectBreakpointCommandAdd::CommandObjectBreakpointCommandAdd (CommandInterpreter &interpreter) :
129 CommandObject (interpreter,
130 "add",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000131 "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.",
Chris Lattner24943d22010-06-08 16:52:24 +0000132 "breakpoint command add <cmd-options> <breakpoint-id>")
133{
134 SetHelpLong (
135"\nGeneral information about entering breakpoint commands \n\
136------------------------------------------------------ \n\
137 \n\
138This command will cause you to be prompted to enter the command or set \n\
139of commands you wish to be executed when the specified breakpoint is \n\
140hit. You will be told to enter your command(s), and will see a '> ' \n\
141prompt. Because you can enter one or many commands to be executed when \n\
142a breakpoint is hit, you will continue to be prompted after each \n\
143new-line that you enter, until you enter the word 'DONE', which will \n\
144cause the commands you have entered to be stored with the breakpoint \n\
145and executed when the breakpoint is hit. \n\
146 \n\
147Syntax checking is not necessarily done when breakpoint commands are \n\
148entered. An improperly written breakpoint command will attempt to get \n\
149executed when the breakpoint gets hit, and usually silently fail. If \n\
150your breakpoint command does not appear to be getting executed, go \n\
151back and check your syntax. \n\
152 \n\
153 \n\
154Special information about PYTHON breakpoint commands \n\
155---------------------------------------------------- \n\
156 \n\
157You may enter either one line of Python or multiple lines of Python \n\
158(including defining whole functions, if desired). If you enter a \n\
159single line of Python, that will be passed to the Python interpreter \n\
160'as is' when the breakpoint gets hit. If you enter function \n\
161definitions, they will be passed to the Python interpreter as soon as \n\
162you finish entering the breakpoint command, and they can be called \n\
163later (don't forget to add calls to them, if you want them called when \n\
164the breakpoint is hit). If you enter multiple lines of Python that \n\
165are not function definitions, they will be collected into a new, \n\
166automatically generated Python function, and a call to the newly \n\
167generated function will be attached to the breakpoint. Important \n\
168Note: Because loose Python code gets collected into functions, if you \n\
169want to access global variables in the 'loose' code, you need to \n\
170specify that they are global, using the 'global' keyword. Be sure to \n\
171use correct Python syntax, including indentation, when entering Python \n\
172breakpoint commands. \n\
173 \n\
174Example Python one-line breakpoint command: \n\
175 \n\
176(lldb) breakpoint command add -p 1 \n\
177Enter your Python command(s). Type 'DONE' to end. \n\
178> print \"Hit this breakpoint!\" \n\
179> DONE \n\
180 \n\
Johnny Chen4c1b2182010-09-10 19:34:12 +0000181As a convenience, this also works for a short Python one-liner: \n\
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000182(lldb) breakpoint command add -p 1 -o \"import time; print time.asctime()\" \n\
Johnny Chen4c1b2182010-09-10 19:34:12 +0000183(lldb) run \n\
184Launching '.../a.out' (x86_64) \n\
185(lldb) Fri Sep 10 12:17:45 2010 \n\
186Process 21778 Stopped \n\
187* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread \n\
188 36 \n\
189 37 int c(int val)\n\
190 38 {\n\
191 39 -> return val + 3;\n\
192 40 }\n\
193 41 \n\
194 42 int main (int argc, char const *argv[])\n\
195(lldb) \n\
196 \n\
Chris Lattner24943d22010-06-08 16:52:24 +0000197Example multiple line Python breakpoint command, using function definition: \n\
198 \n\
199(lldb) breakpoint command add -p 1 \n\
200Enter your Python command(s). Type 'DONE' to end. \n\
201> def breakpoint_output (bp_no): \n\
202> out_string = \"Hit breakpoint number \" + repr (bp_no) \n\
203> print out_string \n\
204> return True \n\
205> breakpoint_output (1) \n\
206> DONE \n\
207 \n\
208 \n\
209Example multiple line Python breakpoint command, using 'loose' Python: \n\
210 \n\
211(lldb) breakpoint command add -p 1 \n\
212Enter your Python command(s). Type 'DONE' to end. \n\
213> global bp_count \n\
214> bp_count = bp_count + 1 \n\
215> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\" \n\
216> DONE \n\
217 \n\
218In this case, since there is a reference to a global variable, \n\
219'bp_count', you will also need to make sure 'bp_count' exists and is \n\
220initialized: \n\
221 \n\
222(lldb) script \n\
223>>> bp_count = 0 \n\
224>>> quit() \n\
225 \n\
226(lldb) \n\
227 \n\
Caroline Ticeabb507a2010-09-08 21:06:11 +0000228Special information about debugger command breakpoint commands \n\
229-------------------------------------------------------------- \n\
Chris Lattner24943d22010-06-08 16:52:24 +0000230 \n\
231You may enter any debugger command, exactly as you would at the \n\
232debugger prompt. You may enter as many debugger commands as you like, \n\
233but do NOT enter more than one command per line. \n" );
234}
235
236CommandObjectBreakpointCommandAdd::~CommandObjectBreakpointCommandAdd ()
237{
238}
239
240bool
241CommandObjectBreakpointCommandAdd::Execute
242(
243 Args& command,
Chris Lattner24943d22010-06-08 16:52:24 +0000244 CommandReturnObject &result
245)
246{
Greg Clayton238c0a12010-09-18 01:14:36 +0000247 Target *target = m_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)
Greg Clayton238c0a12010-09-18 01:14:36 +0000310 m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
311 m_options.m_one_liner.c_str());
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000312 else
Greg Clayton238c0a12010-09-18 01:14:36 +0000313 m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options,
314 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000315 }
316 else
317 {
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000318 // Special handling for one-liner specified inline.
319 if (m_options.m_use_one_liner)
Greg Clayton238c0a12010-09-18 01:14:36 +0000320 SetBreakpointCommandCallback (bp_options,
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000321 m_options.m_one_liner.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000322 else
Greg Clayton238c0a12010-09-18 01:14:36 +0000323 CollectDataForBreakpointCommandCallback (bp_options,
Greg Claytonbef15832010-07-14 00:18:15 +0000324 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000325 }
326 }
327 }
328 }
329
330 return result.Succeeded();
331}
332
333Options *
334CommandObjectBreakpointCommandAdd::GetOptions ()
335{
336 return &m_options;
337}
338
339const char *g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
340
341void
342CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback
343(
344 BreakpointOptions *bp_options,
345 CommandReturnObject &result
346)
347{
Greg Clayton238c0a12010-09-18 01:14:36 +0000348 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
Chris Lattner24943d22010-06-08 16:52:24 +0000349 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
350 if (reader_sp && data_ap.get())
351 {
352 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
353 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
354
355 Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
356 bp_options, // baton
357 eInputReaderGranularityLine, // token size, to pass to callback function
358 "DONE", // end token
359 "> ", // prompt
360 true)); // echo input
361 if (err.Success())
362 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000363 m_interpreter.GetDebugger().PushInputReader (reader_sp);
Chris Lattner24943d22010-06-08 16:52:24 +0000364 result.SetStatus (eReturnStatusSuccessFinishNoResult);
365 }
366 else
367 {
368 result.AppendError (err.AsCString());
369 result.SetStatus (eReturnStatusFailed);
370 }
371 }
372 else
373 {
374 result.AppendError("out of memory");
375 result.SetStatus (eReturnStatusFailed);
376 }
377
378}
379
Johnny Chen3e0571b2010-09-11 00:23:59 +0000380// Set a one-liner as the callback for the breakpoint.
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000381void
Greg Clayton238c0a12010-09-18 01:14:36 +0000382CommandObjectBreakpointCommandAdd::SetBreakpointCommandCallback (BreakpointOptions *bp_options,
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000383 const char *oneliner)
384{
385 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
386
387 // It's necessary to set both user_source and script_source to the oneliner.
388 // The former is used to generate callback description (as in breakpoint command list)
389 // while the latter is used for Python to interpret during the actual callback.
390 data_ap->user_source.AppendString (oneliner);
391 data_ap->script_source.AppendString (oneliner);
392
393 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
394 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
395
396 return;
397}
398
Chris Lattner24943d22010-06-08 16:52:24 +0000399size_t
400CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback
401(
402 void *baton,
Greg Clayton63094e02010-06-23 01:19:29 +0000403 InputReader &reader,
Chris Lattner24943d22010-06-08 16:52:24 +0000404 lldb::InputReaderAction notification,
405 const char *bytes,
406 size_t bytes_len
407)
408{
Greg Clayton63094e02010-06-23 01:19:29 +0000409 FILE *out_fh = reader.GetDebugger().GetOutputFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000410
411 switch (notification)
412 {
413 case eInputReaderActivate:
414 if (out_fh)
415 {
416 ::fprintf (out_fh, "%s\n", g_reader_instructions);
Greg Clayton63094e02010-06-23 01:19:29 +0000417 if (reader.GetPrompt())
418 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000419 }
420 break;
421
422 case eInputReaderDeactivate:
423 break;
424
425 case eInputReaderReactivate:
Greg Clayton63094e02010-06-23 01:19:29 +0000426 if (out_fh && reader.GetPrompt())
427 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000428 break;
429
430 case eInputReaderGotToken:
431 if (bytes && bytes_len && baton)
432 {
433 BreakpointOptions *bp_options = (BreakpointOptions *) baton;
434 if (bp_options)
435 {
436 Baton *bp_options_baton = bp_options->GetBaton();
437 if (bp_options_baton)
438 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
439 }
440 }
Greg Clayton63094e02010-06-23 01:19:29 +0000441 if (out_fh && !reader.IsDone() && reader.GetPrompt())
442 ::fprintf (out_fh, "%s", reader.GetPrompt());
Chris Lattner24943d22010-06-08 16:52:24 +0000443 break;
444
445 case eInputReaderDone:
446 break;
447 }
448
449 return bytes_len;
450}
451
452
453//-------------------------------------------------------------------------
454// CommandObjectBreakpointCommandRemove
455//-------------------------------------------------------------------------
456
Greg Clayton238c0a12010-09-18 01:14:36 +0000457CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove (CommandInterpreter &interpreter) :
458 CommandObject (interpreter,
459 "remove",
Chris Lattner24943d22010-06-08 16:52:24 +0000460 "Remove the set of commands from a breakpoint.",
461 "breakpoint command remove <breakpoint-id>")
462{
463}
464
465CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove ()
466{
467}
468
469bool
Greg Clayton63094e02010-06-23 01:19:29 +0000470CommandObjectBreakpointCommandRemove::Execute
471(
Greg Clayton63094e02010-06-23 01:19:29 +0000472 Args& command,
473 CommandReturnObject &result
474)
Chris Lattner24943d22010-06-08 16:52:24 +0000475{
Greg Clayton238c0a12010-09-18 01:14:36 +0000476 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000477
478 if (target == NULL)
479 {
480 result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands");
481 result.SetStatus (eReturnStatusFailed);
482 return false;
483 }
484
485 const BreakpointList &breakpoints = target->GetBreakpointList();
486 size_t num_breakpoints = breakpoints.GetSize();
487
488 if (num_breakpoints == 0)
489 {
490 result.AppendError ("No breakpoints exist to have commands removed");
491 result.SetStatus (eReturnStatusFailed);
492 return false;
493 }
494
495 if (command.GetArgumentCount() == 0)
496 {
497 result.AppendError ("No breakpoint specified from which to remove the commands");
498 result.SetStatus (eReturnStatusFailed);
499 return false;
500 }
501
502 BreakpointIDList valid_bp_ids;
503 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
504
505 if (result.Succeeded())
506 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000507 const size_t count = valid_bp_ids.GetSize();
508 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000509 {
510 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
511 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
512 {
513 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
514 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
515 {
516 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
517 if (bp_loc_sp)
518 bp_loc_sp->ClearCallback();
519 else
520 {
521 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
522 cur_bp_id.GetBreakpointID(),
523 cur_bp_id.GetLocationID());
524 result.SetStatus (eReturnStatusFailed);
525 return false;
526 }
527 }
528 else
529 {
530 bp->ClearCallback();
531 }
532 }
533 }
534 }
535 return result.Succeeded();
536}
537
538
539//-------------------------------------------------------------------------
540// CommandObjectBreakpointCommandList
541//-------------------------------------------------------------------------
542
Greg Clayton238c0a12010-09-18 01:14:36 +0000543CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) :
544 CommandObject (interpreter,
545 "list",
Chris Lattner24943d22010-06-08 16:52:24 +0000546 "List the script or set of commands to be executed when the breakpoint is hit.",
547 "breakpoint command list <breakpoint-id>")
548{
549}
550
551CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList ()
552{
553}
554
555bool
Greg Clayton63094e02010-06-23 01:19:29 +0000556CommandObjectBreakpointCommandList::Execute
557(
Greg Clayton63094e02010-06-23 01:19:29 +0000558 Args& command,
559 CommandReturnObject &result
560)
Chris Lattner24943d22010-06-08 16:52:24 +0000561{
Greg Clayton238c0a12010-09-18 01:14:36 +0000562 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000563
564 if (target == NULL)
565 {
566 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
567 result.SetStatus (eReturnStatusFailed);
568 return false;
569 }
570
571 const BreakpointList &breakpoints = target->GetBreakpointList();
572 size_t num_breakpoints = breakpoints.GetSize();
573
574 if (num_breakpoints == 0)
575 {
576 result.AppendError ("No breakpoints exist for which to list commands");
577 result.SetStatus (eReturnStatusFailed);
578 return false;
579 }
580
581 if (command.GetArgumentCount() == 0)
582 {
583 result.AppendError ("No breakpoint specified for which to list the commands");
584 result.SetStatus (eReturnStatusFailed);
585 return false;
586 }
587
588 BreakpointIDList valid_bp_ids;
589 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
590
591 if (result.Succeeded())
592 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000593 const size_t count = valid_bp_ids.GetSize();
594 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000595 {
596 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
597 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
598 {
599 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
600
601 if (bp)
602 {
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000603 const BreakpointOptions *bp_options = NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000604 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
605 {
606 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
607 if (bp_loc_sp)
Jim Ingham9c6898b2010-06-22 21:12:54 +0000608 bp_options = bp_loc_sp->GetOptionsNoCreate();
Chris Lattner24943d22010-06-08 16:52:24 +0000609 else
610 {
611 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
612 cur_bp_id.GetBreakpointID(),
613 cur_bp_id.GetLocationID());
614 result.SetStatus (eReturnStatusFailed);
615 return false;
616 }
617 }
618 else
619 {
620 bp_options = bp->GetOptions();
621 }
622
623 if (bp_options)
624 {
625 StreamString id_str;
626 BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000627 const Baton *baton = bp_options->GetBaton();
Chris Lattner24943d22010-06-08 16:52:24 +0000628 if (baton)
629 {
630 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
631 result.GetOutputStream().IndentMore ();
632 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
633 result.GetOutputStream().IndentLess ();
634 }
635 else
636 {
637 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData());
638 }
639 }
640 result.SetStatus (eReturnStatusSuccessFinishResult);
641 }
642 else
643 {
644 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
645 result.SetStatus (eReturnStatusFailed);
646 }
647
648 }
649 }
650 }
651
652 return result.Succeeded();
653}
654
655//-------------------------------------------------------------------------
656// CommandObjectBreakpointCommand
657//-------------------------------------------------------------------------
658
Greg Clayton63094e02010-06-23 01:19:29 +0000659CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +0000660 CommandObjectMultiword (interpreter,
661 "command",
Chris Lattner24943d22010-06-08 16:52:24 +0000662 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
663 "command <sub-command> [<sub-command-options>] <breakpoint-id>")
664{
665 bool status;
Greg Clayton238c0a12010-09-18 01:14:36 +0000666 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
667 CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove (interpreter));
668 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter));
Chris Lattner24943d22010-06-08 16:52:24 +0000669
670 add_command_object->SetCommandName ("breakpoint command add");
671 remove_command_object->SetCommandName ("breakpoint command remove");
672 list_command_object->SetCommandName ("breakpoint command list");
673
Greg Clayton238c0a12010-09-18 01:14:36 +0000674 status = LoadSubCommand ("add", add_command_object);
675 status = LoadSubCommand ("remove", remove_command_object);
676 status = LoadSubCommand ("list", list_command_object);
Chris Lattner24943d22010-06-08 16:52:24 +0000677}
678
679
680CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
681{
682}
683
684bool
685CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction
686(
687 void *baton,
688 StoppointCallbackContext *context,
689 lldb::user_id_t break_id,
690 lldb::user_id_t break_loc_id
691)
692{
693 bool ret_value = true;
694 if (baton == NULL)
695 return true;
696
697
698 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
699 StringList &commands = data->user_source;
700
701 if (commands.GetSize() > 0)
702 {
703 uint32_t num_commands = commands.GetSize();
Chris Lattner24943d22010-06-08 16:52:24 +0000704 CommandReturnObject result;
Greg Clayton63094e02010-06-23 01:19:29 +0000705 if (context->exe_ctx.target)
Chris Lattner24943d22010-06-08 16:52:24 +0000706 {
Greg Clayton63094e02010-06-23 01:19:29 +0000707
708 Debugger &debugger = context->exe_ctx.target->GetDebugger();
709 CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
710
711 FILE *out_fh = debugger.GetOutputFileHandle();
712 FILE *err_fh = debugger.GetErrorFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000713
Greg Clayton63094e02010-06-23 01:19:29 +0000714 uint32_t i;
715 for (i = 0; i < num_commands; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000716 {
Greg Clayton63094e02010-06-23 01:19:29 +0000717
718 // First time through we use the context from the stoppoint, after that we use whatever
719 // has been set by the previous command.
720
721 if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &context->exe_ctx))
722 break;
723
724 // FIXME: This isn't really the right way to do this. We should be able to peek at the public
725 // to see if there is any new events, but that is racey, since the internal process thread has to run and
726 // deliver the event to the public queue before a run will show up. So for now we check
727 // the internal thread state.
728
729 lldb::StateType internal_state = context->exe_ctx.process->GetPrivateState();
730 if (internal_state != eStateStopped)
Chris Lattner24943d22010-06-08 16:52:24 +0000731 {
Greg Clayton63094e02010-06-23 01:19:29 +0000732 if (i < num_commands - 1)
733 {
734 if (out_fh)
735 ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s."
736 " last command: \"%s\"\n", StateAsCString(internal_state),
737 commands.GetStringAtIndex(i));
738 }
739 break;
Chris Lattner24943d22010-06-08 16:52:24 +0000740 }
Greg Clayton63094e02010-06-23 01:19:29 +0000741
742 if (out_fh)
743 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
744 if (err_fh)
745 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
746 result.Clear();
747 result.SetStatus (eReturnStatusSuccessFinishNoResult);
Chris Lattner24943d22010-06-08 16:52:24 +0000748 }
Chris Lattner24943d22010-06-08 16:52:24 +0000749
Greg Clayton63094e02010-06-23 01:19:29 +0000750 if (err_fh && !result.Succeeded() && i < num_commands)
751 ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i));
752
Chris Lattner24943d22010-06-08 16:52:24 +0000753 if (out_fh)
754 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
Greg Clayton63094e02010-06-23 01:19:29 +0000755
Chris Lattner24943d22010-06-08 16:52:24 +0000756 if (err_fh)
Greg Clayton63094e02010-06-23 01:19:29 +0000757 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
Chris Lattner24943d22010-06-08 16:52:24 +0000758 }
Chris Lattner24943d22010-06-08 16:52:24 +0000759 }
760 return ret_value;
761}
762