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