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