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