1 //===-- CommandObjectBreakpoint.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 #include "CommandObjectBreakpoint.h"
11 #include "CommandObjectBreakpointCommand.h"
12 
13 // C Includes
14 // C++ Includes
15 // Other libraries and framework includes
16 // Project includes
17 #include "lldb/Breakpoint/Breakpoint.h"
18 #include "lldb/Breakpoint/BreakpointIDList.h"
19 #include "lldb/Breakpoint/BreakpointLocation.h"
20 #include "lldb/Core/RegularExpression.h"
21 #include "lldb/Core/StreamString.h"
22 #include "lldb/Interpreter/CommandInterpreter.h"
23 #include "lldb/Interpreter/CommandReturnObject.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Interpreter/CommandCompletions.h"
26 #include "lldb/Target/StackFrame.h"
27 
28 using namespace lldb;
29 using namespace lldb_private;
30 
31 static void
32 AddBreakpointDescription (CommandContext *context, StreamString *s, Breakpoint *bp, lldb::DescriptionLevel level)
33 {
34     s->IndentMore();
35     bp->GetDescription (s, level, true);
36     s->IndentLess();
37     s->EOL();
38 }
39 
40 //-------------------------------------------------------------------------
41 // CommandObjectBreakpointSet::CommandOptions
42 //-------------------------------------------------------------------------
43 
44 CommandObjectBreakpointSet::CommandOptions::CommandOptions() :
45     Options (),
46     m_filename (),
47     m_line_num (0),
48     m_column (0),
49     m_ignore_inlines (false),
50     m_func_name (),
51     m_func_regexp (),
52     m_modules (),
53     m_load_addr()
54 {
55     BuildValidOptionSets();
56 }
57 
58 CommandObjectBreakpointSet::CommandOptions::~CommandOptions ()
59 {
60 }
61 
62 lldb::OptionDefinition
63 CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
64 {
65     { 0, false, "file",       'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, "<filename>",
66         "Set the breakpoint by source location in this particular file."},
67 
68     { 0, true, "line",       'l', required_argument, NULL, 0, "<linenum>",
69         "Set the breakpoint by source location at this particular line."},
70 
71     { 0, false, "shlib",       's', required_argument, NULL, CommandCompletions::eModuleCompletion, "<shlib-name>",
72         "Set the breakpoint only in this shared library (can use this option multiple times for multiple shlibs)."},
73 
74     // Comment out this option for the moment, as we don't actually use it, but will in the future.
75     // This way users won't see it, but the infrastructure is left in place.
76     //    { 0, false, "column",     'c', required_argument, NULL, "<column>",
77     //    "Set the breakpoint by source location at this particular column."},
78 
79     { 0, false, "ignore_inlines", 'i', no_argument,   NULL, 0, NULL,
80         "Ignore inlined subroutines when setting the breakppoint." },
81 
82     { 1, true, "address",    'a', required_argument, NULL, 0, "<address>",
83         "Set the breakpoint by address, at the specified address."},
84 
85     { 1, false, "ignore_inlines", 'i', no_argument,   NULL, 0, NULL,
86         "Ignore inlined subroutines when setting the breakppoint." },
87 
88     { 2, true, "name",       'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, "<function-name>",
89         "Set the breakpoint by function name." },
90 
91     { 2, false, "shlib",       's', required_argument, NULL, CommandCompletions::eModuleCompletion, "<shlib-name>",
92         "Set the breakpoint only in this shared library (can use this option multiple times for multiple shlibs)."},
93 
94     { 2, false, "ignore_inlines", 'i', no_argument,   NULL, 0, NULL,
95         "Ignore inlined subroutines when setting the breakpoint." },
96 
97     { 3, true, "func_regex", 'r', required_argument, NULL, 0, "<regular-expression>",
98         "Set the breakpoint by function name, evaluating a regular-expression to find the function name(s)." },
99 
100     { 3, false, "shlib",       's', required_argument, NULL, CommandCompletions::eModuleCompletion, "<shlib-name>",
101         "Set the breakpoint only in this shared library (can use this option multiple times for multiple shlibs)."},
102 
103     { 3, false, "ignore_inlines", 'i', no_argument,   NULL, 0, NULL,
104         "Ignore inlined subroutines when setting the breakpoint." },
105 
106     { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
107 };
108 
109 const lldb::OptionDefinition*
110 CommandObjectBreakpointSet::CommandOptions::GetDefinitions ()
111 {
112     return g_option_table;
113 }
114 
115 Error
116 CommandObjectBreakpointSet::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
117 {
118     Error error;
119     char short_option = (char) m_getopt_table[option_idx].val;
120 
121     switch (short_option)
122     {
123         case 'a':
124             m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 0);
125             if (m_load_addr == LLDB_INVALID_ADDRESS)
126                 m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 16);
127 
128             if (m_load_addr == LLDB_INVALID_ADDRESS)
129                 error.SetErrorStringWithFormat ("Invalid address string '%s'.\n", optarg);
130             break;
131 
132         case 'c':
133             m_column = Args::StringToUInt32 (option_arg, 0);
134             break;
135         case 'f':
136             m_filename = option_arg;
137             break;
138         case 'i':
139             m_ignore_inlines = true;
140             break;
141         case 'l':
142             m_line_num = Args::StringToUInt32 (option_arg, 0);
143             break;
144         case 'n':
145             m_func_name = option_arg;
146             break;
147         case 'r':
148             m_func_regexp = option_arg;
149             break;
150         case 's':
151             {
152                 m_modules.push_back (std::string (option_arg));
153                 break;
154             }
155         default:
156             error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
157             break;
158     }
159 
160     return error;
161 }
162 
163 void
164 CommandObjectBreakpointSet::CommandOptions::ResetOptionValues ()
165 {
166     Options::ResetOptionValues();
167 
168     m_filename.clear();
169     m_line_num = 0;
170     m_column = 0;
171     m_ignore_inlines = false;
172     m_func_name.clear();
173     m_func_regexp.clear();
174     m_load_addr = LLDB_INVALID_ADDRESS;
175     m_modules.clear();
176 }
177 
178 //-------------------------------------------------------------------------
179 // CommandObjectBreakpointSet
180 //-------------------------------------------------------------------------
181 
182 CommandObjectBreakpointSet::CommandObjectBreakpointSet () :
183     CommandObject ("breakpoint set", "Sets a breakpoint or set of breakpoints in the executable.",
184                    "breakpoint set <cmd-options>")
185 {
186 }
187 
188 CommandObjectBreakpointSet::~CommandObjectBreakpointSet ()
189 {
190 }
191 
192 Options *
193 CommandObjectBreakpointSet::GetOptions ()
194 {
195     return &m_options;
196 }
197 
198 bool
199 CommandObjectBreakpointSet::Execute
200 (
201     Args& command,
202     CommandContext *context,
203     CommandInterpreter *interpreter,
204     CommandReturnObject &result
205 )
206 {
207     Target *target = context->GetTarget();
208     if (target == NULL)
209     {
210         result.AppendError ("Invalid target, set executable file using 'file' command.");
211         result.SetStatus (eReturnStatusFailed);
212         return false;
213     }
214 
215     // The following are the various types of breakpoints that could be set:
216     //   1).  -f -l -p  [-s -g]   (setting breakpoint by source location)
217     //   2).  -a  [-s -g]         (setting breakpoint by address)
218     //   3).  -n  [-s -g]         (setting breakpoint by function name)
219     //   4).  -r  [-s -g]         (setting breakpoint by function name regular expression)
220 
221     BreakpointSetType break_type = eSetTypeInvalid;
222 
223     if (m_options.m_line_num != 0)
224         break_type = eSetTypeFileAndLine;
225     else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
226         break_type = eSetTypeAddress;
227     else if (!m_options.m_func_name.empty())
228         break_type = eSetTypeFunctionName;
229     else if  (!m_options.m_func_regexp.empty())
230         break_type = eSetTypeFunctionRegexp;
231 
232     ModuleSP module_sp = target->GetExecutableModule();
233     Breakpoint *bp = NULL;
234     FileSpec module;
235     bool use_module = false;
236     int num_modules = m_options.m_modules.size();
237 
238     if ((num_modules > 0) && (break_type != eSetTypeAddress))
239         use_module = true;
240 
241     switch (break_type)
242     {
243         case eSetTypeFileAndLine: // Breakpoint by source position
244         {
245             FileSpec file;
246             if (m_options.m_filename.empty())
247             {
248                 StackFrame *cur_frame = context->GetExecutionContext().frame;
249                 if (cur_frame == NULL)
250                 {
251                     result.AppendError ("Attempting to set breakpoint by line number alone with no selected frame.");
252                     result.SetStatus (eReturnStatusFailed);
253                     break;
254                 }
255                 else if (!cur_frame->HasDebugInformation())
256                 {
257                     result.AppendError ("Attempting to set breakpoint by line number alone but selected frame has no debug info.");
258                     result.SetStatus (eReturnStatusFailed);
259                     break;
260                 }
261                 else
262                 {
263                     const SymbolContext &context = cur_frame->GetSymbolContext(true);
264                     if (context.line_entry.file)
265                     {
266                         file = context.line_entry.file;
267                     }
268                     else if (context.comp_unit != NULL)
269                     {    file = context.comp_unit;
270                     }
271                     else
272                     {
273                         result.AppendError ("Attempting to set breakpoint by line number alone but can't find the file for the selected frame.");
274                         result.SetStatus (eReturnStatusFailed);
275                         break;
276                     }
277                 }
278             }
279             else
280             {
281                 file.SetFile(m_options.m_filename.c_str());
282             }
283 
284             if (use_module)
285             {
286                 for (int i = 0; i < num_modules; ++i)
287                 {
288                     module.SetFile(m_options.m_modules[i].c_str());
289                     bp = target->CreateBreakpoint (&module,
290                                                    file,
291                                                    m_options.m_line_num,
292                                                    m_options.m_ignore_inlines).get();
293                     if (bp)
294                     {
295                         StreamString &output_stream = result.GetOutputStream();
296                         output_stream.Printf ("Breakpoint created: ");
297                         bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief);
298                         output_stream.EOL();
299                         result.SetStatus (eReturnStatusSuccessFinishResult);
300                     }
301                     else
302                     {
303                         result.AppendErrorWithFormat("Breakpoint creation failed: No breakpoint created in module '%s'.\n",
304                                                     m_options.m_modules[i].c_str());
305                         result.SetStatus (eReturnStatusFailed);
306                     }
307                 }
308             }
309             else
310                 bp = target->CreateBreakpoint (NULL,
311                                                file,
312                                                m_options.m_line_num,
313                                                m_options.m_ignore_inlines).get();
314         }
315         break;
316         case eSetTypeAddress: // Breakpoint by address
317             bp = target->CreateBreakpoint (m_options.m_load_addr, false).get();
318             break;
319         case eSetTypeFunctionName: // Breakpoint by function name
320             if (use_module)
321             {
322                 for (int i = 0; i < num_modules; ++i)
323                 {
324                     module.SetFile(m_options.m_modules[i].c_str());
325                     bp = target->CreateBreakpoint (&module, m_options.m_func_name.c_str()).get();
326                     if (bp)
327                     {
328                         StreamString &output_stream = result.GetOutputStream();
329                         output_stream.Printf ("Breakpoint created: ");
330                         bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief);
331                         output_stream.EOL();
332                         result.SetStatus (eReturnStatusSuccessFinishResult);
333                     }
334                     else
335                     {
336                         result.AppendErrorWithFormat("Breakpoint creation failed: No breakpoint created in module '%s'.\n",
337                                                     m_options.m_modules[i].c_str());
338                         result.SetStatus (eReturnStatusFailed);
339                     }
340                 }
341             }
342             else
343                 bp = target->CreateBreakpoint (NULL, m_options.m_func_name.c_str()).get();
344             break;
345         case eSetTypeFunctionRegexp: // Breakpoint by regular expression function name
346             {
347                 RegularExpression regexp(m_options.m_func_regexp.c_str());
348                 if (use_module)
349                 {
350                     for (int i = 0; i < num_modules; ++i)
351                     {
352                         module.SetFile(m_options.m_modules[i].c_str());
353                         bp = target->CreateBreakpoint (&module, regexp).get();
354                         if (bp)
355                         {
356                             StreamString &output_stream = result.GetOutputStream();
357                             output_stream.Printf ("Breakpoint created: ");
358                             bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief);
359                             output_stream.EOL();
360                             result.SetStatus (eReturnStatusSuccessFinishResult);
361                         }
362                         else
363                         {
364                             result.AppendErrorWithFormat("Breakpoint creation failed: No breakpoint created in module '%s'.\n",
365                                                         m_options.m_modules[i].c_str());
366                             result.SetStatus (eReturnStatusFailed);
367                         }
368                     }
369                 }
370                 else
371                     bp = target->CreateBreakpoint (NULL, regexp).get();
372             }
373             break;
374         default:
375             break;
376     }
377 
378     if (bp && !use_module)
379     {
380         StreamString &output_stream = result.GetOutputStream();
381         output_stream.Printf ("Breakpoint created: ");
382         bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief);
383         output_stream.EOL();
384         result.SetStatus (eReturnStatusSuccessFinishResult);
385     }
386     else if (!bp)
387     {
388         result.AppendError ("Breakpoint creation failed: No breakpoint created.");
389         result.SetStatus (eReturnStatusFailed);
390     }
391 
392     return result.Succeeded();
393 }
394 
395 
396 
397 //-------------------------------------------------------------------------
398 // CommandObjectMultiwordBreakpoint
399 //-------------------------------------------------------------------------
400 
401 CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInterpreter *interpreter) :
402     CommandObjectMultiword ("breakpoint",
403                               "A set of commands for operating on breakpoints.",
404                               "breakpoint <command> [<command-options>]")
405 {
406     bool status;
407 
408     CommandObjectSP list_command_object (new CommandObjectBreakpointList ());
409     CommandObjectSP delete_command_object (new CommandObjectBreakpointDelete ());
410     CommandObjectSP enable_command_object (new CommandObjectBreakpointEnable ());
411     CommandObjectSP disable_command_object (new CommandObjectBreakpointDisable ());
412     CommandObjectSP set_command_object (new CommandObjectBreakpointSet ());
413     CommandObjectSP command_command_object (new CommandObjectBreakpointCommand (interpreter));
414 
415     enable_command_object->SetCommandName("breakpoint enable");
416     disable_command_object->SetCommandName("breakpoint disable");
417     set_command_object->SetCommandName("breakpoint set");
418     command_command_object->SetCommandName ("breakpoint command");
419     list_command_object->SetCommandName ("breakpoint list");
420 
421     status = LoadSubCommand (list_command_object, "list", interpreter);
422     status = LoadSubCommand (enable_command_object, "enable", interpreter);
423     status = LoadSubCommand (disable_command_object, "disable", interpreter);
424     status = LoadSubCommand (delete_command_object, "delete", interpreter);
425     status = LoadSubCommand (set_command_object, "set", interpreter);
426     status = LoadSubCommand (command_command_object, "command", interpreter);
427 }
428 
429 CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint ()
430 {
431 }
432 
433 void
434 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result,
435                                                          BreakpointIDList *valid_ids)
436 {
437     // args can be strings representing 1). integers (for breakpoint ids)
438     //                                  2). the full breakpoint & location canonical representation
439     //                                  3). the word "to" or a hyphen, representing a range (in which case there
440     //                                      had *better* be an entry both before & after of one of the first two types.
441 
442     Args temp_args;
443 
444     // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff directly from the old ARGS to
445     // the new TEMP_ARGS.  Do not copy breakpoint id range strings over; instead generate a list of strings for
446     // all the breakpoint ids in the range, and shove all of those breakpoint id strings into TEMP_ARGS.
447 
448     BreakpointIDList::FindAndReplaceIDRanges (args, target, result, temp_args);
449 
450     // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual BreakpointIDList:
451 
452     valid_ids->InsertStringArray ((const char **) temp_args.GetArgumentVector(), temp_args.GetArgumentCount(), result);
453 
454     // At this point,  all of the breakpoint ids that the user passed in have been converted to breakpoint IDs
455     // and put into valid_ids.
456 
457     if (result.Succeeded())
458     {
459         // Now that we've converted everything from args into a list of breakpoint ids, go through our tentative list
460         // of breakpoint id's and verify that they correspond to valid/currently set breakpoints.
461 
462         for (int i = 0; i < valid_ids->Size(); ++i)
463         {
464             BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex (i);
465             Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
466             if (breakpoint != NULL)
467             {
468                 int num_locations = breakpoint->GetNumLocations();
469                 if (cur_bp_id.GetLocationID() > num_locations)
470                 {
471                     StreamString id_str;
472                     BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(),
473                                                            cur_bp_id.GetLocationID());
474                     i = valid_ids->Size() + 1;
475                     result.AppendErrorWithFormat ("'%s' is not a currently valid breakpoint/location id.\n",
476                                                  id_str.GetData());
477                     result.SetStatus (eReturnStatusFailed);
478                 }
479             }
480             else
481             {
482                 i = valid_ids->Size() + 1;
483                 result.AppendErrorWithFormat ("'%d' is not a currently valid breakpoint id.\n", cur_bp_id.GetBreakpointID());
484                 result.SetStatus (eReturnStatusFailed);
485             }
486         }
487     }
488 }
489 
490 //-------------------------------------------------------------------------
491 // CommandObjectBreakpointList::Options
492 //-------------------------------------------------------------------------
493 
494 CommandObjectBreakpointList::CommandOptions::CommandOptions() :
495     Options (),
496     m_level (lldb::eDescriptionLevelFull)  // Breakpoint List defaults to brief descriptions
497 {
498     BuildValidOptionSets();
499 }
500 
501 CommandObjectBreakpointList::CommandOptions::~CommandOptions ()
502 {
503 }
504 
505 lldb::OptionDefinition
506 CommandObjectBreakpointList::CommandOptions::g_option_table[] =
507 {
508     { 0, false, "brief",    'b', no_argument, NULL, 0, NULL,
509         "Give a brief description of the breakpoint (no location info)."},
510 
511     // FIXME: We need to add an "internal" command, and then add this sort of thing to it.
512     // But I need to see it for now, and don't want to wait.
513     { 0, false, "internal", 'i', no_argument, NULL, 0, NULL,
514         "Show debugger internal breakpoints" },
515 
516     { 1, false, "full",    'f', no_argument, NULL, 0, NULL,
517         "Give a full description of the breakpoint and its locations."},
518     // DITTO FIXME
519     { 1, false, "internal", 'i', no_argument, NULL, 0, NULL,
520         "Show debugger internal breakpoints" },
521 
522     { 2, false, "verbose", 'v', no_argument, NULL, 0, NULL,
523         "Explain everything we know about the breakpoint (for debugging debugger bugs)." },
524     // DITTO FIXME
525     { 2, false, "internal", 'i', no_argument, NULL, 0, NULL,
526         "Show debugger internal breakpoints" },
527 
528     { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
529 };
530 
531 const lldb::OptionDefinition*
532 CommandObjectBreakpointList::CommandOptions::GetDefinitions ()
533 {
534     return g_option_table;
535 }
536 
537 Error
538 CommandObjectBreakpointList::CommandOptions::SetOptionValue (int option_idx, const char *option_arg)
539 {
540     Error error;
541     char short_option = (char) m_getopt_table[option_idx].val;
542 
543     switch (short_option)
544     {
545         case 'b':
546             m_level = lldb::eDescriptionLevelBrief;
547             break;
548         case 'f':
549             m_level = lldb::eDescriptionLevelFull;
550             break;
551         case 'v':
552             m_level = lldb::eDescriptionLevelVerbose;
553             break;
554         case 'i':
555             m_internal = true;
556             break;
557         default:
558             error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
559             break;
560     }
561 
562     return error;
563 }
564 
565 void
566 CommandObjectBreakpointList::CommandOptions::ResetOptionValues ()
567 {
568     Options::ResetOptionValues();
569 
570     m_level = lldb::eDescriptionLevelFull;
571     m_internal = false;
572 }
573 
574 //-------------------------------------------------------------------------
575 // CommandObjectBreakpointList
576 //-------------------------------------------------------------------------
577 
578 CommandObjectBreakpointList::CommandObjectBreakpointList () :
579     CommandObject ("breakpoint list",
580                      "List some or all breakpoints at configurable levels of detail.",
581                      "breakpoint list [<breakpoint-id>]")
582 {
583 }
584 
585 CommandObjectBreakpointList::~CommandObjectBreakpointList ()
586 {
587 }
588 
589 Options *
590 CommandObjectBreakpointList::GetOptions ()
591 {
592     return &m_options;
593 }
594 
595 bool
596 CommandObjectBreakpointList::Execute
597 (
598     Args& args,
599     CommandContext *context,
600     CommandInterpreter *interpreter,
601     CommandReturnObject &result
602 )
603 {
604     Target *target = context->GetTarget();
605     if (target == NULL)
606     {
607         result.AppendError ("Invalid target, set executable file using 'file' command.");
608         result.SetStatus (eReturnStatusSuccessFinishNoResult);
609         return true;
610     }
611 
612     const BreakpointList &breakpoints = target->GetBreakpointList(m_options.m_internal);
613     size_t num_breakpoints = breakpoints.GetSize();
614 
615     if (num_breakpoints == 0)
616     {
617         result.AppendMessage ("No breakpoints currently set.");
618         result.SetStatus (eReturnStatusSuccessFinishNoResult);
619         return true;
620     }
621 
622     StreamString &output_stream = result.GetOutputStream();
623 
624     if (args.GetArgumentCount() == 0)
625     {
626         // No breakpoint selected; show info about all currently set breakpoints.
627         result.AppendMessage ("Current breakpoints:");
628         for (int i = 0; i < num_breakpoints; ++i)
629         {
630             Breakpoint *breakpoint = breakpoints.GetBreakpointByIndex (i).get();
631             AddBreakpointDescription (context, &output_stream, breakpoint, m_options.m_level);
632         }
633         result.SetStatus (eReturnStatusSuccessFinishNoResult);
634     }
635     else
636     {
637         // Particular breakpoints selected; show info about that breakpoint.
638         BreakpointIDList valid_bp_ids;
639         CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (args, target, result, &valid_bp_ids);
640 
641         if (result.Succeeded())
642         {
643             for (int i = 0; i < valid_bp_ids.Size(); ++i)
644             {
645                 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
646                 Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
647                 AddBreakpointDescription (context, &output_stream, breakpoint, m_options.m_level);
648             }
649             result.SetStatus (eReturnStatusSuccessFinishNoResult);
650         }
651         else
652         {
653             result.AppendError ("Invalid breakpoint id.");
654             result.SetStatus (eReturnStatusFailed);
655         }
656     }
657 
658     return result.Succeeded();
659 }
660 
661 //-------------------------------------------------------------------------
662 // CommandObjectBreakpointEnable
663 //-------------------------------------------------------------------------
664 
665 CommandObjectBreakpointEnable::CommandObjectBreakpointEnable () :
666     CommandObject ("enable",
667                      "Enables the specified disabled breakpoint(s).  If no breakpoints are specified, enables all of them.",
668                      "breakpoint enable [<breakpoint-id> | <breakpoint-id-list>]")
669 {
670     // This command object can either be called via 'enable' or 'breakpoint enable'.  Because it has two different
671     // potential invocation methods, we need to be a little tricky about generating the syntax string.
672     //StreamString tmp_string;
673     //tmp_string.Printf ("%s <breakpoint-id>", GetCommandName());
674     //m_cmd_syntax.assign (tmp_string.GetData(), tmp_string.GetSize());
675 }
676 
677 
678 CommandObjectBreakpointEnable::~CommandObjectBreakpointEnable ()
679 {
680 }
681 
682 
683 bool
684 CommandObjectBreakpointEnable::Execute (Args& args, CommandContext *context,
685                                           CommandInterpreter *interpreter, CommandReturnObject &result)
686 {
687     Target *target = context->GetTarget();
688     if (target == NULL)
689     {
690         result.AppendError ("Invalid target, set executable file using 'file' command.");
691         result.SetStatus (eReturnStatusFailed);
692         return false;
693     }
694 
695     const BreakpointList &breakpoints = target->GetBreakpointList();
696     size_t num_breakpoints = breakpoints.GetSize();
697 
698     if (num_breakpoints == 0)
699     {
700         result.AppendError ("No breakpoints exist to be enabled.");
701         result.SetStatus (eReturnStatusFailed);
702         return false;
703     }
704 
705     if (args.GetArgumentCount() == 0)
706     {
707         // No breakpoint selected; enable all currently set breakpoints.
708         target->EnableAllBreakpoints ();
709         result.AppendMessageWithFormat ("All breakpoints enabled. (%d breakpoints)\n", num_breakpoints);
710         result.SetStatus (eReturnStatusSuccessFinishNoResult);
711     }
712     else
713     {
714         // Particular breakpoint selected; enable that breakpoint.
715         BreakpointIDList valid_bp_ids;
716         CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (args, target, result, &valid_bp_ids);
717 
718         if (result.Succeeded())
719         {
720             int enable_count = 0;
721             int loc_count = 0;
722             for (int i = 0; i < valid_bp_ids.Size(); ++i)
723             {
724                 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
725 
726                 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
727                 {
728                     Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
729                     if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
730                     {
731                         BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get();
732                         if (location)
733                         {
734                             location->SetEnabled (true);
735                             breakpoint->SetEnabled (true);
736                             ++loc_count;
737                         }
738                     }
739                     else
740                     {
741                         target->EnableBreakpointByID (cur_bp_id.GetBreakpointID());
742                         ++enable_count;
743 
744                         int num_locations = breakpoint->GetNumLocations ();
745                         for (int j = 0; j < num_locations; ++j)
746                         {
747                             BreakpointLocation *cur_loc = breakpoint->GetLocationAtIndex(j).get();
748                             if (cur_loc)
749                                 cur_loc->SetEnabled (true);
750                         }
751                     }
752                 }
753             }
754             result.AppendMessageWithFormat ("%d breakpoints enabled.\n", enable_count + loc_count);
755             result.SetStatus (eReturnStatusSuccessFinishNoResult);
756         }
757     }
758 
759     return result.Succeeded();
760 }
761 
762 //-------------------------------------------------------------------------
763 // CommandObjectBreakpointDisable
764 //-------------------------------------------------------------------------
765 
766 CommandObjectBreakpointDisable::CommandObjectBreakpointDisable () :
767     CommandObject ("disable",
768                    "Disables the specified breakpoint(s) without removing it/them.  If no breakpoints are specified, disables them all.",
769                    "disable [<breakpoint-id> | <breakpoint-id-list>]")
770 {
771     // This command object can either be called via 'enable' or 'breakpoint enable'.  Because it has two different
772     // potential invocation methods, we need to be a little tricky about generating the syntax string.
773     //StreamString tmp_string;
774     //tmp_string.Printf ("%s <breakpoint-id>", GetCommandName());
775     //m_cmd_syntax.assign(tmp_string.GetData(), tmp_string.GetSize());
776 }
777 
778 CommandObjectBreakpointDisable::~CommandObjectBreakpointDisable ()
779 {
780 }
781 
782 bool
783 CommandObjectBreakpointDisable::Execute (Args& args, CommandContext *context,
784                                            CommandInterpreter *interpreter, CommandReturnObject &result)
785 {
786     Target *target = context->GetTarget();
787     if (target == NULL)
788     {
789         result.AppendError ("Invalid target, set executable file using 'file' command.");
790         result.SetStatus (eReturnStatusFailed);
791         return false;
792     }
793 
794     const BreakpointList &breakpoints = target->GetBreakpointList();
795     size_t num_breakpoints = breakpoints.GetSize();
796 
797     if (num_breakpoints == 0)
798     {
799         result.AppendError ("No breakpoints exist to be disabled.");
800         result.SetStatus (eReturnStatusFailed);
801         return false;
802     }
803 
804     if (args.GetArgumentCount() == 0)
805     {
806         // No breakpoint selected; disable all currently set breakpoints.
807         target->DisableAllBreakpoints ();
808         result.AppendMessageWithFormat ("All breakpoints disabled. (%d breakpoints)\n", num_breakpoints);
809         result.SetStatus (eReturnStatusSuccessFinishNoResult);
810     }
811     else
812     {
813         // Particular breakpoint selected; disable that breakpoint.
814         BreakpointIDList valid_bp_ids;
815 
816         CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (args, target, result, &valid_bp_ids);
817 
818         if (result.Succeeded())
819         {
820             int disable_count = 0;
821             int loc_count = 0;
822             for (int i = 0; i < valid_bp_ids.Size(); ++i)
823             {
824                 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
825 
826                 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
827                 {
828                     Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
829                     if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
830                     {
831                         BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get();
832                         if (location)
833                         {
834                             location->SetEnabled (false);
835                             ++loc_count;
836                         }
837                     }
838                     else
839                     {
840                         target->DisableBreakpointByID (cur_bp_id.GetBreakpointID());
841                         ++disable_count;
842 
843                         int num_locations = breakpoint->GetNumLocations();
844                         for (int j = 0; j < num_locations; ++j)
845                         {
846                             BreakpointLocation *cur_loc = breakpoint->GetLocationAtIndex(j).get();
847                             if (cur_loc)
848                                 cur_loc->SetEnabled (false);
849                         }
850                     }
851                 }
852             }
853             result.AppendMessageWithFormat ("%d breakpoints disabled.\n", disable_count + loc_count);
854             result.SetStatus (eReturnStatusSuccessFinishNoResult);
855         }
856     }
857 
858     return result.Succeeded();
859 }
860 
861 //-------------------------------------------------------------------------
862 // CommandObjectBreakpointDelete
863 //-------------------------------------------------------------------------
864 
865 CommandObjectBreakpointDelete::CommandObjectBreakpointDelete() :
866     CommandObject ("breakpoint delete",
867                    "Delete the specified breakpoint(s).  If no breakpoints are specified, deletes them all.",
868                    "breakpoint delete [<breakpoint-id> | <breakpoint-id-list>]")
869 {
870 }
871 
872 
873 CommandObjectBreakpointDelete::~CommandObjectBreakpointDelete ()
874 {
875 }
876 
877 bool
878 CommandObjectBreakpointDelete::Execute (Args& args, CommandContext *context,
879                                           CommandInterpreter *interpreter, CommandReturnObject &result)
880 {
881     Target *target = context->GetTarget();
882     if (target == NULL)
883     {
884         result.AppendError ("Invalid target, set executable file using 'file' command.");
885         result.SetStatus (eReturnStatusFailed);
886         return false;
887     }
888 
889     const BreakpointList &breakpoints = target->GetBreakpointList();
890     size_t num_breakpoints = breakpoints.GetSize();
891 
892     if (num_breakpoints == 0)
893     {
894         result.AppendError ("No breakpoints exist to be deleted.");
895         result.SetStatus (eReturnStatusFailed);
896         return false;
897     }
898 
899     if (args.GetArgumentCount() == 0)
900     {
901         // No breakpoint selected; disable all currently set breakpoints.
902         if (args.GetArgumentCount() != 0)
903         {
904             result.AppendErrorWithFormat ("Specify breakpoints to delete with the -i option.\n");
905             result.SetStatus (eReturnStatusFailed);
906             return false;
907         }
908 
909         target->RemoveAllBreakpoints ();
910         result.AppendMessageWithFormat ("All breakpoints removed. (%d breakpoints)\n", num_breakpoints);
911         result.SetStatus (eReturnStatusSuccessFinishNoResult);
912     }
913     else
914     {
915         // Particular breakpoint selected; disable that breakpoint.
916         BreakpointIDList valid_bp_ids;
917         CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (args, target, result, &valid_bp_ids);
918 
919         if (result.Succeeded())
920         {
921             int delete_count = 0;
922             int disable_count = 0;
923             for (int i = 0; i < valid_bp_ids.Size(); ++i)
924             {
925                 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
926 
927                 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
928                 {
929                     if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
930                     {
931                         Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
932                         BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get();
933                         // It makes no sense to try to delete individual locations, so we disable them instead.
934                         if (location)
935                         {
936                             location->SetEnabled (false);
937                             ++disable_count;
938                         }
939                     }
940                     else
941                     {
942                         target->RemoveBreakpointByID (cur_bp_id.GetBreakpointID());
943                         ++delete_count;
944                     }
945                 }
946             }
947             result.AppendMessageWithFormat ("%d breakpoints deleted; %d breakpoint locations disabled.\n",
948                                            delete_count, disable_count);
949             result.SetStatus (eReturnStatusSuccessFinishNoResult);
950         }
951     }
952     return result.Succeeded();
953 }
954