blob: aad7158d28f8a4530ea72c3cd5f2f502b7ba74ec [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{
Caroline Tice4d6675c2010-10-01 19:59:14 +000051 { LLDB_OPT_SET_ALL, false, "one-liner", 'o', required_argument, NULL, NULL, eArgTypeOneLiner,
Caroline Tice8bb61f02010-09-21 23:25:40 +000052 "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." },
Johnny Chenb81ed0d2010-09-11 00:18:09 +000053
Caroline Tice4d6675c2010-10-01 19:59:14 +000054 { LLDB_OPT_SET_1, true, "script", 's', no_argument, NULL, NULL, eArgTypeNone,
Chris Lattner24943d22010-06-08 16:52:24 +000055 "Write the breakpoint command script in the default scripting language."},
56
Caroline Tice4d6675c2010-10-01 19:59:14 +000057 { LLDB_OPT_SET_2, true, "python", 'p', no_argument, NULL, NULL, eArgTypeNone,
Chris Lattner24943d22010-06-08 16:52:24 +000058 "Write the breakpoint command script in the Python scripting language."},
Caroline Tice4d6675c2010-10-01 19:59:14 +000059
60 { LLDB_OPT_SET_3, true, "commands", 'c', no_argument, NULL, NULL, eArgTypeNone,
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
Caroline Tice4d6675c2010-10-01 19:59:14 +000063 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
Chris Lattner24943d22010-06-08 16:52:24 +000064};
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.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000132 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000133{
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 Ticeb447e842010-09-21 19:25:28 +0000228 \n\
229Final Note: If you get a warning that no breakpoint command was generated, \n\
230but you did not get any syntax errors, you probably forgot to add a call \n\
231to your functions. \n\
232 \n\
Caroline Ticeabb507a2010-09-08 21:06:11 +0000233Special information about debugger command breakpoint commands \n\
234-------------------------------------------------------------- \n\
Chris Lattner24943d22010-06-08 16:52:24 +0000235 \n\
236You may enter any debugger command, exactly as you would at the \n\
237debugger prompt. You may enter as many debugger commands as you like, \n\
238but do NOT enter more than one command per line. \n" );
Caroline Tice43b014a2010-10-04 22:28:36 +0000239
240
241 CommandArgumentEntry arg;
242 CommandArgumentData bp_id_arg;
243
244 // Define the first (and only) variant of this arg.
245 bp_id_arg.arg_type = eArgTypeBreakpointID;
246 bp_id_arg.arg_repetition = eArgRepeatPlain;
247
248 // There is only one variant this argument could be; put it into the argument entry.
249 arg.push_back (bp_id_arg);
250
251 // Push the data for the first argument into the m_arguments vector.
252 m_arguments.push_back (arg);
Chris Lattner24943d22010-06-08 16:52:24 +0000253}
254
255CommandObjectBreakpointCommandAdd::~CommandObjectBreakpointCommandAdd ()
256{
257}
258
259bool
260CommandObjectBreakpointCommandAdd::Execute
261(
262 Args& command,
Chris Lattner24943d22010-06-08 16:52:24 +0000263 CommandReturnObject &result
264)
265{
Greg Clayton238c0a12010-09-18 01:14:36 +0000266 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000267
268 if (target == NULL)
269 {
270 result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands");
271 result.SetStatus (eReturnStatusFailed);
272 return false;
273 }
274
275 const BreakpointList &breakpoints = target->GetBreakpointList();
276 size_t num_breakpoints = breakpoints.GetSize();
277
278 if (num_breakpoints == 0)
279 {
280 result.AppendError ("No breakpoints exist to have commands added");
281 result.SetStatus (eReturnStatusFailed);
282 return false;
283 }
284
285 if (command.GetArgumentCount() == 0)
286 {
287 result.AppendError ("No breakpoint specified to which to add the commands");
288 result.SetStatus (eReturnStatusFailed);
289 return false;
290 }
291
292 BreakpointIDList valid_bp_ids;
293 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
294
295 if (result.Succeeded())
296 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000297 const size_t count = valid_bp_ids.GetSize();
298 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000299 {
300 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
301 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
302 {
303 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000304 BreakpointOptions *bp_options = NULL;
305 if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
306 {
307 // This breakpoint does not have an associated location.
308 bp_options = bp->GetOptions();
309 }
310 else
Chris Lattner24943d22010-06-08 16:52:24 +0000311 {
312 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000313 // This breakpoint does have an associated location.
314 // Get its breakpoint options.
Chris Lattner24943d22010-06-08 16:52:24 +0000315 if (bp_loc_sp)
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000316 bp_options = bp_loc_sp->GetLocationOptions();
317 }
318
319 // Skip this breakpoiont if bp_options is not good.
320 if (bp_options == NULL) continue;
321
322 // If we are using script language, get the script interpreter
323 // in order to set or collect command callback. Otherwise, call
324 // the methods associated with this object.
325 if (m_options.m_use_script_language)
326 {
327 // Special handling for one-liner specified inline.
328 if (m_options.m_use_one_liner)
Greg Clayton238c0a12010-09-18 01:14:36 +0000329 m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
330 m_options.m_one_liner.c_str());
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000331 else
Greg Clayton238c0a12010-09-18 01:14:36 +0000332 m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options,
333 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000334 }
335 else
336 {
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000337 // Special handling for one-liner specified inline.
338 if (m_options.m_use_one_liner)
Greg Clayton238c0a12010-09-18 01:14:36 +0000339 SetBreakpointCommandCallback (bp_options,
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000340 m_options.m_one_liner.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000341 else
Greg Clayton238c0a12010-09-18 01:14:36 +0000342 CollectDataForBreakpointCommandCallback (bp_options,
Greg Claytonbef15832010-07-14 00:18:15 +0000343 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000344 }
345 }
346 }
347 }
348
349 return result.Succeeded();
350}
351
352Options *
353CommandObjectBreakpointCommandAdd::GetOptions ()
354{
355 return &m_options;
356}
357
358const char *g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
359
360void
361CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback
362(
363 BreakpointOptions *bp_options,
364 CommandReturnObject &result
365)
366{
Greg Clayton238c0a12010-09-18 01:14:36 +0000367 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
Chris Lattner24943d22010-06-08 16:52:24 +0000368 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
369 if (reader_sp && data_ap.get())
370 {
371 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
372 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
373
374 Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
375 bp_options, // baton
376 eInputReaderGranularityLine, // token size, to pass to callback function
377 "DONE", // end token
378 "> ", // prompt
379 true)); // echo input
380 if (err.Success())
381 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000382 m_interpreter.GetDebugger().PushInputReader (reader_sp);
Chris Lattner24943d22010-06-08 16:52:24 +0000383 result.SetStatus (eReturnStatusSuccessFinishNoResult);
384 }
385 else
386 {
387 result.AppendError (err.AsCString());
388 result.SetStatus (eReturnStatusFailed);
389 }
390 }
391 else
392 {
393 result.AppendError("out of memory");
394 result.SetStatus (eReturnStatusFailed);
395 }
396
397}
398
Johnny Chen3e0571b2010-09-11 00:23:59 +0000399// Set a one-liner as the callback for the breakpoint.
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000400void
Greg Clayton238c0a12010-09-18 01:14:36 +0000401CommandObjectBreakpointCommandAdd::SetBreakpointCommandCallback (BreakpointOptions *bp_options,
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000402 const char *oneliner)
403{
404 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
405
406 // It's necessary to set both user_source and script_source to the oneliner.
407 // The former is used to generate callback description (as in breakpoint command list)
408 // while the latter is used for Python to interpret during the actual callback.
409 data_ap->user_source.AppendString (oneliner);
410 data_ap->script_source.AppendString (oneliner);
411
412 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
413 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
414
415 return;
416}
417
Chris Lattner24943d22010-06-08 16:52:24 +0000418size_t
419CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback
420(
421 void *baton,
Greg Clayton63094e02010-06-23 01:19:29 +0000422 InputReader &reader,
Chris Lattner24943d22010-06-08 16:52:24 +0000423 lldb::InputReaderAction notification,
424 const char *bytes,
425 size_t bytes_len
426)
427{
Greg Clayton63094e02010-06-23 01:19:29 +0000428 FILE *out_fh = reader.GetDebugger().GetOutputFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000429
430 switch (notification)
431 {
432 case eInputReaderActivate:
433 if (out_fh)
434 {
435 ::fprintf (out_fh, "%s\n", g_reader_instructions);
Greg Clayton63094e02010-06-23 01:19:29 +0000436 if (reader.GetPrompt())
437 ::fprintf (out_fh, "%s", reader.GetPrompt());
Caroline Ticef81b4c52010-10-27 18:34:42 +0000438 ::fflush (out_fh);
Chris Lattner24943d22010-06-08 16:52:24 +0000439 }
440 break;
441
442 case eInputReaderDeactivate:
443 break;
444
445 case eInputReaderReactivate:
Greg Clayton63094e02010-06-23 01:19:29 +0000446 if (out_fh && reader.GetPrompt())
Caroline Ticef81b4c52010-10-27 18:34:42 +0000447 {
Greg Clayton63094e02010-06-23 01:19:29 +0000448 ::fprintf (out_fh, "%s", reader.GetPrompt());
Caroline Ticef81b4c52010-10-27 18:34:42 +0000449 ::fflush (out_fh);
450 }
Chris Lattner24943d22010-06-08 16:52:24 +0000451 break;
452
453 case eInputReaderGotToken:
454 if (bytes && bytes_len && baton)
455 {
456 BreakpointOptions *bp_options = (BreakpointOptions *) baton;
457 if (bp_options)
458 {
459 Baton *bp_options_baton = bp_options->GetBaton();
460 if (bp_options_baton)
461 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
462 }
463 }
Greg Clayton63094e02010-06-23 01:19:29 +0000464 if (out_fh && !reader.IsDone() && reader.GetPrompt())
Caroline Ticef81b4c52010-10-27 18:34:42 +0000465 {
Greg Clayton63094e02010-06-23 01:19:29 +0000466 ::fprintf (out_fh, "%s", reader.GetPrompt());
Caroline Ticef81b4c52010-10-27 18:34:42 +0000467 ::fflush (out_fh);
468 }
Chris Lattner24943d22010-06-08 16:52:24 +0000469 break;
470
Caroline Ticec4f55fe2010-11-19 20:47:54 +0000471 case eInputReaderInterrupt:
472 {
473 // Finish, and cancel the breakpoint command.
474 reader.SetIsDone (true);
475 BreakpointOptions *bp_options = (BreakpointOptions *) baton;
476 if (bp_options)
477 {
478 Baton *bp_options_baton = bp_options->GetBaton ();
479 if (bp_options_baton)
480 {
481 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear();
482 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.Clear();
483 }
484 }
485 ::fprintf (out_fh, "Warning: No command attached to breakpoint.\n");
486 ::fflush (out_fh);
487 }
488 break;
489
490 case eInputReaderEndOfFile:
491 reader.SetIsDone (true);
492 break;
493
Chris Lattner24943d22010-06-08 16:52:24 +0000494 case eInputReaderDone:
495 break;
496 }
497
498 return bytes_len;
499}
500
501
502//-------------------------------------------------------------------------
503// CommandObjectBreakpointCommandRemove
504//-------------------------------------------------------------------------
505
Greg Clayton238c0a12010-09-18 01:14:36 +0000506CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove (CommandInterpreter &interpreter) :
507 CommandObject (interpreter,
508 "remove",
Chris Lattner24943d22010-06-08 16:52:24 +0000509 "Remove the set of commands from a breakpoint.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000510 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000511{
Caroline Tice43b014a2010-10-04 22:28:36 +0000512 CommandArgumentEntry arg;
513 CommandArgumentData bp_id_arg;
514
515 // Define the first (and only) variant of this arg.
516 bp_id_arg.arg_type = eArgTypeBreakpointID;
517 bp_id_arg.arg_repetition = eArgRepeatPlain;
518
519 // There is only one variant this argument could be; put it into the argument entry.
520 arg.push_back (bp_id_arg);
521
522 // Push the data for the first argument into the m_arguments vector.
523 m_arguments.push_back (arg);
Chris Lattner24943d22010-06-08 16:52:24 +0000524}
525
526CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove ()
527{
528}
529
530bool
Greg Clayton63094e02010-06-23 01:19:29 +0000531CommandObjectBreakpointCommandRemove::Execute
532(
Greg Clayton63094e02010-06-23 01:19:29 +0000533 Args& command,
534 CommandReturnObject &result
535)
Chris Lattner24943d22010-06-08 16:52:24 +0000536{
Greg Clayton238c0a12010-09-18 01:14:36 +0000537 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000538
539 if (target == NULL)
540 {
541 result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands");
542 result.SetStatus (eReturnStatusFailed);
543 return false;
544 }
545
546 const BreakpointList &breakpoints = target->GetBreakpointList();
547 size_t num_breakpoints = breakpoints.GetSize();
548
549 if (num_breakpoints == 0)
550 {
551 result.AppendError ("No breakpoints exist to have commands removed");
552 result.SetStatus (eReturnStatusFailed);
553 return false;
554 }
555
556 if (command.GetArgumentCount() == 0)
557 {
558 result.AppendError ("No breakpoint specified from which to remove the commands");
559 result.SetStatus (eReturnStatusFailed);
560 return false;
561 }
562
563 BreakpointIDList valid_bp_ids;
564 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
565
566 if (result.Succeeded())
567 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000568 const size_t count = valid_bp_ids.GetSize();
569 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000570 {
571 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
572 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
573 {
574 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
575 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
576 {
577 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
578 if (bp_loc_sp)
579 bp_loc_sp->ClearCallback();
580 else
581 {
582 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
583 cur_bp_id.GetBreakpointID(),
584 cur_bp_id.GetLocationID());
585 result.SetStatus (eReturnStatusFailed);
586 return false;
587 }
588 }
589 else
590 {
591 bp->ClearCallback();
592 }
593 }
594 }
595 }
596 return result.Succeeded();
597}
598
599
600//-------------------------------------------------------------------------
601// CommandObjectBreakpointCommandList
602//-------------------------------------------------------------------------
603
Greg Clayton238c0a12010-09-18 01:14:36 +0000604CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) :
605 CommandObject (interpreter,
606 "list",
Chris Lattner24943d22010-06-08 16:52:24 +0000607 "List the script or set of commands to be executed when the breakpoint is hit.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000608 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000609{
Caroline Tice43b014a2010-10-04 22:28:36 +0000610 CommandArgumentEntry arg;
611 CommandArgumentData bp_id_arg;
612
613 // Define the first (and only) variant of this arg.
614 bp_id_arg.arg_type = eArgTypeBreakpointID;
615 bp_id_arg.arg_repetition = eArgRepeatPlain;
616
617 // There is only one variant this argument could be; put it into the argument entry.
618 arg.push_back (bp_id_arg);
619
620 // Push the data for the first argument into the m_arguments vector.
621 m_arguments.push_back (arg);
Chris Lattner24943d22010-06-08 16:52:24 +0000622}
623
624CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList ()
625{
626}
627
628bool
Greg Clayton63094e02010-06-23 01:19:29 +0000629CommandObjectBreakpointCommandList::Execute
630(
Greg Clayton63094e02010-06-23 01:19:29 +0000631 Args& command,
632 CommandReturnObject &result
633)
Chris Lattner24943d22010-06-08 16:52:24 +0000634{
Greg Clayton238c0a12010-09-18 01:14:36 +0000635 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000636
637 if (target == NULL)
638 {
639 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
640 result.SetStatus (eReturnStatusFailed);
641 return false;
642 }
643
644 const BreakpointList &breakpoints = target->GetBreakpointList();
645 size_t num_breakpoints = breakpoints.GetSize();
646
647 if (num_breakpoints == 0)
648 {
649 result.AppendError ("No breakpoints exist for which to list commands");
650 result.SetStatus (eReturnStatusFailed);
651 return false;
652 }
653
654 if (command.GetArgumentCount() == 0)
655 {
656 result.AppendError ("No breakpoint specified for which to list the commands");
657 result.SetStatus (eReturnStatusFailed);
658 return false;
659 }
660
661 BreakpointIDList valid_bp_ids;
662 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
663
664 if (result.Succeeded())
665 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000666 const size_t count = valid_bp_ids.GetSize();
667 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000668 {
669 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
670 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
671 {
672 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
673
674 if (bp)
675 {
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000676 const BreakpointOptions *bp_options = NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000677 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
678 {
679 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
680 if (bp_loc_sp)
Jim Ingham9c6898b2010-06-22 21:12:54 +0000681 bp_options = bp_loc_sp->GetOptionsNoCreate();
Chris Lattner24943d22010-06-08 16:52:24 +0000682 else
683 {
684 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
685 cur_bp_id.GetBreakpointID(),
686 cur_bp_id.GetLocationID());
687 result.SetStatus (eReturnStatusFailed);
688 return false;
689 }
690 }
691 else
692 {
693 bp_options = bp->GetOptions();
694 }
695
696 if (bp_options)
697 {
698 StreamString id_str;
699 BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000700 const Baton *baton = bp_options->GetBaton();
Chris Lattner24943d22010-06-08 16:52:24 +0000701 if (baton)
702 {
703 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
704 result.GetOutputStream().IndentMore ();
705 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
706 result.GetOutputStream().IndentLess ();
707 }
708 else
709 {
710 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData());
711 }
712 }
713 result.SetStatus (eReturnStatusSuccessFinishResult);
714 }
715 else
716 {
717 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
718 result.SetStatus (eReturnStatusFailed);
719 }
720
721 }
722 }
723 }
724
725 return result.Succeeded();
726}
727
728//-------------------------------------------------------------------------
729// CommandObjectBreakpointCommand
730//-------------------------------------------------------------------------
731
Greg Clayton63094e02010-06-23 01:19:29 +0000732CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +0000733 CommandObjectMultiword (interpreter,
734 "command",
Chris Lattner24943d22010-06-08 16:52:24 +0000735 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
736 "command <sub-command> [<sub-command-options>] <breakpoint-id>")
737{
738 bool status;
Greg Clayton238c0a12010-09-18 01:14:36 +0000739 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
740 CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove (interpreter));
741 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter));
Chris Lattner24943d22010-06-08 16:52:24 +0000742
743 add_command_object->SetCommandName ("breakpoint command add");
744 remove_command_object->SetCommandName ("breakpoint command remove");
745 list_command_object->SetCommandName ("breakpoint command list");
746
Greg Clayton238c0a12010-09-18 01:14:36 +0000747 status = LoadSubCommand ("add", add_command_object);
748 status = LoadSubCommand ("remove", remove_command_object);
749 status = LoadSubCommand ("list", list_command_object);
Chris Lattner24943d22010-06-08 16:52:24 +0000750}
751
752
753CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
754{
755}
756
757bool
758CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction
759(
760 void *baton,
761 StoppointCallbackContext *context,
762 lldb::user_id_t break_id,
763 lldb::user_id_t break_loc_id
764)
765{
766 bool ret_value = true;
767 if (baton == NULL)
768 return true;
769
770
771 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
772 StringList &commands = data->user_source;
773
774 if (commands.GetSize() > 0)
775 {
776 uint32_t num_commands = commands.GetSize();
Chris Lattner24943d22010-06-08 16:52:24 +0000777 CommandReturnObject result;
Greg Clayton63094e02010-06-23 01:19:29 +0000778 if (context->exe_ctx.target)
Chris Lattner24943d22010-06-08 16:52:24 +0000779 {
Greg Clayton63094e02010-06-23 01:19:29 +0000780
781 Debugger &debugger = context->exe_ctx.target->GetDebugger();
782 CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
783
784 FILE *out_fh = debugger.GetOutputFileHandle();
785 FILE *err_fh = debugger.GetErrorFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000786
Greg Clayton63094e02010-06-23 01:19:29 +0000787 uint32_t i;
788 for (i = 0; i < num_commands; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000789 {
Greg Clayton63094e02010-06-23 01:19:29 +0000790
791 // First time through we use the context from the stoppoint, after that we use whatever
792 // has been set by the previous command.
793
794 if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &context->exe_ctx))
795 break;
796
797 // FIXME: This isn't really the right way to do this. We should be able to peek at the public
798 // to see if there is any new events, but that is racey, since the internal process thread has to run and
799 // deliver the event to the public queue before a run will show up. So for now we check
800 // the internal thread state.
801
802 lldb::StateType internal_state = context->exe_ctx.process->GetPrivateState();
803 if (internal_state != eStateStopped)
Chris Lattner24943d22010-06-08 16:52:24 +0000804 {
Greg Clayton63094e02010-06-23 01:19:29 +0000805 if (i < num_commands - 1)
806 {
807 if (out_fh)
808 ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s."
809 " last command: \"%s\"\n", StateAsCString(internal_state),
810 commands.GetStringAtIndex(i));
811 }
812 break;
Chris Lattner24943d22010-06-08 16:52:24 +0000813 }
Greg Clayton63094e02010-06-23 01:19:29 +0000814
815 if (out_fh)
816 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
817 if (err_fh)
818 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
819 result.Clear();
820 result.SetStatus (eReturnStatusSuccessFinishNoResult);
Chris Lattner24943d22010-06-08 16:52:24 +0000821 }
Chris Lattner24943d22010-06-08 16:52:24 +0000822
Greg Clayton63094e02010-06-23 01:19:29 +0000823 if (err_fh && !result.Succeeded() && i < num_commands)
824 ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i));
825
Chris Lattner24943d22010-06-08 16:52:24 +0000826 if (out_fh)
827 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
Greg Clayton63094e02010-06-23 01:19:29 +0000828
Chris Lattner24943d22010-06-08 16:52:24 +0000829 if (err_fh)
Greg Clayton63094e02010-06-23 01:19:29 +0000830 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
Chris Lattner24943d22010-06-08 16:52:24 +0000831 }
Chris Lattner24943d22010-06-08 16:52:24 +0000832 }
833 return ret_value;
834}
835