Fix/unify the spelling of Objective-C.
[lldb.git] / lldb / source / Commands / CommandObjectBreakpoint.cpp
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 // C Includes
11 // C++ Includes
12 #include <vector>
13
14 // Other libraries and framework includes
15 // Project includes
16 #include "CommandObjectBreakpoint.h"
17 #include "CommandObjectBreakpointCommand.h"
18 #include "lldb/Breakpoint/Breakpoint.h"
19 #include "lldb/Breakpoint/BreakpointIDList.h"
20 #include "lldb/Breakpoint/BreakpointLocation.h"
21 #include "lldb/Host/OptionParser.h"
22 #include "lldb/Interpreter/CommandCompletions.h"
23 #include "lldb/Interpreter/CommandInterpreter.h"
24 #include "lldb/Interpreter/CommandReturnObject.h"
25 #include "lldb/Interpreter/OptionArgParser.h"
26 #include "lldb/Interpreter/OptionValueBoolean.h"
27 #include "lldb/Interpreter/OptionValueString.h"
28 #include "lldb/Interpreter/OptionValueUInt64.h"
29 #include "lldb/Interpreter/Options.h"
30 #include "lldb/Target/Language.h"
31 #include "lldb/Target/StackFrame.h"
32 #include "lldb/Target/Target.h"
33 #include "lldb/Target/Thread.h"
34 #include "lldb/Target/ThreadSpec.h"
35 #include "lldb/Utility/RegularExpression.h"
36 #include "lldb/Utility/StreamString.h"
37
38 using namespace lldb;
39 using namespace lldb_private;
40
41 static void AddBreakpointDescription(Stream *s, Breakpoint *bp,
42                                      lldb::DescriptionLevel level) {
43   s->IndentMore();
44   bp->GetDescription(s, level, true);
45   s->IndentLess();
46   s->EOL();
47 }
48
49 //-------------------------------------------------------------------------
50 // Modifiable Breakpoint Options
51 //-------------------------------------------------------------------------
52 #pragma mark Modify::CommandOptions
53 static OptionDefinition g_breakpoint_modify_options[] = {
54     // clang-format off
55   { LLDB_OPT_SET_1, false, "ignore-count", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount,       "Set the number of times this breakpoint is skipped before stopping." },
56   { LLDB_OPT_SET_1, false, "one-shot",     'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean,     "The breakpoint is deleted the first time it stop causes a stop." },
57   { LLDB_OPT_SET_1, false, "thread-index", 'x', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose index matches this argument." },
58   { LLDB_OPT_SET_1, false, "thread-id",    't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadID,    "The breakpoint stops only for the thread whose TID matches this argument." },
59   { LLDB_OPT_SET_1, false, "thread-name",  'T', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadName,  "The breakpoint stops only for the thread whose thread name matches this argument." },
60   { LLDB_OPT_SET_1, false, "queue-name",   'q', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeQueueName,   "The breakpoint stops only for threads in the queue whose name is given by this argument." },
61   { LLDB_OPT_SET_1, false, "condition",    'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression,  "The breakpoint stops only if this condition expression evaluates to true." },
62   { LLDB_OPT_SET_1, false, "auto-continue",'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean,     "The breakpoint will auto-continue after running its commands." },
63   { LLDB_OPT_SET_2, false, "enable",       'e', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,        "Enable the breakpoint." },
64   { LLDB_OPT_SET_3, false, "disable",      'd', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,        "Disable the breakpoint." },
65   { LLDB_OPT_SET_4, false, "command",      'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCommand,     "A command to run when the breakpoint is hit, can be provided more than once, the commands will get run in order left to right." },
66     // clang-format on
67 };
68 class lldb_private::BreakpointOptionGroup : public OptionGroup
69 {
70 public:
71   BreakpointOptionGroup() :
72           OptionGroup(),
73           m_bp_opts(false) {}
74   
75   ~BreakpointOptionGroup() override = default;
76
77   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
78     return llvm::makeArrayRef(g_breakpoint_modify_options);
79   }
80
81   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
82                           ExecutionContext *execution_context) override {
83     Status error;
84     const int short_option = g_breakpoint_modify_options[option_idx].short_option;
85
86     switch (short_option) {
87     case 'c':
88       // Normally an empty breakpoint condition marks is as unset. But we need
89       // to say it was passed in.
90       m_bp_opts.SetCondition(option_arg.str().c_str());
91       m_bp_opts.m_set_flags.Set(BreakpointOptions::eCondition);
92       break;
93     case 'C':
94       m_commands.push_back(option_arg);
95       break;
96     case 'd':
97       m_bp_opts.SetEnabled(false);
98       break;
99     case 'e':
100       m_bp_opts.SetEnabled(true);
101       break;
102     case 'G': {
103       bool value, success;
104       value = OptionArgParser::ToBoolean(option_arg, false, &success);
105       if (success) {
106         m_bp_opts.SetAutoContinue(value);
107       } else
108         error.SetErrorStringWithFormat(
109             "invalid boolean value '%s' passed for -G option",
110             option_arg.str().c_str());
111     }
112     break;
113     case 'i':
114     {
115       uint32_t ignore_count;
116       if (option_arg.getAsInteger(0, ignore_count))
117         error.SetErrorStringWithFormat("invalid ignore count '%s'",
118                                        option_arg.str().c_str());
119       else
120         m_bp_opts.SetIgnoreCount(ignore_count);
121     }
122     break;
123     case 'o': {
124       bool value, success;
125       value = OptionArgParser::ToBoolean(option_arg, false, &success);
126       if (success) {
127         m_bp_opts.SetOneShot(value);
128       } else
129         error.SetErrorStringWithFormat(
130             "invalid boolean value '%s' passed for -o option",
131             option_arg.str().c_str());
132     } break;
133     case 't':
134     {
135       lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID;
136       if (option_arg[0] != '\0') {
137         if (option_arg.getAsInteger(0, thread_id))
138           error.SetErrorStringWithFormat("invalid thread id string '%s'",
139                                          option_arg.str().c_str());
140       }
141       m_bp_opts.SetThreadID(thread_id);
142     }
143     break;
144     case 'T':
145       m_bp_opts.GetThreadSpec()->SetName(option_arg.str().c_str());
146       break;
147     case 'q':
148       m_bp_opts.GetThreadSpec()->SetQueueName(option_arg.str().c_str());
149       break;
150     case 'x':
151     {
152       uint32_t thread_index = UINT32_MAX;
153       if (option_arg[0] != '\n') {
154         if (option_arg.getAsInteger(0, thread_index))
155           error.SetErrorStringWithFormat("invalid thread index string '%s'",
156                                          option_arg.str().c_str());
157       }
158       m_bp_opts.GetThreadSpec()->SetIndex(thread_index);
159     }
160     break;
161     default:
162       error.SetErrorStringWithFormat("unrecognized option '%c'",
163                                      short_option);
164       break;
165     }
166
167     return error;
168   }
169
170   void OptionParsingStarting(ExecutionContext *execution_context) override {
171     m_bp_opts.Clear();
172     m_commands.clear();
173   }
174   
175   Status OptionParsingFinished(ExecutionContext *execution_context) override {
176     if (!m_commands.empty())
177     {
178       if (!m_commands.empty())
179       {
180           auto cmd_data = llvm::make_unique<BreakpointOptions::CommandData>();
181         
182           for (std::string &str : m_commands)
183             cmd_data->user_source.AppendString(str); 
184
185           cmd_data->stop_on_error = true;
186           m_bp_opts.SetCommandDataCallback(cmd_data);
187       }
188     }
189     return Status();
190   }
191   
192   const BreakpointOptions &GetBreakpointOptions()
193   {
194     return m_bp_opts;
195   }
196
197   std::vector<std::string> m_commands;
198   BreakpointOptions m_bp_opts;
199
200 };
201 static OptionDefinition g_breakpoint_dummy_options[] = {
202     // clang-format off
203   { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Act on Dummy breakpoints - i.e. breakpoints set before a file is provided, "
204   "which prime new targets." },
205     // clang-format on
206 };
207
208 class BreakpointDummyOptionGroup : public OptionGroup
209 {
210 public:
211   BreakpointDummyOptionGroup() :
212           OptionGroup() {}
213   
214   ~BreakpointDummyOptionGroup() override = default;
215
216   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
217     return llvm::makeArrayRef(g_breakpoint_dummy_options);
218   }
219
220   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
221                           ExecutionContext *execution_context) override {
222     Status error;
223     const int short_option = g_breakpoint_modify_options[option_idx].short_option;
224
225     switch (short_option) {
226       case 'D':
227         m_use_dummy = true;
228         break;
229     default:
230       error.SetErrorStringWithFormat("unrecognized option '%c'",
231                                      short_option);
232       break;
233     }
234
235     return error;
236   }
237
238   void OptionParsingStarting(ExecutionContext *execution_context) override {
239     m_use_dummy = false;
240   }
241
242   bool m_use_dummy;
243
244 };
245
246 // If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to
247 // update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately.
248 #define LLDB_OPT_FILE (LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2)
249 #define LLDB_OPT_NOT_10 (LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10)
250 #define LLDB_OPT_SKIP_PROLOGUE (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8))
251 #define LLDB_OPT_OFFSET_APPLIES (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8))
252 #define LLDB_OPT_MOVE_TO_NEAREST_CODE (LLDB_OPT_SET_1 | LLDB_OPT_SET_9)
253 #define LLDB_OPT_EXPR_LANGUAGE (LLDB_OPT_SET_FROM_TO(3, 8))
254
255 static OptionDefinition g_breakpoint_set_options[] = {
256     // clang-format off
257   { LLDB_OPT_NOT_10,               false, "shlib",                  's', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eModuleCompletion,     eArgTypeShlibName,           "Set the breakpoint only in this shared library.  Can repeat this option "
258   "multiple times to specify multiple shared libraries." },
259   { LLDB_OPT_SET_ALL,              false, "hardware",               'H', OptionParser::eNoArgument,       nullptr, nullptr, 0,                                         eArgTypeNone,                "Require the breakpoint to use hardware breakpoints." },
260   { LLDB_OPT_FILE,                 false, "file",                   'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,            "Specifies the source file in which to set this breakpoint.  Note, by default "
261   "lldb only looks for files that are #included if they use the standard include "
262   "file extensions.  To set breakpoints on .c/.cpp/.m/.mm files that are "
263   "#included, set target.inline-breakpoint-strategy to \"always\"." },
264   { LLDB_OPT_SET_1,                true,  "line",                   'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeLineNum,             "Specifies the line number on which to set this breakpoint." },
265
266   // Comment out this option for the moment, as we don't actually use it, but
267   // will in the future. This way users won't see it, but the infrastructure is
268   // left in place.
269   //    { 0, false, "column",     'C', OptionParser::eRequiredArgument, nullptr, "<column>",
270   //    "Set the breakpoint by source location at this particular column."},
271
272   { LLDB_OPT_SET_2,                true,  "address",                'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeAddressOrExpression, "Set the breakpoint at the specified address.  If the address maps uniquely to "
273   "a particular binary, then the address will be converted to a \"file\" "
274   "address, so that the breakpoint will track that binary+offset no matter where "
275   "the binary eventually loads.  Alternately, if you also specify the module - "
276   "with the -s option - then the address will be treated as a file address in "
277   "that module, and resolved accordingly.  Again, this will allow lldb to track "
278   "that offset on subsequent reloads.  The module need not have been loaded at "
279   "the time you specify this breakpoint, and will get resolved when the module "
280   "is loaded." },
281   { LLDB_OPT_SET_3,                true,  "name",                   'n', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion,     eArgTypeFunctionName,        "Set the breakpoint by function name.  Can be repeated multiple times to make "
282   "one breakpoint for multiple names" },
283   { LLDB_OPT_SET_9,                false, "source-regexp-function", 'X', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion,     eArgTypeFunctionName,        "When used with '-p' limits the source regex to source contained in the named "
284   "functions.  Can be repeated multiple times." },
285   { LLDB_OPT_SET_4,                true,  "fullname",               'F', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion,     eArgTypeFullName,            "Set the breakpoint by fully qualified function names. For C++ this means "
286   "namespaces and all arguments, and for Objective-C this means a full function "
287   "prototype with class and selector.  Can be repeated multiple times to make "
288   "one breakpoint for multiple names." },
289   { LLDB_OPT_SET_5,                true,  "selector",               'S', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeSelector,            "Set the breakpoint by ObjC selector name. Can be repeated multiple times to "
290   "make one breakpoint for multiple Selectors." },
291   { LLDB_OPT_SET_6,                true,  "method",                 'M', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeMethod,              "Set the breakpoint by C++ method names.  Can be repeated multiple times to "
292   "make one breakpoint for multiple methods." },
293   { LLDB_OPT_SET_7,                true,  "func-regex",             'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeRegularExpression,   "Set the breakpoint by function name, evaluating a regular-expression to find "
294   "the function name(s)." },
295   { LLDB_OPT_SET_8,                true,  "basename",               'b', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion,     eArgTypeFunctionName,        "Set the breakpoint by function basename (C++ namespaces and arguments will be "
296   "ignored).  Can be repeated multiple times to make one breakpoint for multiple "
297   "symbols." },
298   { LLDB_OPT_SET_9,                true,  "source-pattern-regexp",  'p', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeRegularExpression,   "Set the breakpoint by specifying a regular expression which is matched "
299   "against the source text in a source file or files specified with the -f "
300   "option.  The -f option can be specified more than once.  If no source files "
301   "are specified, uses the current \"default source file\".  If you want to "
302   "match against all source files, pass the \"--all-files\" option." },
303   { LLDB_OPT_SET_9,                false, "all-files",              'A', OptionParser::eNoArgument,       nullptr, nullptr, 0,                                         eArgTypeNone,                "All files are searched for source pattern matches." },
304   { LLDB_OPT_SET_10,               true,  "language-exception",     'E', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeLanguage,            "Set the breakpoint on exceptions thrown by the specified language (without "
305   "options, on throw but not catch.)" },
306   { LLDB_OPT_SET_10,               false, "on-throw",               'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeBoolean,             "Set the breakpoint on exception throW." },
307   { LLDB_OPT_SET_10,               false, "on-catch",               'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeBoolean,             "Set the breakpoint on exception catcH." },
308
309   //  Don't add this option till it actually does something useful...
310   //    { LLDB_OPT_SET_10, false, "exception-typename", 'O', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeTypeName,
311   //        "The breakpoint will only stop if an exception Object of this type is thrown.  Can be repeated multiple times to stop for multiple object types" },
312
313   { LLDB_OPT_EXPR_LANGUAGE,        false, "language",               'L', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeLanguage,            "Specifies the Language to use when interpreting the breakpoint's expression "
314   "(note: currently only implemented for setting breakpoints on identifiers).  "
315   "If not set the target.language setting is used." },
316   { LLDB_OPT_SKIP_PROLOGUE,        false, "skip-prologue",          'K', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeBoolean,             "sKip the prologue if the breakpoint is at the beginning of a function.  "
317   "If not set the target.skip-prologue setting is used." },
318   { LLDB_OPT_SET_ALL,              false, "breakpoint-name",        'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeBreakpointName,      "Adds this to the list of names for this breakpoint." },
319   { LLDB_OPT_OFFSET_APPLIES,       false, "address-slide",          'R', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeAddress,             "Add the specified offset to whatever address(es) the breakpoint resolves to.  "
320   "At present this applies the offset directly as given, and doesn't try to align it to instruction boundaries." },
321   { LLDB_OPT_MOVE_TO_NEAREST_CODE, false, "move-to-nearest-code", 'm', OptionParser::eRequiredArgument,   nullptr, nullptr, 0,                                         eArgTypeBoolean,             "Move breakpoints to nearest code. If not set the target.move-to-nearest-code "
322   "setting is used." },
323     // clang-format on
324 };
325
326 //-------------------------------------------------------------------------
327 // CommandObjectBreakpointSet
328 //-------------------------------------------------------------------------
329
330 class CommandObjectBreakpointSet : public CommandObjectParsed {
331 public:
332   typedef enum BreakpointSetType {
333     eSetTypeInvalid,
334     eSetTypeFileAndLine,
335     eSetTypeAddress,
336     eSetTypeFunctionName,
337     eSetTypeFunctionRegexp,
338     eSetTypeSourceRegexp,
339     eSetTypeException
340   } BreakpointSetType;
341
342   CommandObjectBreakpointSet(CommandInterpreter &interpreter)
343       : CommandObjectParsed(
344             interpreter, "breakpoint set",
345             "Sets a breakpoint or set of breakpoints in the executable.",
346             "breakpoint set <cmd-options>"),
347         m_bp_opts(), m_options() {
348           // We're picking up all the normal options, commands and disable.
349           m_all_options.Append(&m_bp_opts, 
350                                LLDB_OPT_SET_1 | LLDB_OPT_SET_3 | LLDB_OPT_SET_4, 
351                                LLDB_OPT_SET_ALL);
352           m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
353           m_all_options.Append(&m_options);
354           m_all_options.Finalize();
355         }
356
357   ~CommandObjectBreakpointSet() override = default;
358
359   Options *GetOptions() override { return &m_all_options; }
360
361   class CommandOptions : public OptionGroup {
362   public:
363     CommandOptions()
364         : OptionGroup(), m_condition(), m_filenames(), m_line_num(0), m_column(0),
365           m_func_names(), m_func_name_type_mask(eFunctionNameTypeNone),
366           m_func_regexp(), m_source_text_regexp(), m_modules(), m_load_addr(),
367           m_catch_bp(false), m_throw_bp(true), m_hardware(false),
368           m_exception_language(eLanguageTypeUnknown),
369           m_language(lldb::eLanguageTypeUnknown),
370           m_skip_prologue(eLazyBoolCalculate),
371           m_all_files(false), m_move_to_nearest_code(eLazyBoolCalculate) {}
372
373     ~CommandOptions() override = default;
374
375     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
376                           ExecutionContext *execution_context) override {
377       Status error;
378       const int short_option = g_breakpoint_set_options[option_idx].short_option;
379
380       switch (short_option) {
381       case 'a': {
382         m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg,
383                                                  LLDB_INVALID_ADDRESS, &error);
384       } break;
385
386       case 'A':
387         m_all_files = true;
388         break;
389
390       case 'b':
391         m_func_names.push_back(option_arg);
392         m_func_name_type_mask |= eFunctionNameTypeBase;
393         break;
394
395       case 'C':
396         if (option_arg.getAsInteger(0, m_column))
397           error.SetErrorStringWithFormat("invalid column number: %s",
398                                          option_arg.str().c_str());
399         break;
400
401       case 'E': {
402         LanguageType language = Language::GetLanguageTypeFromString(option_arg);
403
404         switch (language) {
405         case eLanguageTypeC89:
406         case eLanguageTypeC:
407         case eLanguageTypeC99:
408         case eLanguageTypeC11:
409           m_exception_language = eLanguageTypeC;
410           break;
411         case eLanguageTypeC_plus_plus:
412         case eLanguageTypeC_plus_plus_03:
413         case eLanguageTypeC_plus_plus_11:
414         case eLanguageTypeC_plus_plus_14:
415           m_exception_language = eLanguageTypeC_plus_plus;
416           break;
417         case eLanguageTypeObjC:
418           m_exception_language = eLanguageTypeObjC;
419           break;
420         case eLanguageTypeObjC_plus_plus:
421           error.SetErrorStringWithFormat(
422               "Set exception breakpoints separately for c++ and objective-c");
423           break;
424         case eLanguageTypeUnknown:
425           error.SetErrorStringWithFormat(
426               "Unknown language type: '%s' for exception breakpoint",
427               option_arg.str().c_str());
428           break;
429         default:
430           error.SetErrorStringWithFormat(
431               "Unsupported language type: '%s' for exception breakpoint",
432               option_arg.str().c_str());
433         }
434       } break;
435
436       case 'f':
437         m_filenames.AppendIfUnique(FileSpec(option_arg, false));
438         break;
439
440       case 'F':
441         m_func_names.push_back(option_arg);
442         m_func_name_type_mask |= eFunctionNameTypeFull;
443         break;
444         
445       case 'h': {
446         bool success;
447         m_catch_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
448         if (!success)
449           error.SetErrorStringWithFormat(
450               "Invalid boolean value for on-catch option: '%s'",
451               option_arg.str().c_str());
452       } break;
453
454       case 'H':
455         m_hardware = true;
456         break;
457
458       case 'K': {
459         bool success;
460         bool value;
461         value = OptionArgParser::ToBoolean(option_arg, true, &success);
462         if (value)
463           m_skip_prologue = eLazyBoolYes;
464         else
465           m_skip_prologue = eLazyBoolNo;
466
467         if (!success)
468           error.SetErrorStringWithFormat(
469               "Invalid boolean value for skip prologue option: '%s'",
470               option_arg.str().c_str());
471       } break;
472
473       case 'l':
474         if (option_arg.getAsInteger(0, m_line_num))
475           error.SetErrorStringWithFormat("invalid line number: %s.",
476                                          option_arg.str().c_str());
477         break;
478
479       case 'L':
480         m_language = Language::GetLanguageTypeFromString(option_arg);
481         if (m_language == eLanguageTypeUnknown)
482           error.SetErrorStringWithFormat(
483               "Unknown language type: '%s' for breakpoint",
484               option_arg.str().c_str());
485         break;
486
487       case 'm': {
488         bool success;
489         bool value;
490         value = OptionArgParser::ToBoolean(option_arg, true, &success);
491         if (value)
492           m_move_to_nearest_code = eLazyBoolYes;
493         else
494           m_move_to_nearest_code = eLazyBoolNo;
495
496         if (!success)
497           error.SetErrorStringWithFormat(
498               "Invalid boolean value for move-to-nearest-code option: '%s'",
499               option_arg.str().c_str());
500         break;
501       }
502
503       case 'M':
504         m_func_names.push_back(option_arg);
505         m_func_name_type_mask |= eFunctionNameTypeMethod;
506         break;
507
508       case 'n':
509         m_func_names.push_back(option_arg);
510         m_func_name_type_mask |= eFunctionNameTypeAuto;
511         break;
512
513       case 'N': {
514         if (BreakpointID::StringIsBreakpointName(option_arg, error))
515           m_breakpoint_names.push_back(option_arg);
516         else
517           error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
518                                          option_arg.str().c_str());
519         break;
520       }
521
522       case 'R': {
523         lldb::addr_t tmp_offset_addr;
524         tmp_offset_addr = OptionArgParser::ToAddress(execution_context,
525                                                      option_arg, 0, &error);
526         if (error.Success())
527           m_offset_addr = tmp_offset_addr;
528       } break;
529
530       case 'O':
531         m_exception_extra_args.AppendArgument("-O");
532         m_exception_extra_args.AppendArgument(option_arg);
533         break;
534
535       case 'p':
536         m_source_text_regexp.assign(option_arg);
537         break;
538
539       case 'r':
540         m_func_regexp.assign(option_arg);
541         break;
542
543       case 's':
544         m_modules.AppendIfUnique(FileSpec(option_arg, false));
545         break;
546
547       case 'S':
548         m_func_names.push_back(option_arg);
549         m_func_name_type_mask |= eFunctionNameTypeSelector;
550         break;
551
552       case 'w': {
553         bool success;
554         m_throw_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
555         if (!success)
556           error.SetErrorStringWithFormat(
557               "Invalid boolean value for on-throw option: '%s'",
558               option_arg.str().c_str());
559       } break;
560
561       case 'X':
562         m_source_regex_func_names.insert(option_arg);
563         break;
564
565       default:
566         error.SetErrorStringWithFormat("unrecognized option '%c'",
567                                        short_option);
568         break;
569       }
570
571       return error;
572     }
573
574     void OptionParsingStarting(ExecutionContext *execution_context) override {
575       m_filenames.Clear();
576       m_line_num = 0;
577       m_column = 0;
578       m_func_names.clear();
579       m_func_name_type_mask = eFunctionNameTypeNone;
580       m_func_regexp.clear();
581       m_source_text_regexp.clear();
582       m_modules.Clear();
583       m_load_addr = LLDB_INVALID_ADDRESS;
584       m_offset_addr = 0;
585       m_catch_bp = false;
586       m_throw_bp = true;
587       m_hardware = false;
588       m_exception_language = eLanguageTypeUnknown;
589       m_language = lldb::eLanguageTypeUnknown;
590       m_skip_prologue = eLazyBoolCalculate;
591       m_breakpoint_names.clear();
592       m_all_files = false;
593       m_exception_extra_args.Clear();
594       m_move_to_nearest_code = eLazyBoolCalculate;
595       m_source_regex_func_names.clear();
596     }
597
598     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
599       return llvm::makeArrayRef(g_breakpoint_set_options);
600     }
601
602     // Instance variables to hold the values for command options.
603
604     std::string m_condition;
605     FileSpecList m_filenames;
606     uint32_t m_line_num;
607     uint32_t m_column;
608     std::vector<std::string> m_func_names;
609     std::vector<std::string> m_breakpoint_names;
610     uint32_t m_func_name_type_mask;
611     std::string m_func_regexp;
612     std::string m_source_text_regexp;
613     FileSpecList m_modules;
614     lldb::addr_t m_load_addr;
615     lldb::addr_t m_offset_addr;
616     bool m_catch_bp;
617     bool m_throw_bp;
618     bool m_hardware; // Request to use hardware breakpoints
619     lldb::LanguageType m_exception_language;
620     lldb::LanguageType m_language;
621     LazyBool m_skip_prologue;
622     bool m_all_files;
623     Args m_exception_extra_args;
624     LazyBool m_move_to_nearest_code;
625     std::unordered_set<std::string> m_source_regex_func_names;
626   };
627
628 protected:
629   bool DoExecute(Args &command, CommandReturnObject &result) override {
630     Target *target = GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy);
631
632     if (target == nullptr) {
633       result.AppendError("Invalid target.  Must set target before setting "
634                          "breakpoints (see 'target create' command).");
635       result.SetStatus(eReturnStatusFailed);
636       return false;
637     }
638
639     // The following are the various types of breakpoints that could be set:
640     //   1).  -f -l -p  [-s -g]   (setting breakpoint by source location)
641     //   2).  -a  [-s -g]         (setting breakpoint by address)
642     //   3).  -n  [-s -g]         (setting breakpoint by function name)
643     //   4).  -r  [-s -g]         (setting breakpoint by function name regular
644     //   expression)
645     //   5).  -p -f               (setting a breakpoint by comparing a reg-exp
646     //   to source text)
647     //   6).  -E [-w -h]          (setting a breakpoint for exceptions for a
648     //   given language.)
649
650     BreakpointSetType break_type = eSetTypeInvalid;
651
652     if (m_options.m_line_num != 0)
653       break_type = eSetTypeFileAndLine;
654     else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
655       break_type = eSetTypeAddress;
656     else if (!m_options.m_func_names.empty())
657       break_type = eSetTypeFunctionName;
658     else if (!m_options.m_func_regexp.empty())
659       break_type = eSetTypeFunctionRegexp;
660     else if (!m_options.m_source_text_regexp.empty())
661       break_type = eSetTypeSourceRegexp;
662     else if (m_options.m_exception_language != eLanguageTypeUnknown)
663       break_type = eSetTypeException;
664
665     BreakpointSP bp_sp = nullptr;
666     FileSpec module_spec;
667     const bool internal = false;
668
669     // If the user didn't specify skip-prologue, having an offset should turn
670     // that off.
671     if (m_options.m_offset_addr != 0 &&
672         m_options.m_skip_prologue == eLazyBoolCalculate)
673       m_options.m_skip_prologue = eLazyBoolNo;
674
675     switch (break_type) {
676     case eSetTypeFileAndLine: // Breakpoint by source position
677     {
678       FileSpec file;
679       const size_t num_files = m_options.m_filenames.GetSize();
680       if (num_files == 0) {
681         if (!GetDefaultFile(target, file, result)) {
682           result.AppendError("No file supplied and no default file available.");
683           result.SetStatus(eReturnStatusFailed);
684           return false;
685         }
686       } else if (num_files > 1) {
687         result.AppendError("Only one file at a time is allowed for file and "
688                            "line breakpoints.");
689         result.SetStatus(eReturnStatusFailed);
690         return false;
691       } else
692         file = m_options.m_filenames.GetFileSpecAtIndex(0);
693
694       // Only check for inline functions if
695       LazyBool check_inlines = eLazyBoolCalculate;
696
697       bp_sp = target->CreateBreakpoint(&(m_options.m_modules), 
698                                        file,
699                                        m_options.m_line_num, 
700                                        m_options.m_offset_addr,
701                                        check_inlines, 
702                                        m_options.m_skip_prologue,
703                                        internal, 
704                                        m_options.m_hardware,
705                                        m_options.m_move_to_nearest_code);
706     } break;
707
708     case eSetTypeAddress: // Breakpoint by address
709     {
710       // If a shared library has been specified, make an lldb_private::Address
711       // with the library, and use that.  That way the address breakpoint
712       //  will track the load location of the library.
713       size_t num_modules_specified = m_options.m_modules.GetSize();
714       if (num_modules_specified == 1) {
715         const FileSpec *file_spec =
716             m_options.m_modules.GetFileSpecPointerAtIndex(0);
717         bp_sp = target->CreateAddressInModuleBreakpoint(m_options.m_load_addr,
718                                                         internal, file_spec,
719                                                         m_options.m_hardware);
720       } else if (num_modules_specified == 0) {
721         bp_sp = target->CreateBreakpoint(m_options.m_load_addr, internal,
722                                          m_options.m_hardware);
723       } else {
724         result.AppendError("Only one shared library can be specified for "
725                            "address breakpoints.");
726         result.SetStatus(eReturnStatusFailed);
727         return false;
728       }
729       break;
730     }
731     case eSetTypeFunctionName: // Breakpoint by function name
732     {
733       uint32_t name_type_mask = m_options.m_func_name_type_mask;
734
735       if (name_type_mask == 0)
736         name_type_mask = eFunctionNameTypeAuto;
737
738       bp_sp = target->CreateBreakpoint(&(m_options.m_modules), 
739                                        &(m_options.m_filenames),
740                                        m_options.m_func_names, 
741                                        name_type_mask, 
742                                        m_options.m_language,
743                                        m_options.m_offset_addr, 
744                                        m_options.m_skip_prologue, 
745                                        internal,
746                                        m_options.m_hardware);
747     } break;
748
749     case eSetTypeFunctionRegexp: // Breakpoint by regular expression function
750                                  // name
751       {
752         RegularExpression regexp(m_options.m_func_regexp);
753         if (!regexp.IsValid()) {
754           char err_str[1024];
755           regexp.GetErrorAsCString(err_str, sizeof(err_str));
756           result.AppendErrorWithFormat(
757               "Function name regular expression could not be compiled: \"%s\"",
758               err_str);
759           result.SetStatus(eReturnStatusFailed);
760           return false;
761         }
762
763         bp_sp = target->CreateFuncRegexBreakpoint(&(m_options.m_modules), 
764                                                   &(m_options.m_filenames), 
765                                                   regexp,
766                                                   m_options.m_language, 
767                                                   m_options.m_skip_prologue, 
768                                                   internal,
769                                                   m_options.m_hardware);
770       }
771       break;
772     case eSetTypeSourceRegexp: // Breakpoint by regexp on source text.
773     {
774       const size_t num_files = m_options.m_filenames.GetSize();
775
776       if (num_files == 0 && !m_options.m_all_files) {
777         FileSpec file;
778         if (!GetDefaultFile(target, file, result)) {
779           result.AppendError(
780               "No files provided and could not find default file.");
781           result.SetStatus(eReturnStatusFailed);
782           return false;
783         } else {
784           m_options.m_filenames.Append(file);
785         }
786       }
787
788       RegularExpression regexp(m_options.m_source_text_regexp);
789       if (!regexp.IsValid()) {
790         char err_str[1024];
791         regexp.GetErrorAsCString(err_str, sizeof(err_str));
792         result.AppendErrorWithFormat(
793             "Source text regular expression could not be compiled: \"%s\"",
794             err_str);
795         result.SetStatus(eReturnStatusFailed);
796         return false;
797       }
798       bp_sp = 
799           target->CreateSourceRegexBreakpoint(&(m_options.m_modules), 
800                                               &(m_options.m_filenames),
801                                               m_options
802                                                   .m_source_regex_func_names,
803                                               regexp,
804                                               internal,
805                                               m_options.m_hardware,
806                                               m_options.m_move_to_nearest_code);
807     } break;
808     case eSetTypeException: {
809       Status precond_error;
810       bp_sp = target->CreateExceptionBreakpoint(m_options.m_exception_language, 
811                                                 m_options.m_catch_bp,
812                                                 m_options.m_throw_bp, 
813                                                 internal,
814                                                 &m_options
815                                                     .m_exception_extra_args, 
816                                                 &precond_error);
817       if (precond_error.Fail()) {
818         result.AppendErrorWithFormat(
819             "Error setting extra exception arguments: %s",
820             precond_error.AsCString());
821         target->RemoveBreakpointByID(bp_sp->GetID());
822         result.SetStatus(eReturnStatusFailed);
823         return false;
824       }
825     } break;
826     default:
827       break;
828     }
829
830     // Now set the various options that were passed in:
831     if (bp_sp) {
832       bp_sp->GetOptions()->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
833
834       if (!m_options.m_breakpoint_names.empty()) {
835         Status name_error;
836         for (auto name : m_options.m_breakpoint_names) {
837           target->AddNameToBreakpoint(bp_sp, name.c_str(), name_error);
838           if (name_error.Fail()) {
839             result.AppendErrorWithFormat("Invalid breakpoint name: %s",
840                                          name.c_str());
841             target->RemoveBreakpointByID(bp_sp->GetID());
842             result.SetStatus(eReturnStatusFailed);
843             return false;
844           }
845         }
846       }
847     }
848     
849     if (bp_sp) {
850       Stream &output_stream = result.GetOutputStream();
851       const bool show_locations = false;
852       bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
853                          show_locations);
854       if (target == m_interpreter.GetDebugger().GetDummyTarget())
855         output_stream.Printf("Breakpoint set in dummy target, will get copied "
856                              "into future targets.\n");
857       else {
858         // Don't print out this warning for exception breakpoints.  They can
859         // get set before the target is set, but we won't know how to actually
860         // set the breakpoint till we run.
861         if (bp_sp->GetNumLocations() == 0 && break_type != eSetTypeException) {
862           output_stream.Printf("WARNING:  Unable to resolve breakpoint to any "
863                                "actual locations.\n");
864         }
865       }
866       result.SetStatus(eReturnStatusSuccessFinishResult);
867     } else if (!bp_sp) {
868       result.AppendError("Breakpoint creation failed: No breakpoint created.");
869       result.SetStatus(eReturnStatusFailed);
870     }
871
872     return result.Succeeded();
873   }
874
875 private:
876   bool GetDefaultFile(Target *target, FileSpec &file,
877                       CommandReturnObject &result) {
878     uint32_t default_line;
879     // First use the Source Manager's default file. Then use the current stack
880     // frame's file.
881     if (!target->GetSourceManager().GetDefaultFileAndLine(file, default_line)) {
882       StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
883       if (cur_frame == nullptr) {
884         result.AppendError(
885             "No selected frame to use to find the default file.");
886         result.SetStatus(eReturnStatusFailed);
887         return false;
888       } else if (!cur_frame->HasDebugInformation()) {
889         result.AppendError("Cannot use the selected frame to find the default "
890                            "file, it has no debug info.");
891         result.SetStatus(eReturnStatusFailed);
892         return false;
893       } else {
894         const SymbolContext &sc =
895             cur_frame->GetSymbolContext(eSymbolContextLineEntry);
896         if (sc.line_entry.file) {
897           file = sc.line_entry.file;
898         } else {
899           result.AppendError("Can't find the file for the selected frame to "
900                              "use as the default file.");
901           result.SetStatus(eReturnStatusFailed);
902           return false;
903         }
904       }
905     }
906     return true;
907   }
908
909   BreakpointOptionGroup m_bp_opts;
910   BreakpointDummyOptionGroup m_dummy_options;
911   CommandOptions m_options;
912   OptionGroupOptions m_all_options;
913 };
914
915 //-------------------------------------------------------------------------
916 // CommandObjectBreakpointModify
917 //-------------------------------------------------------------------------
918 #pragma mark Modify
919
920 class CommandObjectBreakpointModify : public CommandObjectParsed {
921 public:
922   CommandObjectBreakpointModify(CommandInterpreter &interpreter)
923       : CommandObjectParsed(interpreter, "breakpoint modify",
924                             "Modify the options on a breakpoint or set of "
925                             "breakpoints in the executable.  "
926                             "If no breakpoint is specified, acts on the last "
927                             "created breakpoint.  "
928                             "With the exception of -e, -d and -i, passing an "
929                             "empty argument clears the modification.",
930                             nullptr),
931         m_options() {
932     CommandArgumentEntry arg;
933     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
934                                       eArgTypeBreakpointIDRange);
935     // Add the entry for the first argument for this command to the object's
936     // arguments vector.
937     m_arguments.push_back(arg);
938     
939     m_options.Append(&m_bp_opts, 
940                      LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, 
941                      LLDB_OPT_SET_ALL);
942     m_options.Append(&m_dummy_opts, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
943     m_options.Finalize();
944   }
945
946   ~CommandObjectBreakpointModify() override = default;
947
948   Options *GetOptions() override { return &m_options; }
949
950 protected:
951   bool DoExecute(Args &command, CommandReturnObject &result) override {
952     Target *target = GetSelectedOrDummyTarget(m_dummy_opts.m_use_dummy);
953     if (target == nullptr) {
954       result.AppendError("Invalid target.  No existing target or breakpoints.");
955       result.SetStatus(eReturnStatusFailed);
956       return false;
957     }
958
959     std::unique_lock<std::recursive_mutex> lock;
960     target->GetBreakpointList().GetListMutex(lock);
961
962     BreakpointIDList valid_bp_ids;
963
964     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
965         command, target, result, &valid_bp_ids, 
966         BreakpointName::Permissions::PermissionKinds::disablePerm);
967
968     if (result.Succeeded()) {
969       const size_t count = valid_bp_ids.GetSize();
970       for (size_t i = 0; i < count; ++i) {
971         BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
972
973         if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
974           Breakpoint *bp =
975               target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
976           if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
977             BreakpointLocation *location =
978                 bp->FindLocationByID(cur_bp_id.GetLocationID()).get();
979             if (location)
980               location->GetLocationOptions()
981                   ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
982           } else {
983             bp->GetOptions()
984                 ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
985           }
986         }
987       }
988     }
989
990     return result.Succeeded();
991   }
992
993 private:
994   BreakpointOptionGroup m_bp_opts;
995   BreakpointDummyOptionGroup m_dummy_opts;
996   OptionGroupOptions m_options;
997 };
998
999 //-------------------------------------------------------------------------
1000 // CommandObjectBreakpointEnable
1001 //-------------------------------------------------------------------------
1002 #pragma mark Enable
1003
1004 class CommandObjectBreakpointEnable : public CommandObjectParsed {
1005 public:
1006   CommandObjectBreakpointEnable(CommandInterpreter &interpreter)
1007       : CommandObjectParsed(interpreter, "enable",
1008                             "Enable the specified disabled breakpoint(s). If "
1009                             "no breakpoints are specified, enable all of them.",
1010                             nullptr) {
1011     CommandArgumentEntry arg;
1012     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1013                                       eArgTypeBreakpointIDRange);
1014     // Add the entry for the first argument for this command to the object's
1015     // arguments vector.
1016     m_arguments.push_back(arg);
1017   }
1018
1019   ~CommandObjectBreakpointEnable() override = default;
1020
1021 protected:
1022   bool DoExecute(Args &command, CommandReturnObject &result) override {
1023     Target *target = GetSelectedOrDummyTarget();
1024     if (target == nullptr) {
1025       result.AppendError("Invalid target.  No existing target or breakpoints.");
1026       result.SetStatus(eReturnStatusFailed);
1027       return false;
1028     }
1029
1030     std::unique_lock<std::recursive_mutex> lock;
1031     target->GetBreakpointList().GetListMutex(lock);
1032
1033     const BreakpointList &breakpoints = target->GetBreakpointList();
1034
1035     size_t num_breakpoints = breakpoints.GetSize();
1036
1037     if (num_breakpoints == 0) {
1038       result.AppendError("No breakpoints exist to be enabled.");
1039       result.SetStatus(eReturnStatusFailed);
1040       return false;
1041     }
1042
1043     if (command.empty()) {
1044       // No breakpoint selected; enable all currently set breakpoints.
1045       target->EnableAllowedBreakpoints();
1046       result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64
1047                                      " breakpoints)\n",
1048                                      (uint64_t)num_breakpoints);
1049       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1050     } else {
1051       // Particular breakpoint selected; enable that breakpoint.
1052       BreakpointIDList valid_bp_ids;
1053       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1054           command, target, result, &valid_bp_ids, 
1055           BreakpointName::Permissions::PermissionKinds::disablePerm);
1056
1057       if (result.Succeeded()) {
1058         int enable_count = 0;
1059         int loc_count = 0;
1060         const size_t count = valid_bp_ids.GetSize();
1061         for (size_t i = 0; i < count; ++i) {
1062           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1063
1064           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1065             Breakpoint *breakpoint =
1066                 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1067             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1068               BreakpointLocation *location =
1069                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1070               if (location) {
1071                 location->SetEnabled(true);
1072                 ++loc_count;
1073               }
1074             } else {
1075               breakpoint->SetEnabled(true);
1076               ++enable_count;
1077             }
1078           }
1079         }
1080         result.AppendMessageWithFormat("%d breakpoints enabled.\n",
1081                                        enable_count + loc_count);
1082         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1083       }
1084     }
1085
1086     return result.Succeeded();
1087   }
1088 };
1089
1090 //-------------------------------------------------------------------------
1091 // CommandObjectBreakpointDisable
1092 //-------------------------------------------------------------------------
1093 #pragma mark Disable
1094
1095 class CommandObjectBreakpointDisable : public CommandObjectParsed {
1096 public:
1097   CommandObjectBreakpointDisable(CommandInterpreter &interpreter)
1098       : CommandObjectParsed(
1099             interpreter, "breakpoint disable",
1100             "Disable the specified breakpoint(s) without deleting "
1101             "them.  If none are specified, disable all "
1102             "breakpoints.",
1103             nullptr) {
1104     SetHelpLong(
1105         "Disable the specified breakpoint(s) without deleting them.  \
1106 If none are specified, disable all breakpoints."
1107         R"(
1108
1109 )"
1110         "Note: disabling a breakpoint will cause none of its locations to be hit \
1111 regardless of whether individual locations are enabled or disabled.  After the sequence:"
1112         R"(
1113
1114     (lldb) break disable 1
1115     (lldb) break enable 1.1
1116
1117 execution will NOT stop at location 1.1.  To achieve that, type:
1118
1119     (lldb) break disable 1.*
1120     (lldb) break enable 1.1
1121
1122 )"
1123         "The first command disables all locations for breakpoint 1, \
1124 the second re-enables the first location.");
1125
1126     CommandArgumentEntry arg;
1127     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1128                                       eArgTypeBreakpointIDRange);
1129     // Add the entry for the first argument for this command to the object's
1130     // arguments vector.
1131     m_arguments.push_back(arg);
1132   }
1133
1134   ~CommandObjectBreakpointDisable() override = default;
1135
1136 protected:
1137   bool DoExecute(Args &command, CommandReturnObject &result) override {
1138     Target *target = GetSelectedOrDummyTarget();
1139     if (target == nullptr) {
1140       result.AppendError("Invalid target.  No existing target or breakpoints.");
1141       result.SetStatus(eReturnStatusFailed);
1142       return false;
1143     }
1144
1145     std::unique_lock<std::recursive_mutex> lock;
1146     target->GetBreakpointList().GetListMutex(lock);
1147
1148     const BreakpointList &breakpoints = target->GetBreakpointList();
1149     size_t num_breakpoints = breakpoints.GetSize();
1150
1151     if (num_breakpoints == 0) {
1152       result.AppendError("No breakpoints exist to be disabled.");
1153       result.SetStatus(eReturnStatusFailed);
1154       return false;
1155     }
1156
1157     if (command.empty()) {
1158       // No breakpoint selected; disable all currently set breakpoints.
1159       target->DisableAllowedBreakpoints();
1160       result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu64
1161                                      " breakpoints)\n",
1162                                      (uint64_t)num_breakpoints);
1163       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1164     } else {
1165       // Particular breakpoint selected; disable that breakpoint.
1166       BreakpointIDList valid_bp_ids;
1167
1168       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1169           command, target, result, &valid_bp_ids, 
1170           BreakpointName::Permissions::PermissionKinds::disablePerm);
1171
1172       if (result.Succeeded()) {
1173         int disable_count = 0;
1174         int loc_count = 0;
1175         const size_t count = valid_bp_ids.GetSize();
1176         for (size_t i = 0; i < count; ++i) {
1177           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1178
1179           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1180             Breakpoint *breakpoint =
1181                 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1182             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1183               BreakpointLocation *location =
1184                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1185               if (location) {
1186                 location->SetEnabled(false);
1187                 ++loc_count;
1188               }
1189             } else {
1190               breakpoint->SetEnabled(false);
1191               ++disable_count;
1192             }
1193           }
1194         }
1195         result.AppendMessageWithFormat("%d breakpoints disabled.\n",
1196                                        disable_count + loc_count);
1197         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1198       }
1199     }
1200
1201     return result.Succeeded();
1202   }
1203 };
1204
1205 //-------------------------------------------------------------------------
1206 // CommandObjectBreakpointList
1207 //-------------------------------------------------------------------------
1208
1209 #pragma mark List::CommandOptions
1210 static OptionDefinition g_breakpoint_list_options[] = {
1211     // clang-format off
1212   { LLDB_OPT_SET_ALL, false, "internal",          'i', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show debugger internal breakpoints" },
1213   { LLDB_OPT_SET_1,   false, "brief",             'b', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a brief description of the breakpoint (no location info)." },
1214   // FIXME: We need to add an "internal" command, and then add this sort of thing to it.
1215   // But I need to see it for now, and don't want to wait.
1216   { LLDB_OPT_SET_2,   false, "full",              'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a full description of the breakpoint and its locations." },
1217   { LLDB_OPT_SET_3,   false, "verbose",           'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Explain everything we know about the breakpoint (for debugging debugger bugs)." },
1218   { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "List Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets." },
1219     // clang-format on
1220 };
1221
1222 #pragma mark List
1223
1224 class CommandObjectBreakpointList : public CommandObjectParsed {
1225 public:
1226   CommandObjectBreakpointList(CommandInterpreter &interpreter)
1227       : CommandObjectParsed(
1228             interpreter, "breakpoint list",
1229             "List some or all breakpoints at configurable levels of detail.",
1230             nullptr),
1231         m_options() {
1232     CommandArgumentEntry arg;
1233     CommandArgumentData bp_id_arg;
1234
1235     // Define the first (and only) variant of this arg.
1236     bp_id_arg.arg_type = eArgTypeBreakpointID;
1237     bp_id_arg.arg_repetition = eArgRepeatOptional;
1238
1239     // There is only one variant this argument could be; put it into the
1240     // argument entry.
1241     arg.push_back(bp_id_arg);
1242
1243     // Push the data for the first argument into the m_arguments vector.
1244     m_arguments.push_back(arg);
1245   }
1246
1247   ~CommandObjectBreakpointList() override = default;
1248
1249   Options *GetOptions() override { return &m_options; }
1250
1251   class CommandOptions : public Options {
1252   public:
1253     CommandOptions()
1254         : Options(), m_level(lldb::eDescriptionLevelBrief), m_use_dummy(false) {
1255     }
1256
1257     ~CommandOptions() override = default;
1258
1259     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1260                           ExecutionContext *execution_context) override {
1261       Status error;
1262       const int short_option = m_getopt_table[option_idx].val;
1263
1264       switch (short_option) {
1265       case 'b':
1266         m_level = lldb::eDescriptionLevelBrief;
1267         break;
1268       case 'D':
1269         m_use_dummy = true;
1270         break;
1271       case 'f':
1272         m_level = lldb::eDescriptionLevelFull;
1273         break;
1274       case 'v':
1275         m_level = lldb::eDescriptionLevelVerbose;
1276         break;
1277       case 'i':
1278         m_internal = true;
1279         break;
1280       default:
1281         error.SetErrorStringWithFormat("unrecognized option '%c'",
1282                                        short_option);
1283         break;
1284       }
1285
1286       return error;
1287     }
1288
1289     void OptionParsingStarting(ExecutionContext *execution_context) override {
1290       m_level = lldb::eDescriptionLevelFull;
1291       m_internal = false;
1292       m_use_dummy = false;
1293     }
1294
1295     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1296       return llvm::makeArrayRef(g_breakpoint_list_options);
1297     }
1298
1299     // Instance variables to hold the values for command options.
1300
1301     lldb::DescriptionLevel m_level;
1302
1303     bool m_internal;
1304     bool m_use_dummy;
1305   };
1306
1307 protected:
1308   bool DoExecute(Args &command, CommandReturnObject &result) override {
1309     Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
1310
1311     if (target == nullptr) {
1312       result.AppendError("Invalid target. No current target or breakpoints.");
1313       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1314       return true;
1315     }
1316
1317     const BreakpointList &breakpoints =
1318         target->GetBreakpointList(m_options.m_internal);
1319     std::unique_lock<std::recursive_mutex> lock;
1320     target->GetBreakpointList(m_options.m_internal).GetListMutex(lock);
1321
1322     size_t num_breakpoints = breakpoints.GetSize();
1323
1324     if (num_breakpoints == 0) {
1325       result.AppendMessage("No breakpoints currently set.");
1326       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1327       return true;
1328     }
1329
1330     Stream &output_stream = result.GetOutputStream();
1331
1332     if (command.empty()) {
1333       // No breakpoint selected; show info about all currently set breakpoints.
1334       result.AppendMessage("Current breakpoints:");
1335       for (size_t i = 0; i < num_breakpoints; ++i) {
1336         Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get();
1337         if (breakpoint->AllowList())
1338           AddBreakpointDescription(&output_stream, breakpoint, 
1339                                    m_options.m_level);
1340       }
1341       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1342     } else {
1343       // Particular breakpoints selected; show info about that breakpoint.
1344       BreakpointIDList valid_bp_ids;
1345       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1346           command, target, result, &valid_bp_ids, 
1347           BreakpointName::Permissions::PermissionKinds::listPerm);
1348
1349       if (result.Succeeded()) {
1350         for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) {
1351           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1352           Breakpoint *breakpoint =
1353               target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1354           AddBreakpointDescription(&output_stream, breakpoint,
1355                                    m_options.m_level);
1356         }
1357         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1358       } else {
1359         result.AppendError("Invalid breakpoint ID.");
1360         result.SetStatus(eReturnStatusFailed);
1361       }
1362     }
1363
1364     return result.Succeeded();
1365   }
1366
1367 private:
1368   CommandOptions m_options;
1369 };
1370
1371 //-------------------------------------------------------------------------
1372 // CommandObjectBreakpointClear
1373 //-------------------------------------------------------------------------
1374 #pragma mark Clear::CommandOptions
1375
1376 static OptionDefinition g_breakpoint_clear_options[] = {
1377     // clang-format off
1378   { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specify the breakpoint by source location in this particular file." },
1379   { LLDB_OPT_SET_1, true,  "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeLineNum,  "Specify the breakpoint by source location at this particular line." }
1380     // clang-format on
1381 };
1382
1383 #pragma mark Clear
1384
1385 class CommandObjectBreakpointClear : public CommandObjectParsed {
1386 public:
1387   typedef enum BreakpointClearType {
1388     eClearTypeInvalid,
1389     eClearTypeFileAndLine
1390   } BreakpointClearType;
1391
1392   CommandObjectBreakpointClear(CommandInterpreter &interpreter)
1393       : CommandObjectParsed(interpreter, "breakpoint clear",
1394                             "Delete or disable breakpoints matching the "
1395                             "specified source file and line.",
1396                             "breakpoint clear <cmd-options>"),
1397         m_options() {}
1398
1399   ~CommandObjectBreakpointClear() override = default;
1400
1401   Options *GetOptions() override { return &m_options; }
1402
1403   class CommandOptions : public Options {
1404   public:
1405     CommandOptions() : Options(), m_filename(), m_line_num(0) {}
1406
1407     ~CommandOptions() override = default;
1408
1409     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1410                           ExecutionContext *execution_context) override {
1411       Status error;
1412       const int short_option = m_getopt_table[option_idx].val;
1413
1414       switch (short_option) {
1415       case 'f':
1416         m_filename.assign(option_arg);
1417         break;
1418
1419       case 'l':
1420         option_arg.getAsInteger(0, m_line_num);
1421         break;
1422
1423       default:
1424         error.SetErrorStringWithFormat("unrecognized option '%c'",
1425                                        short_option);
1426         break;
1427       }
1428
1429       return error;
1430     }
1431
1432     void OptionParsingStarting(ExecutionContext *execution_context) override {
1433       m_filename.clear();
1434       m_line_num = 0;
1435     }
1436
1437     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1438       return llvm::makeArrayRef(g_breakpoint_clear_options);
1439     }
1440
1441     // Instance variables to hold the values for command options.
1442
1443     std::string m_filename;
1444     uint32_t m_line_num;
1445   };
1446
1447 protected:
1448   bool DoExecute(Args &command, CommandReturnObject &result) override {
1449     Target *target = GetSelectedOrDummyTarget();
1450     if (target == nullptr) {
1451       result.AppendError("Invalid target. No existing target or breakpoints.");
1452       result.SetStatus(eReturnStatusFailed);
1453       return false;
1454     }
1455
1456     // The following are the various types of breakpoints that could be
1457     // cleared:
1458     //   1). -f -l (clearing breakpoint by source location)
1459
1460     BreakpointClearType break_type = eClearTypeInvalid;
1461
1462     if (m_options.m_line_num != 0)
1463       break_type = eClearTypeFileAndLine;
1464
1465     std::unique_lock<std::recursive_mutex> lock;
1466     target->GetBreakpointList().GetListMutex(lock);
1467
1468     BreakpointList &breakpoints = target->GetBreakpointList();
1469     size_t num_breakpoints = breakpoints.GetSize();
1470
1471     // Early return if there's no breakpoint at all.
1472     if (num_breakpoints == 0) {
1473       result.AppendError("Breakpoint clear: No breakpoint cleared.");
1474       result.SetStatus(eReturnStatusFailed);
1475       return result.Succeeded();
1476     }
1477
1478     // Find matching breakpoints and delete them.
1479
1480     // First create a copy of all the IDs.
1481     std::vector<break_id_t> BreakIDs;
1482     for (size_t i = 0; i < num_breakpoints; ++i)
1483       BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID());
1484
1485     int num_cleared = 0;
1486     StreamString ss;
1487     switch (break_type) {
1488     case eClearTypeFileAndLine: // Breakpoint by source position
1489     {
1490       const ConstString filename(m_options.m_filename.c_str());
1491       BreakpointLocationCollection loc_coll;
1492
1493       for (size_t i = 0; i < num_breakpoints; ++i) {
1494         Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get();
1495
1496         if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) {
1497           // If the collection size is 0, it's a full match and we can just
1498           // remove the breakpoint.
1499           if (loc_coll.GetSize() == 0) {
1500             bp->GetDescription(&ss, lldb::eDescriptionLevelBrief);
1501             ss.EOL();
1502             target->RemoveBreakpointByID(bp->GetID());
1503             ++num_cleared;
1504           }
1505         }
1506       }
1507     } break;
1508
1509     default:
1510       break;
1511     }
1512
1513     if (num_cleared > 0) {
1514       Stream &output_stream = result.GetOutputStream();
1515       output_stream.Printf("%d breakpoints cleared:\n", num_cleared);
1516       output_stream << ss.GetString();
1517       output_stream.EOL();
1518       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1519     } else {
1520       result.AppendError("Breakpoint clear: No breakpoint cleared.");
1521       result.SetStatus(eReturnStatusFailed);
1522     }
1523
1524     return result.Succeeded();
1525   }
1526
1527 private:
1528   CommandOptions m_options;
1529 };
1530
1531 //-------------------------------------------------------------------------
1532 // CommandObjectBreakpointDelete
1533 //-------------------------------------------------------------------------
1534 static OptionDefinition g_breakpoint_delete_options[] = {
1535     // clang-format off
1536   { LLDB_OPT_SET_1, false, "force",             'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Delete all breakpoints without querying for confirmation." },
1537   { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Delete Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets." },
1538     // clang-format on
1539 };
1540
1541 #pragma mark Delete
1542
1543 class CommandObjectBreakpointDelete : public CommandObjectParsed {
1544 public:
1545   CommandObjectBreakpointDelete(CommandInterpreter &interpreter)
1546       : CommandObjectParsed(interpreter, "breakpoint delete",
1547                             "Delete the specified breakpoint(s).  If no "
1548                             "breakpoints are specified, delete them all.",
1549                             nullptr),
1550         m_options() {
1551     CommandArgumentEntry arg;
1552     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1553                                       eArgTypeBreakpointIDRange);
1554     // Add the entry for the first argument for this command to the object's
1555     // arguments vector.
1556     m_arguments.push_back(arg);
1557   }
1558
1559   ~CommandObjectBreakpointDelete() override = default;
1560
1561   Options *GetOptions() override { return &m_options; }
1562
1563   class CommandOptions : public Options {
1564   public:
1565     CommandOptions() : Options(), m_use_dummy(false), m_force(false) {}
1566
1567     ~CommandOptions() override = default;
1568
1569     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1570                           ExecutionContext *execution_context) override {
1571       Status error;
1572       const int short_option = m_getopt_table[option_idx].val;
1573
1574       switch (short_option) {
1575       case 'f':
1576         m_force = true;
1577         break;
1578
1579       case 'D':
1580         m_use_dummy = true;
1581         break;
1582
1583       default:
1584         error.SetErrorStringWithFormat("unrecognized option '%c'",
1585                                        short_option);
1586         break;
1587       }
1588
1589       return error;
1590     }
1591
1592     void OptionParsingStarting(ExecutionContext *execution_context) override {
1593       m_use_dummy = false;
1594       m_force = false;
1595     }
1596
1597     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1598       return llvm::makeArrayRef(g_breakpoint_delete_options);
1599     }
1600
1601     // Instance variables to hold the values for command options.
1602     bool m_use_dummy;
1603     bool m_force;
1604   };
1605
1606 protected:
1607   bool DoExecute(Args &command, CommandReturnObject &result) override {
1608     Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
1609
1610     if (target == nullptr) {
1611       result.AppendError("Invalid target. No existing target or breakpoints.");
1612       result.SetStatus(eReturnStatusFailed);
1613       return false;
1614     }
1615
1616     std::unique_lock<std::recursive_mutex> lock;
1617     target->GetBreakpointList().GetListMutex(lock);
1618
1619     const BreakpointList &breakpoints = target->GetBreakpointList();
1620
1621     size_t num_breakpoints = breakpoints.GetSize();
1622
1623     if (num_breakpoints == 0) {
1624       result.AppendError("No breakpoints exist to be deleted.");
1625       result.SetStatus(eReturnStatusFailed);
1626       return false;
1627     }
1628
1629     if (command.empty()) {
1630       if (!m_options.m_force &&
1631           !m_interpreter.Confirm(
1632               "About to delete all breakpoints, do you want to do that?",
1633               true)) {
1634         result.AppendMessage("Operation cancelled...");
1635       } else {
1636         target->RemoveAllowedBreakpoints();
1637         result.AppendMessageWithFormat(
1638             "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n",
1639             (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : "");
1640       }
1641       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1642     } else {
1643       // Particular breakpoint selected; disable that breakpoint.
1644       BreakpointIDList valid_bp_ids;
1645       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1646           command, target, result, &valid_bp_ids, 
1647           BreakpointName::Permissions::PermissionKinds::deletePerm);
1648
1649       if (result.Succeeded()) {
1650         int delete_count = 0;
1651         int disable_count = 0;
1652         const size_t count = valid_bp_ids.GetSize();
1653         for (size_t i = 0; i < count; ++i) {
1654           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1655
1656           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1657             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1658               Breakpoint *breakpoint =
1659                   target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1660               BreakpointLocation *location =
1661                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1662               // It makes no sense to try to delete individual locations, so we
1663               // disable them instead.
1664               if (location) {
1665                 location->SetEnabled(false);
1666                 ++disable_count;
1667               }
1668             } else {
1669               target->RemoveBreakpointByID(cur_bp_id.GetBreakpointID());
1670               ++delete_count;
1671             }
1672           }
1673         }
1674         result.AppendMessageWithFormat(
1675             "%d breakpoints deleted; %d breakpoint locations disabled.\n",
1676             delete_count, disable_count);
1677         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1678       }
1679     }
1680     return result.Succeeded();
1681   }
1682
1683 private:
1684   CommandOptions m_options;
1685 };
1686
1687 //-------------------------------------------------------------------------
1688 // CommandObjectBreakpointName
1689 //-------------------------------------------------------------------------
1690
1691 static OptionDefinition g_breakpoint_name_options[] = {
1692     // clang-format off
1693   {LLDB_OPT_SET_1, false, "name",              'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."},
1694   {LLDB_OPT_SET_2, false, "breakpoint-id",     'B', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointID,   "Specify a breakpoint ID to use."},
1695   {LLDB_OPT_SET_3, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,           "Operate on Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
1696   {LLDB_OPT_SET_4, false, "help-string",  'H', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "A help string describing the purpose of this name."},
1697     // clang-format on
1698 };
1699 class BreakpointNameOptionGroup : public OptionGroup {
1700 public:
1701   BreakpointNameOptionGroup()
1702       : OptionGroup(), m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) {
1703   }
1704
1705   ~BreakpointNameOptionGroup() override = default;
1706
1707   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1708     return llvm::makeArrayRef(g_breakpoint_name_options);
1709   }
1710
1711   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1712                         ExecutionContext *execution_context) override {
1713     Status error;
1714     const int short_option = g_breakpoint_name_options[option_idx].short_option;
1715
1716     switch (short_option) {
1717     case 'N':
1718       if (BreakpointID::StringIsBreakpointName(option_arg, error) &&
1719           error.Success())
1720         m_name.SetValueFromString(option_arg);
1721       break;
1722     case 'B':
1723       if (m_breakpoint.SetValueFromString(option_arg).Fail())
1724         error.SetErrorStringWithFormat(
1725             "unrecognized value \"%s\" for breakpoint",
1726             option_arg.str().c_str());
1727       break;
1728     case 'D':
1729       if (m_use_dummy.SetValueFromString(option_arg).Fail())
1730         error.SetErrorStringWithFormat(
1731             "unrecognized value \"%s\" for use-dummy",
1732             option_arg.str().c_str());
1733       break;
1734     case 'H':
1735       m_help_string.SetValueFromString(option_arg);
1736       break;
1737
1738     default:
1739       error.SetErrorStringWithFormat("unrecognized short option '%c'",
1740                                      short_option);
1741       break;
1742     }
1743     return error;
1744   }
1745
1746   void OptionParsingStarting(ExecutionContext *execution_context) override {
1747     m_name.Clear();
1748     m_breakpoint.Clear();
1749     m_use_dummy.Clear();
1750     m_use_dummy.SetDefaultValue(false);
1751     m_help_string.Clear();
1752   }
1753
1754   OptionValueString m_name;
1755   OptionValueUInt64 m_breakpoint;
1756   OptionValueBoolean m_use_dummy;
1757   OptionValueString m_help_string;
1758 };
1759
1760 static OptionDefinition g_breakpoint_access_options[] = {
1761     // clang-format off
1762   {LLDB_OPT_SET_1,   false, "allow-list",    'L', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Determines whether the breakpoint will show up in break list if not referred to explicitly."},
1763   {LLDB_OPT_SET_2,   false, "allow-disable", 'A', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Determines whether the breakpoint can be disabled by name or when all breakpoints are disabled."},
1764   {LLDB_OPT_SET_3,   false, "allow-delete",  'D', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Determines whether the breakpoint can be deleted by name or when all breakpoints are deleted."},
1765     // clang-format on
1766 };
1767
1768 class BreakpointAccessOptionGroup : public OptionGroup
1769 {
1770 public:
1771   BreakpointAccessOptionGroup() :
1772           OptionGroup()
1773    {}
1774   
1775   ~BreakpointAccessOptionGroup() override = default;
1776   
1777   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1778     return llvm::makeArrayRef(g_breakpoint_access_options);
1779   }
1780   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1781                         ExecutionContext *execution_context) override {
1782     Status error;
1783     const int short_option 
1784         = g_breakpoint_access_options[option_idx].short_option;
1785
1786     switch (short_option) {
1787       case 'L': {
1788         bool value, success;
1789         value = OptionArgParser::ToBoolean(option_arg, false, &success);
1790         if (success) {
1791           m_permissions.SetAllowList(value);
1792         } else
1793           error.SetErrorStringWithFormat(
1794               "invalid boolean value '%s' passed for -L option",
1795               option_arg.str().c_str());
1796       } break;
1797       case 'A': {
1798         bool value, success;
1799         value = OptionArgParser::ToBoolean(option_arg, false, &success);
1800         if (success) {
1801           m_permissions.SetAllowDisable(value);
1802         } else
1803           error.SetErrorStringWithFormat(
1804               "invalid boolean value '%s' passed for -L option",
1805               option_arg.str().c_str());
1806       } break;
1807       case 'D': {
1808         bool value, success;
1809         value = OptionArgParser::ToBoolean(option_arg, false, &success);
1810         if (success) {
1811           m_permissions.SetAllowDelete(value);
1812         } else
1813           error.SetErrorStringWithFormat(
1814               "invalid boolean value '%s' passed for -L option",
1815               option_arg.str().c_str());
1816       } break;
1817
1818     }
1819     
1820     return error;
1821   }
1822   
1823   void OptionParsingStarting(ExecutionContext *execution_context) override {
1824   }
1825   
1826   const BreakpointName::Permissions &GetPermissions() const
1827   {
1828     return m_permissions;
1829   }
1830   BreakpointName::Permissions m_permissions;  
1831 };
1832
1833 class CommandObjectBreakpointNameConfigure : public CommandObjectParsed {
1834 public:
1835   CommandObjectBreakpointNameConfigure(CommandInterpreter &interpreter)
1836       : CommandObjectParsed(
1837             interpreter, "configure", "Configure the options for the breakpoint"
1838             " name provided.  "
1839             "If you provide a breakpoint id, the options will be copied from "
1840             "the breakpoint, otherwise only the options specified will be set "
1841             "on the name.",
1842             "breakpoint name configure <command-options> "
1843             "<breakpoint-name-list>"),
1844         m_bp_opts(), m_option_group() {
1845     // Create the first variant for the first (and only) argument for this
1846     // command.
1847     CommandArgumentEntry arg1;
1848     CommandArgumentData id_arg;
1849     id_arg.arg_type = eArgTypeBreakpointName;
1850     id_arg.arg_repetition = eArgRepeatOptional;
1851     arg1.push_back(id_arg);
1852     m_arguments.push_back(arg1);
1853
1854     m_option_group.Append(&m_bp_opts, 
1855                           LLDB_OPT_SET_ALL, 
1856                           LLDB_OPT_SET_1);
1857     m_option_group.Append(&m_access_options, 
1858                           LLDB_OPT_SET_ALL, 
1859                           LLDB_OPT_SET_ALL);
1860     m_option_group.Append(&m_bp_id, 
1861                           LLDB_OPT_SET_2|LLDB_OPT_SET_4, 
1862                           LLDB_OPT_SET_ALL);
1863     m_option_group.Finalize();
1864   }
1865
1866   ~CommandObjectBreakpointNameConfigure() override = default;
1867
1868   Options *GetOptions() override { return &m_option_group; }
1869
1870 protected:
1871   bool DoExecute(Args &command, CommandReturnObject &result) override {
1872
1873     const size_t argc = command.GetArgumentCount();
1874     if (argc == 0) {
1875       result.AppendError("No names provided.");
1876       result.SetStatus(eReturnStatusFailed);
1877       return false;
1878     }
1879     
1880     Target *target =
1881         GetSelectedOrDummyTarget(false);
1882
1883     if (target == nullptr) {
1884       result.AppendError("Invalid target. No existing target or breakpoints.");
1885       result.SetStatus(eReturnStatusFailed);
1886       return false;
1887     }
1888
1889     std::unique_lock<std::recursive_mutex> lock;
1890     target->GetBreakpointList().GetListMutex(lock);
1891
1892     // Make a pass through first to see that all the names are legal.
1893     for (auto &entry : command.entries()) {
1894       Status error;
1895       if (!BreakpointID::StringIsBreakpointName(entry.ref, error))
1896       {
1897         result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s",
1898                                      entry.c_str(), error.AsCString());
1899         result.SetStatus(eReturnStatusFailed);
1900         return false;
1901       }
1902     }
1903     // Now configure them, we already pre-checked the names so we don't need to
1904     // check the error:
1905     BreakpointSP bp_sp;
1906     if (m_bp_id.m_breakpoint.OptionWasSet())
1907     {
1908       lldb::break_id_t bp_id = m_bp_id.m_breakpoint.GetUInt64Value();
1909       bp_sp = target->GetBreakpointByID(bp_id);
1910       if (!bp_sp)
1911       {
1912         result.AppendErrorWithFormatv("Could not find specified breakpoint {0}",
1913                            bp_id);
1914         result.SetStatus(eReturnStatusFailed);
1915         return false;
1916       }
1917     }
1918
1919     Status error;
1920     for (auto &entry : command.entries()) {
1921       ConstString name(entry.c_str());
1922       BreakpointName *bp_name = target->FindBreakpointName(name, true, error);
1923       if (!bp_name)
1924         continue;
1925       if (m_bp_id.m_help_string.OptionWasSet())
1926         bp_name->SetHelp(m_bp_id.m_help_string.GetStringValue().str().c_str());
1927       
1928       if (bp_sp)
1929         target->ConfigureBreakpointName(*bp_name,
1930                                        *bp_sp->GetOptions(),
1931                                        m_access_options.GetPermissions());
1932       else
1933         target->ConfigureBreakpointName(*bp_name,
1934                                        m_bp_opts.GetBreakpointOptions(),
1935                                        m_access_options.GetPermissions());
1936     }
1937     return true;
1938   }
1939
1940 private:
1941   BreakpointNameOptionGroup m_bp_id; // Only using the id part of this.
1942   BreakpointOptionGroup m_bp_opts;
1943   BreakpointAccessOptionGroup m_access_options;
1944   OptionGroupOptions m_option_group;
1945 };
1946
1947 class CommandObjectBreakpointNameAdd : public CommandObjectParsed {
1948 public:
1949   CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter)
1950       : CommandObjectParsed(
1951             interpreter, "add", "Add a name to the breakpoints provided.",
1952             "breakpoint name add <command-options> <breakpoint-id-list>"),
1953         m_name_options(), m_option_group() {
1954     // Create the first variant for the first (and only) argument for this
1955     // command.
1956     CommandArgumentEntry arg1;
1957     CommandArgumentData id_arg;
1958     id_arg.arg_type = eArgTypeBreakpointID;
1959     id_arg.arg_repetition = eArgRepeatOptional;
1960     arg1.push_back(id_arg);
1961     m_arguments.push_back(arg1);
1962
1963     m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
1964     m_option_group.Finalize();
1965   }
1966
1967   ~CommandObjectBreakpointNameAdd() override = default;
1968
1969   Options *GetOptions() override { return &m_option_group; }
1970
1971 protected:
1972   bool DoExecute(Args &command, CommandReturnObject &result) override {
1973     if (!m_name_options.m_name.OptionWasSet()) {
1974       result.SetError("No name option provided.");
1975       return false;
1976     }
1977
1978     Target *target =
1979         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1980
1981     if (target == nullptr) {
1982       result.AppendError("Invalid target. No existing target or breakpoints.");
1983       result.SetStatus(eReturnStatusFailed);
1984       return false;
1985     }
1986
1987     std::unique_lock<std::recursive_mutex> lock;
1988     target->GetBreakpointList().GetListMutex(lock);
1989
1990     const BreakpointList &breakpoints = target->GetBreakpointList();
1991
1992     size_t num_breakpoints = breakpoints.GetSize();
1993     if (num_breakpoints == 0) {
1994       result.SetError("No breakpoints, cannot add names.");
1995       result.SetStatus(eReturnStatusFailed);
1996       return false;
1997     }
1998
1999     // Particular breakpoint selected; disable that breakpoint.
2000     BreakpointIDList valid_bp_ids;
2001     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
2002         command, target, result, &valid_bp_ids, 
2003         BreakpointName::Permissions::PermissionKinds::listPerm);
2004
2005     if (result.Succeeded()) {
2006       if (valid_bp_ids.GetSize() == 0) {
2007         result.SetError("No breakpoints specified, cannot add names.");
2008         result.SetStatus(eReturnStatusFailed);
2009         return false;
2010       }
2011       size_t num_valid_ids = valid_bp_ids.GetSize();
2012       const char *bp_name = m_name_options.m_name.GetCurrentValue();
2013       Status error; // This error reports illegal names, but we've already 
2014                     // checked that, so we don't need to check it again here.
2015       for (size_t index = 0; index < num_valid_ids; index++) {
2016         lldb::break_id_t bp_id =
2017             valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
2018         BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
2019         target->AddNameToBreakpoint(bp_sp, bp_name, error);
2020       }
2021     }
2022
2023     return true;
2024   }
2025
2026 private:
2027   BreakpointNameOptionGroup m_name_options;
2028   OptionGroupOptions m_option_group;
2029 };
2030
2031 class CommandObjectBreakpointNameDelete : public CommandObjectParsed {
2032 public:
2033   CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter)
2034       : CommandObjectParsed(
2035             interpreter, "delete",
2036             "Delete a name from the breakpoints provided.",
2037             "breakpoint name delete <command-options> <breakpoint-id-list>"),
2038         m_name_options(), m_option_group() {
2039     // Create the first variant for the first (and only) argument for this
2040     // command.
2041     CommandArgumentEntry arg1;
2042     CommandArgumentData id_arg;
2043     id_arg.arg_type = eArgTypeBreakpointID;
2044     id_arg.arg_repetition = eArgRepeatOptional;
2045     arg1.push_back(id_arg);
2046     m_arguments.push_back(arg1);
2047
2048     m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
2049     m_option_group.Finalize();
2050   }
2051
2052   ~CommandObjectBreakpointNameDelete() override = default;
2053
2054   Options *GetOptions() override { return &m_option_group; }
2055
2056 protected:
2057   bool DoExecute(Args &command, CommandReturnObject &result) override {
2058     if (!m_name_options.m_name.OptionWasSet()) {
2059       result.SetError("No name option provided.");
2060       return false;
2061     }
2062
2063     Target *target =
2064         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
2065
2066     if (target == nullptr) {
2067       result.AppendError("Invalid target. No existing target or breakpoints.");
2068       result.SetStatus(eReturnStatusFailed);
2069       return false;
2070     }
2071
2072     std::unique_lock<std::recursive_mutex> lock;
2073     target->GetBreakpointList().GetListMutex(lock);
2074
2075     const BreakpointList &breakpoints = target->GetBreakpointList();
2076
2077     size_t num_breakpoints = breakpoints.GetSize();
2078     if (num_breakpoints == 0) {
2079       result.SetError("No breakpoints, cannot delete names.");
2080       result.SetStatus(eReturnStatusFailed);
2081       return false;
2082     }
2083
2084     // Particular breakpoint selected; disable that breakpoint.
2085     BreakpointIDList valid_bp_ids;
2086     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
2087         command, target, result, &valid_bp_ids, 
2088         BreakpointName::Permissions::PermissionKinds::deletePerm);
2089
2090     if (result.Succeeded()) {
2091       if (valid_bp_ids.GetSize() == 0) {
2092         result.SetError("No breakpoints specified, cannot delete names.");
2093         result.SetStatus(eReturnStatusFailed);
2094         return false;
2095       }
2096       ConstString bp_name(m_name_options.m_name.GetCurrentValue());
2097       size_t num_valid_ids = valid_bp_ids.GetSize();
2098       for (size_t index = 0; index < num_valid_ids; index++) {
2099         lldb::break_id_t bp_id =
2100             valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
2101         BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
2102         target->RemoveNameFromBreakpoint(bp_sp, bp_name);
2103       }
2104     }
2105
2106     return true;
2107   }
2108
2109 private:
2110   BreakpointNameOptionGroup m_name_options;
2111   OptionGroupOptions m_option_group;
2112 };
2113
2114 class CommandObjectBreakpointNameList : public CommandObjectParsed {
2115 public:
2116   CommandObjectBreakpointNameList(CommandInterpreter &interpreter)
2117       : CommandObjectParsed(interpreter, "list",
2118                             "List either the names for a breakpoint or info "
2119                             "about a given name.  With no arguments, lists all "
2120                             "names",
2121                             "breakpoint name list <command-options>"),
2122         m_name_options(), m_option_group() {
2123     m_option_group.Append(&m_name_options, LLDB_OPT_SET_3, LLDB_OPT_SET_ALL);
2124     m_option_group.Finalize();
2125   }
2126
2127   ~CommandObjectBreakpointNameList() override = default;
2128
2129   Options *GetOptions() override { return &m_option_group; }
2130
2131 protected:
2132   bool DoExecute(Args &command, CommandReturnObject &result) override {
2133     Target *target =
2134         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
2135
2136     if (target == nullptr) {
2137       result.AppendError("Invalid target. No existing target or breakpoints.");
2138       result.SetStatus(eReturnStatusFailed);
2139       return false;
2140     }
2141     
2142     
2143     std::vector<std::string> name_list;
2144     if (command.empty()) {
2145       target->GetBreakpointNames(name_list);
2146     } else {
2147       for (const Args::ArgEntry &arg : command)
2148       {
2149         name_list.push_back(arg.c_str());
2150       }
2151     }
2152     
2153     if (name_list.empty()) {
2154       result.AppendMessage("No breakpoint names found.");
2155     } else {
2156       for (const std::string &name_str : name_list) {
2157         const char *name = name_str.c_str();
2158         // First print out the options for the name:
2159         Status error;
2160         BreakpointName *bp_name = target->FindBreakpointName(ConstString(name),
2161                                                              false,
2162                                                              error);
2163         if (bp_name)
2164         {
2165           StreamString s;
2166           result.AppendMessageWithFormat("Name: %s\n", name);
2167           if (bp_name->GetDescription(&s, eDescriptionLevelFull))
2168           {
2169             result.AppendMessage(s.GetString());
2170           }
2171         
2172           std::unique_lock<std::recursive_mutex> lock;
2173           target->GetBreakpointList().GetListMutex(lock);
2174
2175           BreakpointList &breakpoints = target->GetBreakpointList();
2176           bool any_set = false;
2177           for (BreakpointSP bp_sp : breakpoints.Breakpoints()) {
2178             if (bp_sp->MatchesName(name)) {
2179               StreamString s;
2180               any_set = true;
2181               bp_sp->GetDescription(&s, eDescriptionLevelBrief);
2182               s.EOL();
2183               result.AppendMessage(s.GetString());
2184             }
2185           }
2186           if (!any_set)
2187             result.AppendMessage("No breakpoints using this name.");
2188         } else {
2189           result.AppendMessageWithFormat("Name: %s not found.\n", name);
2190         }
2191       }
2192     }
2193     return true;
2194   }
2195
2196 private:
2197   BreakpointNameOptionGroup m_name_options;
2198   OptionGroupOptions m_option_group;
2199 };
2200
2201 //-------------------------------------------------------------------------
2202 // CommandObjectBreakpointName
2203 //-------------------------------------------------------------------------
2204 class CommandObjectBreakpointName : public CommandObjectMultiword {
2205 public:
2206   CommandObjectBreakpointName(CommandInterpreter &interpreter)
2207       : CommandObjectMultiword(
2208             interpreter, "name", "Commands to manage name tags for breakpoints",
2209             "breakpoint name <subcommand> [<command-options>]") {
2210     CommandObjectSP add_command_object(
2211         new CommandObjectBreakpointNameAdd(interpreter));
2212     CommandObjectSP delete_command_object(
2213         new CommandObjectBreakpointNameDelete(interpreter));
2214     CommandObjectSP list_command_object(
2215         new CommandObjectBreakpointNameList(interpreter));
2216     CommandObjectSP configure_command_object(
2217         new CommandObjectBreakpointNameConfigure(interpreter));
2218
2219     LoadSubCommand("add", add_command_object);
2220     LoadSubCommand("delete", delete_command_object);
2221     LoadSubCommand("list", list_command_object);
2222     LoadSubCommand("configure", configure_command_object);
2223   }
2224
2225   ~CommandObjectBreakpointName() override = default;
2226 };
2227
2228 //-------------------------------------------------------------------------
2229 // CommandObjectBreakpointRead
2230 //-------------------------------------------------------------------------
2231 #pragma mark Read::CommandOptions
2232 static OptionDefinition g_breakpoint_read_options[] = {
2233     // clang-format off
2234   { LLDB_OPT_SET_ALL, true, "file",                   'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename,       "The file from which to read the breakpoints." },
2235   {LLDB_OPT_SET_ALL, false, "breakpoint-name",        'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                       eArgTypeBreakpointName, "Only read in breakpoints with this name."},
2236     // clang-format on
2237 };
2238
2239 #pragma mark Read
2240
2241 class CommandObjectBreakpointRead : public CommandObjectParsed {
2242 public:
2243   CommandObjectBreakpointRead(CommandInterpreter &interpreter)
2244       : CommandObjectParsed(interpreter, "breakpoint read",
2245                             "Read and set the breakpoints previously saved to "
2246                             "a file with \"breakpoint write\".  ",
2247                             nullptr),
2248         m_options() {
2249     CommandArgumentEntry arg;
2250     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
2251                                       eArgTypeBreakpointIDRange);
2252     // Add the entry for the first argument for this command to the object's
2253     // arguments vector.
2254     m_arguments.push_back(arg);
2255   }
2256
2257   ~CommandObjectBreakpointRead() override = default;
2258
2259   Options *GetOptions() override { return &m_options; }
2260
2261   class CommandOptions : public Options {
2262   public:
2263     CommandOptions() : Options() {}
2264
2265     ~CommandOptions() override = default;
2266
2267     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2268                           ExecutionContext *execution_context) override {
2269       Status error;
2270       const int short_option = m_getopt_table[option_idx].val;
2271
2272       switch (short_option) {
2273       case 'f':
2274         m_filename.assign(option_arg);
2275         break;
2276       case 'N': {
2277         Status name_error;
2278         if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg),
2279                                                   name_error)) {
2280           error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
2281                                          name_error.AsCString());
2282         }
2283         m_names.push_back(option_arg);
2284         break;
2285       }
2286       default:
2287         error.SetErrorStringWithFormat("unrecognized option '%c'",
2288                                        short_option);
2289         break;
2290       }
2291
2292       return error;
2293     }
2294
2295     void OptionParsingStarting(ExecutionContext *execution_context) override {
2296       m_filename.clear();
2297       m_names.clear();
2298     }
2299
2300     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2301       return llvm::makeArrayRef(g_breakpoint_read_options);
2302     }
2303
2304     // Instance variables to hold the values for command options.
2305
2306     std::string m_filename;
2307     std::vector<std::string> m_names;
2308   };
2309
2310 protected:
2311   bool DoExecute(Args &command, CommandReturnObject &result) override {
2312     Target *target = GetSelectedOrDummyTarget();
2313     if (target == nullptr) {
2314       result.AppendError("Invalid target.  No existing target or breakpoints.");
2315       result.SetStatus(eReturnStatusFailed);
2316       return false;
2317     }
2318
2319     std::unique_lock<std::recursive_mutex> lock;
2320     target->GetBreakpointList().GetListMutex(lock);
2321
2322     FileSpec input_spec(m_options.m_filename, true);
2323     BreakpointIDList new_bps;
2324     Status error = target->CreateBreakpointsFromFile(
2325         input_spec, m_options.m_names, new_bps);
2326
2327     if (!error.Success()) {
2328       result.AppendError(error.AsCString());
2329       result.SetStatus(eReturnStatusFailed);
2330       return false;
2331     }
2332
2333     Stream &output_stream = result.GetOutputStream();
2334
2335     size_t num_breakpoints = new_bps.GetSize();
2336     if (num_breakpoints == 0) {
2337       result.AppendMessage("No breakpoints added.");
2338     } else {
2339       // No breakpoint selected; show info about all currently set breakpoints.
2340       result.AppendMessage("New breakpoints:");
2341       for (size_t i = 0; i < num_breakpoints; ++i) {
2342         BreakpointID bp_id = new_bps.GetBreakpointIDAtIndex(i);
2343         Breakpoint *bp = target->GetBreakpointList()
2344                              .FindBreakpointByID(bp_id.GetBreakpointID())
2345                              .get();
2346         if (bp)
2347           bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
2348                              false);
2349       }
2350     }
2351     return result.Succeeded();
2352   }
2353
2354 private:
2355   CommandOptions m_options;
2356 };
2357
2358 //-------------------------------------------------------------------------
2359 // CommandObjectBreakpointWrite
2360 //-------------------------------------------------------------------------
2361 #pragma mark Write::CommandOptions
2362 static OptionDefinition g_breakpoint_write_options[] = {
2363     // clang-format off
2364   { LLDB_OPT_SET_ALL, true,  "file",  'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename,    "The file into which to write the breakpoints." },
2365   { LLDB_OPT_SET_ALL, false, "append",'a', OptionParser::eNoArgument,       nullptr, nullptr, 0,                                       eArgTypeNone,        "Append to saved breakpoints file if it exists."},
2366     // clang-format on
2367 };
2368
2369 #pragma mark Write
2370 class CommandObjectBreakpointWrite : public CommandObjectParsed {
2371 public:
2372   CommandObjectBreakpointWrite(CommandInterpreter &interpreter)
2373       : CommandObjectParsed(interpreter, "breakpoint write",
2374                             "Write the breakpoints listed to a file that can "
2375                             "be read in with \"breakpoint read\".  "
2376                             "If given no arguments, writes all breakpoints.",
2377                             nullptr),
2378         m_options() {
2379     CommandArgumentEntry arg;
2380     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
2381                                       eArgTypeBreakpointIDRange);
2382     // Add the entry for the first argument for this command to the object's
2383     // arguments vector.
2384     m_arguments.push_back(arg);
2385   }
2386
2387   ~CommandObjectBreakpointWrite() override = default;
2388
2389   Options *GetOptions() override { return &m_options; }
2390
2391   class CommandOptions : public Options {
2392   public:
2393     CommandOptions() : Options() {}
2394
2395     ~CommandOptions() override = default;
2396
2397     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2398                           ExecutionContext *execution_context) override {
2399       Status error;
2400       const int short_option = m_getopt_table[option_idx].val;
2401
2402       switch (short_option) {
2403       case 'f':
2404         m_filename.assign(option_arg);
2405         break;
2406       case 'a':
2407         m_append = true;
2408         break;
2409       default:
2410         error.SetErrorStringWithFormat("unrecognized option '%c'",
2411                                        short_option);
2412         break;
2413       }
2414
2415       return error;
2416     }
2417
2418     void OptionParsingStarting(ExecutionContext *execution_context) override {
2419       m_filename.clear();
2420       m_append = false;
2421     }
2422
2423     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2424       return llvm::makeArrayRef(g_breakpoint_write_options);
2425     }
2426
2427     // Instance variables to hold the values for command options.
2428
2429     std::string m_filename;
2430     bool m_append = false;
2431   };
2432
2433 protected:
2434   bool DoExecute(Args &command, CommandReturnObject &result) override {
2435     Target *target = GetSelectedOrDummyTarget();
2436     if (target == nullptr) {
2437       result.AppendError("Invalid target.  No existing target or breakpoints.");
2438       result.SetStatus(eReturnStatusFailed);
2439       return false;
2440     }
2441
2442     std::unique_lock<std::recursive_mutex> lock;
2443     target->GetBreakpointList().GetListMutex(lock);
2444
2445     BreakpointIDList valid_bp_ids;
2446     if (!command.empty()) {
2447       CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
2448           command, target, result, &valid_bp_ids, 
2449           BreakpointName::Permissions::PermissionKinds::listPerm);
2450
2451       if (!result.Succeeded()) {
2452         result.SetStatus(eReturnStatusFailed);
2453         return false;
2454       }
2455     }
2456     Status error = target->SerializeBreakpointsToFile(
2457         FileSpec(m_options.m_filename, true), valid_bp_ids, m_options.m_append);
2458     if (!error.Success()) {
2459       result.AppendErrorWithFormat("error serializing breakpoints: %s.",
2460                                    error.AsCString());
2461       result.SetStatus(eReturnStatusFailed);
2462     }
2463     return result.Succeeded();
2464   }
2465
2466 private:
2467   CommandOptions m_options;
2468 };
2469
2470 //-------------------------------------------------------------------------
2471 // CommandObjectMultiwordBreakpoint
2472 //-------------------------------------------------------------------------
2473 #pragma mark MultiwordBreakpoint
2474
2475 CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
2476     CommandInterpreter &interpreter)
2477     : CommandObjectMultiword(
2478           interpreter, "breakpoint",
2479           "Commands for operating on breakpoints (see 'help b' for shorthand.)",
2480           "breakpoint <subcommand> [<command-options>]") {
2481   CommandObjectSP list_command_object(
2482       new CommandObjectBreakpointList(interpreter));
2483   CommandObjectSP enable_command_object(
2484       new CommandObjectBreakpointEnable(interpreter));
2485   CommandObjectSP disable_command_object(
2486       new CommandObjectBreakpointDisable(interpreter));
2487   CommandObjectSP clear_command_object(
2488       new CommandObjectBreakpointClear(interpreter));
2489   CommandObjectSP delete_command_object(
2490       new CommandObjectBreakpointDelete(interpreter));
2491   CommandObjectSP set_command_object(
2492       new CommandObjectBreakpointSet(interpreter));
2493   CommandObjectSP command_command_object(
2494       new CommandObjectBreakpointCommand(interpreter));
2495   CommandObjectSP modify_command_object(
2496       new CommandObjectBreakpointModify(interpreter));
2497   CommandObjectSP name_command_object(
2498       new CommandObjectBreakpointName(interpreter));
2499   CommandObjectSP write_command_object(
2500       new CommandObjectBreakpointWrite(interpreter));
2501   CommandObjectSP read_command_object(
2502       new CommandObjectBreakpointRead(interpreter));
2503
2504   list_command_object->SetCommandName("breakpoint list");
2505   enable_command_object->SetCommandName("breakpoint enable");
2506   disable_command_object->SetCommandName("breakpoint disable");
2507   clear_command_object->SetCommandName("breakpoint clear");
2508   delete_command_object->SetCommandName("breakpoint delete");
2509   set_command_object->SetCommandName("breakpoint set");
2510   command_command_object->SetCommandName("breakpoint command");
2511   modify_command_object->SetCommandName("breakpoint modify");
2512   name_command_object->SetCommandName("breakpoint name");
2513   write_command_object->SetCommandName("breakpoint write");
2514   read_command_object->SetCommandName("breakpoint read");
2515
2516   LoadSubCommand("list", list_command_object);
2517   LoadSubCommand("enable", enable_command_object);
2518   LoadSubCommand("disable", disable_command_object);
2519   LoadSubCommand("clear", clear_command_object);
2520   LoadSubCommand("delete", delete_command_object);
2521   LoadSubCommand("set", set_command_object);
2522   LoadSubCommand("command", command_command_object);
2523   LoadSubCommand("modify", modify_command_object);
2524   LoadSubCommand("name", name_command_object);
2525   LoadSubCommand("write", write_command_object);
2526   LoadSubCommand("read", read_command_object);
2527 }
2528
2529 CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default;
2530
2531 void CommandObjectMultiwordBreakpoint::VerifyIDs(Args &args, Target *target,
2532                                                  bool allow_locations,
2533                                                  CommandReturnObject &result,
2534                                                  BreakpointIDList *valid_ids,
2535                                                  BreakpointName::Permissions
2536                                                      ::PermissionKinds 
2537                                                      purpose) {
2538   // args can be strings representing 1). integers (for breakpoint ids)
2539   //                                  2). the full breakpoint & location
2540   //                                  canonical representation
2541   //                                  3). the word "to" or a hyphen,
2542   //                                  representing a range (in which case there
2543   //                                      had *better* be an entry both before &
2544   //                                      after of one of the first two types.
2545   //                                  4). A breakpoint name
2546   // If args is empty, we will use the last created breakpoint (if there is
2547   // one.)
2548
2549   Args temp_args;
2550
2551   if (args.empty()) {
2552     if (target->GetLastCreatedBreakpoint()) {
2553       valid_ids->AddBreakpointID(BreakpointID(
2554           target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID));
2555       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2556     } else {
2557       result.AppendError(
2558           "No breakpoint specified and no last created breakpoint.");
2559       result.SetStatus(eReturnStatusFailed);
2560     }
2561     return;
2562   }
2563
2564   // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff
2565   // directly from the old ARGS to the new TEMP_ARGS.  Do not copy breakpoint
2566   // id range strings over; instead generate a list of strings for all the
2567   // breakpoint ids in the range, and shove all of those breakpoint id strings
2568   // into TEMP_ARGS.
2569
2570   BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations, 
2571                                            purpose, result, temp_args);
2572
2573   // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual
2574   // BreakpointIDList:
2575
2576   valid_ids->InsertStringArray(temp_args.GetConstArgumentVector(),
2577                                temp_args.GetArgumentCount(), result);
2578
2579   // At this point,  all of the breakpoint ids that the user passed in have
2580   // been converted to breakpoint IDs and put into valid_ids.
2581
2582   if (result.Succeeded()) {
2583     // Now that we've converted everything from args into a list of breakpoint
2584     // ids, go through our tentative list of breakpoint id's and verify that
2585     // they correspond to valid/currently set breakpoints.
2586
2587     const size_t count = valid_ids->GetSize();
2588     for (size_t i = 0; i < count; ++i) {
2589       BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex(i);
2590       Breakpoint *breakpoint =
2591           target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
2592       if (breakpoint != nullptr) {
2593         const size_t num_locations = breakpoint->GetNumLocations();
2594         if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) {
2595           StreamString id_str;
2596           BreakpointID::GetCanonicalReference(
2597               &id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
2598           i = valid_ids->GetSize() + 1;
2599           result.AppendErrorWithFormat(
2600               "'%s' is not a currently valid breakpoint/location id.\n",
2601               id_str.GetData());
2602           result.SetStatus(eReturnStatusFailed);
2603         }
2604       } else {
2605         i = valid_ids->GetSize() + 1;
2606         result.AppendErrorWithFormat(
2607             "'%d' is not a currently valid breakpoint ID.\n",
2608             cur_bp_id.GetBreakpointID());
2609         result.SetStatus(eReturnStatusFailed);
2610       }
2611     }
2612   }
2613 }