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