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