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