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