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