blob: c706bb555a6826fcda0c58165dc731c82441ed6a [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
Chris Lattner24943d22010-06-08 16:52:24 +0000285 BreakpointIDList valid_bp_ids;
286 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
287
288 if (result.Succeeded())
289 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000290 const size_t count = valid_bp_ids.GetSize();
291 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000292 {
293 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
294 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
295 {
296 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000297 BreakpointOptions *bp_options = NULL;
298 if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
299 {
300 // This breakpoint does not have an associated location.
301 bp_options = bp->GetOptions();
302 }
303 else
Chris Lattner24943d22010-06-08 16:52:24 +0000304 {
305 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000306 // This breakpoint does have an associated location.
307 // Get its breakpoint options.
Chris Lattner24943d22010-06-08 16:52:24 +0000308 if (bp_loc_sp)
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000309 bp_options = bp_loc_sp->GetLocationOptions();
310 }
311
312 // Skip this breakpoiont if bp_options is not good.
313 if (bp_options == NULL) continue;
314
315 // If we are using script language, get the script interpreter
316 // in order to set or collect command callback. Otherwise, call
317 // the methods associated with this object.
318 if (m_options.m_use_script_language)
319 {
320 // Special handling for one-liner specified inline.
321 if (m_options.m_use_one_liner)
Greg Clayton238c0a12010-09-18 01:14:36 +0000322 m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
323 m_options.m_one_liner.c_str());
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000324 else
Greg Clayton238c0a12010-09-18 01:14:36 +0000325 m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options,
326 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000327 }
328 else
329 {
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000330 // Special handling for one-liner specified inline.
331 if (m_options.m_use_one_liner)
Greg Clayton238c0a12010-09-18 01:14:36 +0000332 SetBreakpointCommandCallback (bp_options,
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000333 m_options.m_one_liner.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +0000334 else
Greg Clayton238c0a12010-09-18 01:14:36 +0000335 CollectDataForBreakpointCommandCallback (bp_options,
Greg Claytonbef15832010-07-14 00:18:15 +0000336 result);
Chris Lattner24943d22010-06-08 16:52:24 +0000337 }
338 }
339 }
340 }
341
342 return result.Succeeded();
343}
344
345Options *
346CommandObjectBreakpointCommandAdd::GetOptions ()
347{
348 return &m_options;
349}
350
351const char *g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
352
353void
354CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback
355(
356 BreakpointOptions *bp_options,
357 CommandReturnObject &result
358)
359{
Greg Clayton238c0a12010-09-18 01:14:36 +0000360 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
Chris Lattner24943d22010-06-08 16:52:24 +0000361 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
362 if (reader_sp && data_ap.get())
363 {
364 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
365 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
366
367 Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
368 bp_options, // baton
369 eInputReaderGranularityLine, // token size, to pass to callback function
370 "DONE", // end token
371 "> ", // prompt
372 true)); // echo input
373 if (err.Success())
374 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000375 m_interpreter.GetDebugger().PushInputReader (reader_sp);
Chris Lattner24943d22010-06-08 16:52:24 +0000376 result.SetStatus (eReturnStatusSuccessFinishNoResult);
377 }
378 else
379 {
380 result.AppendError (err.AsCString());
381 result.SetStatus (eReturnStatusFailed);
382 }
383 }
384 else
385 {
386 result.AppendError("out of memory");
387 result.SetStatus (eReturnStatusFailed);
388 }
389
390}
391
Johnny Chen3e0571b2010-09-11 00:23:59 +0000392// Set a one-liner as the callback for the breakpoint.
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000393void
Greg Clayton238c0a12010-09-18 01:14:36 +0000394CommandObjectBreakpointCommandAdd::SetBreakpointCommandCallback (BreakpointOptions *bp_options,
Johnny Chenb81ed0d2010-09-11 00:18:09 +0000395 const char *oneliner)
396{
397 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
398
399 // It's necessary to set both user_source and script_source to the oneliner.
400 // The former is used to generate callback description (as in breakpoint command list)
401 // while the latter is used for Python to interpret during the actual callback.
402 data_ap->user_source.AppendString (oneliner);
403 data_ap->script_source.AppendString (oneliner);
404
405 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
406 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp);
407
408 return;
409}
410
Chris Lattner24943d22010-06-08 16:52:24 +0000411size_t
412CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback
413(
414 void *baton,
Greg Clayton63094e02010-06-23 01:19:29 +0000415 InputReader &reader,
Chris Lattner24943d22010-06-08 16:52:24 +0000416 lldb::InputReaderAction notification,
417 const char *bytes,
418 size_t bytes_len
419)
420{
Greg Clayton63094e02010-06-23 01:19:29 +0000421 FILE *out_fh = reader.GetDebugger().GetOutputFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000422
423 switch (notification)
424 {
425 case eInputReaderActivate:
426 if (out_fh)
427 {
428 ::fprintf (out_fh, "%s\n", g_reader_instructions);
Greg Clayton63094e02010-06-23 01:19:29 +0000429 if (reader.GetPrompt())
430 ::fprintf (out_fh, "%s", reader.GetPrompt());
Caroline Ticef81b4c52010-10-27 18:34:42 +0000431 ::fflush (out_fh);
Chris Lattner24943d22010-06-08 16:52:24 +0000432 }
433 break;
434
435 case eInputReaderDeactivate:
436 break;
437
438 case eInputReaderReactivate:
Greg Clayton63094e02010-06-23 01:19:29 +0000439 if (out_fh && reader.GetPrompt())
Caroline Ticef81b4c52010-10-27 18:34:42 +0000440 {
Greg Clayton63094e02010-06-23 01:19:29 +0000441 ::fprintf (out_fh, "%s", reader.GetPrompt());
Caroline Ticef81b4c52010-10-27 18:34:42 +0000442 ::fflush (out_fh);
443 }
Chris Lattner24943d22010-06-08 16:52:24 +0000444 break;
445
446 case eInputReaderGotToken:
447 if (bytes && bytes_len && baton)
448 {
449 BreakpointOptions *bp_options = (BreakpointOptions *) baton;
450 if (bp_options)
451 {
452 Baton *bp_options_baton = bp_options->GetBaton();
453 if (bp_options_baton)
454 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
455 }
456 }
Greg Clayton63094e02010-06-23 01:19:29 +0000457 if (out_fh && !reader.IsDone() && reader.GetPrompt())
Caroline Ticef81b4c52010-10-27 18:34:42 +0000458 {
Greg Clayton63094e02010-06-23 01:19:29 +0000459 ::fprintf (out_fh, "%s", reader.GetPrompt());
Caroline Ticef81b4c52010-10-27 18:34:42 +0000460 ::fflush (out_fh);
461 }
Chris Lattner24943d22010-06-08 16:52:24 +0000462 break;
463
Caroline Ticec4f55fe2010-11-19 20:47:54 +0000464 case eInputReaderInterrupt:
465 {
466 // Finish, and cancel the breakpoint command.
467 reader.SetIsDone (true);
468 BreakpointOptions *bp_options = (BreakpointOptions *) baton;
469 if (bp_options)
470 {
471 Baton *bp_options_baton = bp_options->GetBaton ();
472 if (bp_options_baton)
473 {
474 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear();
475 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.Clear();
476 }
477 }
478 ::fprintf (out_fh, "Warning: No command attached to breakpoint.\n");
479 ::fflush (out_fh);
480 }
481 break;
482
483 case eInputReaderEndOfFile:
484 reader.SetIsDone (true);
485 break;
486
Chris Lattner24943d22010-06-08 16:52:24 +0000487 case eInputReaderDone:
488 break;
489 }
490
491 return bytes_len;
492}
493
494
495//-------------------------------------------------------------------------
496// CommandObjectBreakpointCommandRemove
497//-------------------------------------------------------------------------
498
Greg Clayton238c0a12010-09-18 01:14:36 +0000499CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove (CommandInterpreter &interpreter) :
500 CommandObject (interpreter,
501 "remove",
Chris Lattner24943d22010-06-08 16:52:24 +0000502 "Remove the set of commands from a breakpoint.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000503 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000504{
Caroline Tice43b014a2010-10-04 22:28:36 +0000505 CommandArgumentEntry arg;
506 CommandArgumentData bp_id_arg;
507
508 // Define the first (and only) variant of this arg.
509 bp_id_arg.arg_type = eArgTypeBreakpointID;
510 bp_id_arg.arg_repetition = eArgRepeatPlain;
511
512 // There is only one variant this argument could be; put it into the argument entry.
513 arg.push_back (bp_id_arg);
514
515 // Push the data for the first argument into the m_arguments vector.
516 m_arguments.push_back (arg);
Chris Lattner24943d22010-06-08 16:52:24 +0000517}
518
519CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove ()
520{
521}
522
523bool
Greg Clayton63094e02010-06-23 01:19:29 +0000524CommandObjectBreakpointCommandRemove::Execute
525(
Greg Clayton63094e02010-06-23 01:19:29 +0000526 Args& command,
527 CommandReturnObject &result
528)
Chris Lattner24943d22010-06-08 16:52:24 +0000529{
Greg Clayton238c0a12010-09-18 01:14:36 +0000530 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000531
532 if (target == NULL)
533 {
534 result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands");
535 result.SetStatus (eReturnStatusFailed);
536 return false;
537 }
538
539 const BreakpointList &breakpoints = target->GetBreakpointList();
540 size_t num_breakpoints = breakpoints.GetSize();
541
542 if (num_breakpoints == 0)
543 {
544 result.AppendError ("No breakpoints exist to have commands removed");
545 result.SetStatus (eReturnStatusFailed);
546 return false;
547 }
548
549 if (command.GetArgumentCount() == 0)
550 {
551 result.AppendError ("No breakpoint specified from which to remove the commands");
552 result.SetStatus (eReturnStatusFailed);
553 return false;
554 }
555
556 BreakpointIDList valid_bp_ids;
557 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
558
559 if (result.Succeeded())
560 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000561 const size_t count = valid_bp_ids.GetSize();
562 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000563 {
564 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
565 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
566 {
567 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
568 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
569 {
570 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
571 if (bp_loc_sp)
572 bp_loc_sp->ClearCallback();
573 else
574 {
575 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
576 cur_bp_id.GetBreakpointID(),
577 cur_bp_id.GetLocationID());
578 result.SetStatus (eReturnStatusFailed);
579 return false;
580 }
581 }
582 else
583 {
584 bp->ClearCallback();
585 }
586 }
587 }
588 }
589 return result.Succeeded();
590}
591
592
593//-------------------------------------------------------------------------
594// CommandObjectBreakpointCommandList
595//-------------------------------------------------------------------------
596
Greg Clayton238c0a12010-09-18 01:14:36 +0000597CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) :
598 CommandObject (interpreter,
599 "list",
Chris Lattner24943d22010-06-08 16:52:24 +0000600 "List the script or set of commands to be executed when the breakpoint is hit.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000601 NULL)
Chris Lattner24943d22010-06-08 16:52:24 +0000602{
Caroline Tice43b014a2010-10-04 22:28:36 +0000603 CommandArgumentEntry arg;
604 CommandArgumentData bp_id_arg;
605
606 // Define the first (and only) variant of this arg.
607 bp_id_arg.arg_type = eArgTypeBreakpointID;
608 bp_id_arg.arg_repetition = eArgRepeatPlain;
609
610 // There is only one variant this argument could be; put it into the argument entry.
611 arg.push_back (bp_id_arg);
612
613 // Push the data for the first argument into the m_arguments vector.
614 m_arguments.push_back (arg);
Chris Lattner24943d22010-06-08 16:52:24 +0000615}
616
617CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList ()
618{
619}
620
621bool
Greg Clayton63094e02010-06-23 01:19:29 +0000622CommandObjectBreakpointCommandList::Execute
623(
Greg Clayton63094e02010-06-23 01:19:29 +0000624 Args& command,
625 CommandReturnObject &result
626)
Chris Lattner24943d22010-06-08 16:52:24 +0000627{
Greg Clayton238c0a12010-09-18 01:14:36 +0000628 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
Chris Lattner24943d22010-06-08 16:52:24 +0000629
630 if (target == NULL)
631 {
632 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
633 result.SetStatus (eReturnStatusFailed);
634 return false;
635 }
636
637 const BreakpointList &breakpoints = target->GetBreakpointList();
638 size_t num_breakpoints = breakpoints.GetSize();
639
640 if (num_breakpoints == 0)
641 {
642 result.AppendError ("No breakpoints exist for which to list commands");
643 result.SetStatus (eReturnStatusFailed);
644 return false;
645 }
646
647 if (command.GetArgumentCount() == 0)
648 {
649 result.AppendError ("No breakpoint specified for which to list the commands");
650 result.SetStatus (eReturnStatusFailed);
651 return false;
652 }
653
654 BreakpointIDList valid_bp_ids;
655 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
656
657 if (result.Succeeded())
658 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000659 const size_t count = valid_bp_ids.GetSize();
660 for (size_t i = 0; i < count; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000661 {
662 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
663 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
664 {
665 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
666
667 if (bp)
668 {
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000669 const BreakpointOptions *bp_options = NULL;
Chris Lattner24943d22010-06-08 16:52:24 +0000670 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
671 {
672 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
673 if (bp_loc_sp)
Jim Ingham9c6898b2010-06-22 21:12:54 +0000674 bp_options = bp_loc_sp->GetOptionsNoCreate();
Chris Lattner24943d22010-06-08 16:52:24 +0000675 else
676 {
677 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
678 cur_bp_id.GetBreakpointID(),
679 cur_bp_id.GetLocationID());
680 result.SetStatus (eReturnStatusFailed);
681 return false;
682 }
683 }
684 else
685 {
686 bp_options = bp->GetOptions();
687 }
688
689 if (bp_options)
690 {
691 StreamString id_str;
692 BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
Jim Ingham3c7b5b92010-06-16 02:00:15 +0000693 const Baton *baton = bp_options->GetBaton();
Chris Lattner24943d22010-06-08 16:52:24 +0000694 if (baton)
695 {
696 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
697 result.GetOutputStream().IndentMore ();
698 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
699 result.GetOutputStream().IndentLess ();
700 }
701 else
702 {
703 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData());
704 }
705 }
706 result.SetStatus (eReturnStatusSuccessFinishResult);
707 }
708 else
709 {
710 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
711 result.SetStatus (eReturnStatusFailed);
712 }
713
714 }
715 }
716 }
717
718 return result.Succeeded();
719}
720
721//-------------------------------------------------------------------------
722// CommandObjectBreakpointCommand
723//-------------------------------------------------------------------------
724
Greg Clayton63094e02010-06-23 01:19:29 +0000725CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +0000726 CommandObjectMultiword (interpreter,
727 "command",
Chris Lattner24943d22010-06-08 16:52:24 +0000728 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
729 "command <sub-command> [<sub-command-options>] <breakpoint-id>")
730{
731 bool status;
Greg Clayton238c0a12010-09-18 01:14:36 +0000732 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
733 CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove (interpreter));
734 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter));
Chris Lattner24943d22010-06-08 16:52:24 +0000735
736 add_command_object->SetCommandName ("breakpoint command add");
737 remove_command_object->SetCommandName ("breakpoint command remove");
738 list_command_object->SetCommandName ("breakpoint command list");
739
Greg Clayton238c0a12010-09-18 01:14:36 +0000740 status = LoadSubCommand ("add", add_command_object);
741 status = LoadSubCommand ("remove", remove_command_object);
742 status = LoadSubCommand ("list", list_command_object);
Chris Lattner24943d22010-06-08 16:52:24 +0000743}
744
745
746CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
747{
748}
749
750bool
751CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction
752(
753 void *baton,
754 StoppointCallbackContext *context,
755 lldb::user_id_t break_id,
756 lldb::user_id_t break_loc_id
757)
758{
759 bool ret_value = true;
760 if (baton == NULL)
761 return true;
762
763
764 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
765 StringList &commands = data->user_source;
766
767 if (commands.GetSize() > 0)
768 {
769 uint32_t num_commands = commands.GetSize();
Chris Lattner24943d22010-06-08 16:52:24 +0000770 CommandReturnObject result;
Greg Clayton63094e02010-06-23 01:19:29 +0000771 if (context->exe_ctx.target)
Chris Lattner24943d22010-06-08 16:52:24 +0000772 {
Greg Clayton63094e02010-06-23 01:19:29 +0000773
774 Debugger &debugger = context->exe_ctx.target->GetDebugger();
775 CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
776
777 FILE *out_fh = debugger.GetOutputFileHandle();
778 FILE *err_fh = debugger.GetErrorFileHandle();
Chris Lattner24943d22010-06-08 16:52:24 +0000779
Greg Clayton63094e02010-06-23 01:19:29 +0000780 uint32_t i;
781 for (i = 0; i < num_commands; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +0000782 {
Greg Clayton63094e02010-06-23 01:19:29 +0000783
784 // First time through we use the context from the stoppoint, after that we use whatever
785 // has been set by the previous command.
786
787 if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &context->exe_ctx))
788 break;
789
790 // FIXME: This isn't really the right way to do this. We should be able to peek at the public
791 // to see if there is any new events, but that is racey, since the internal process thread has to run and
792 // deliver the event to the public queue before a run will show up. So for now we check
793 // the internal thread state.
794
795 lldb::StateType internal_state = context->exe_ctx.process->GetPrivateState();
796 if (internal_state != eStateStopped)
Chris Lattner24943d22010-06-08 16:52:24 +0000797 {
Greg Clayton63094e02010-06-23 01:19:29 +0000798 if (i < num_commands - 1)
799 {
800 if (out_fh)
801 ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s."
802 " last command: \"%s\"\n", StateAsCString(internal_state),
803 commands.GetStringAtIndex(i));
804 }
805 break;
Chris Lattner24943d22010-06-08 16:52:24 +0000806 }
Greg Clayton63094e02010-06-23 01:19:29 +0000807
808 if (out_fh)
809 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
810 if (err_fh)
811 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
812 result.Clear();
813 result.SetStatus (eReturnStatusSuccessFinishNoResult);
Chris Lattner24943d22010-06-08 16:52:24 +0000814 }
Chris Lattner24943d22010-06-08 16:52:24 +0000815
Greg Clayton63094e02010-06-23 01:19:29 +0000816 if (err_fh && !result.Succeeded() && i < num_commands)
817 ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i));
818
Chris Lattner24943d22010-06-08 16:52:24 +0000819 if (out_fh)
820 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData());
Greg Clayton63094e02010-06-23 01:19:29 +0000821
Chris Lattner24943d22010-06-08 16:52:24 +0000822 if (err_fh)
Greg Clayton63094e02010-06-23 01:19:29 +0000823 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData());
Chris Lattner24943d22010-06-08 16:52:24 +0000824 }
Chris Lattner24943d22010-06-08 16:52:24 +0000825 }
826 return ret_value;
827}
828