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     } break;
545     case eSetTypeSourceRegexp: // Breakpoint by regexp on source text.
546     {
547       const size_t num_files = m_options.m_filenames.GetSize();
548 
549       if (num_files == 0 && !m_options.m_all_files) {
550         FileSpec file;
551         if (!GetDefaultFile(target, file, result)) {
552           result.AppendError(
553               "No files provided and could not find default file.");
554           result.SetStatus(eReturnStatusFailed);
555           return false;
556         } else {
557           m_options.m_filenames.Append(file);
558         }
559       }
560 
561       RegularExpression regexp(m_options.m_source_text_regexp.c_str());
562       if (!regexp.IsValid()) {
563         char err_str[1024];
564         regexp.GetErrorAsCString(err_str, sizeof(err_str));
565         result.AppendErrorWithFormat(
566             "Source text regular expression could not be compiled: \"%s\"",
567             err_str);
568         result.SetStatus(eReturnStatusFailed);
569         return false;
570       }
571       bp = target
572                ->CreateSourceRegexBreakpoint(
573                    &(m_options.m_modules), &(m_options.m_filenames),
574                    m_options.m_source_regex_func_names, regexp, internal,
575                    m_options.m_hardware, m_options.m_move_to_nearest_code)
576                .get();
577     } break;
578     case eSetTypeException: {
579       Error precond_error;
580       bp = target
581                ->CreateExceptionBreakpoint(
582                    m_options.m_exception_language, m_options.m_catch_bp,
583                    m_options.m_throw_bp, internal,
584                    &m_options.m_exception_extra_args, &precond_error)
585                .get();
586       if (precond_error.Fail()) {
587         result.AppendErrorWithFormat(
588             "Error setting extra exception arguments: %s",
589             precond_error.AsCString());
590         target->RemoveBreakpointByID(bp->GetID());
591         result.SetStatus(eReturnStatusFailed);
592         return false;
593       }
594     } break;
595     default:
596       break;
597     }
598 
599     // Now set the various options that were passed in:
600     if (bp) {
601       if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID)
602         bp->SetThreadID(m_options.m_thread_id);
603 
604       if (m_options.m_thread_index != UINT32_MAX)
605         bp->GetOptions()->GetThreadSpec()->SetIndex(m_options.m_thread_index);
606 
607       if (!m_options.m_thread_name.empty())
608         bp->GetOptions()->GetThreadSpec()->SetName(
609             m_options.m_thread_name.c_str());
610 
611       if (!m_options.m_queue_name.empty())
612         bp->GetOptions()->GetThreadSpec()->SetQueueName(
613             m_options.m_queue_name.c_str());
614 
615       if (m_options.m_ignore_count != 0)
616         bp->GetOptions()->SetIgnoreCount(m_options.m_ignore_count);
617 
618       if (!m_options.m_condition.empty())
619         bp->GetOptions()->SetCondition(m_options.m_condition.c_str());
620 
621       if (!m_options.m_breakpoint_names.empty()) {
622         Error error; // We don't need to check the error here, since the option
623                      // parser checked it...
624         for (auto name : m_options.m_breakpoint_names)
625           bp->AddName(name.c_str(), error);
626       }
627 
628       bp->SetOneShot(m_options.m_one_shot);
629     }
630 
631     if (bp) {
632       Stream &output_stream = result.GetOutputStream();
633       const bool show_locations = false;
634       bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
635                          show_locations);
636       if (target == m_interpreter.GetDebugger().GetDummyTarget())
637         output_stream.Printf("Breakpoint set in dummy target, will get copied "
638                              "into future targets.\n");
639       else {
640         // Don't print out this warning for exception breakpoints.  They can get
641         // set before the target
642         // is set, but we won't know how to actually set the breakpoint till we
643         // run.
644         if (bp->GetNumLocations() == 0 && break_type != eSetTypeException) {
645           output_stream.Printf("WARNING:  Unable to resolve breakpoint to any "
646                                "actual locations.\n");
647         }
648       }
649       result.SetStatus(eReturnStatusSuccessFinishResult);
650     } else if (!bp) {
651       result.AppendError("Breakpoint creation failed: No breakpoint created.");
652       result.SetStatus(eReturnStatusFailed);
653     }
654 
655     return result.Succeeded();
656   }
657 
658 private:
659   bool GetDefaultFile(Target *target, FileSpec &file,
660                       CommandReturnObject &result) {
661     uint32_t default_line;
662     // First use the Source Manager's default file.
663     // Then use the current stack frame's file.
664     if (!target->GetSourceManager().GetDefaultFileAndLine(file, default_line)) {
665       StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
666       if (cur_frame == nullptr) {
667         result.AppendError(
668             "No selected frame to use to find the default file.");
669         result.SetStatus(eReturnStatusFailed);
670         return false;
671       } else if (!cur_frame->HasDebugInformation()) {
672         result.AppendError("Cannot use the selected frame to find the default "
673                            "file, it has no debug info.");
674         result.SetStatus(eReturnStatusFailed);
675         return false;
676       } else {
677         const SymbolContext &sc =
678             cur_frame->GetSymbolContext(eSymbolContextLineEntry);
679         if (sc.line_entry.file) {
680           file = sc.line_entry.file;
681         } else {
682           result.AppendError("Can't find the file for the selected frame to "
683                              "use as the default file.");
684           result.SetStatus(eReturnStatusFailed);
685           return false;
686         }
687       }
688     }
689     return true;
690   }
691 
692   CommandOptions m_options;
693 };
694 
695 // If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to
696 // update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately.
697 #define LLDB_OPT_FILE (LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2)
698 #define LLDB_OPT_NOT_10 (LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10)
699 #define LLDB_OPT_SKIP_PROLOGUE (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8))
700 #define LLDB_OPT_OFFSET_APPLIES (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8))
701 #define LLDB_OPT_MOVE_TO_NEAREST_CODE (LLDB_OPT_SET_1 | LLDB_OPT_SET_9)
702 #define LLDB_OPT_EXPR_LANGUAGE (LLDB_OPT_SET_FROM_TO(3, 8))
703 
704 OptionDefinition CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
705     {
706         // clang-format off
707   {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 "
708                                                                                                                                                                                                    "multiple times to specify multiple shared libraries."},
709   {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." },
710   {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." },
711   {LLDB_OPT_SET_ALL,              false, "condition",              'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeExpression,          "The breakpoint stops only if this condition expression evaluates to true."},
712   {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."},
713   {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."},
714   {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 "
715                                                                                                                                                                                                    "argument."},
716   {LLDB_OPT_SET_ALL,              false, "hardware",               'H', OptionParser::eNoArgument,       nullptr, nullptr, 0,                                         eArgTypeNone,                "Require the breakpoint to use hardware breakpoints."},
717   {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 "
718                                                                                                                                                                                                    "this argument."},
719   {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 "
720                                                                                                                                                                                                    "lldb only looks for files that are #included if they use the standard include "
721                                                                                                                                                                                                    "file extensions.  To set breakpoints on .c/.cpp/.m/.mm files that are "
722                                                                                                                                                                                                    "#included, set target.inline-breakpoint-strategy to \"always\"."},
723   {LLDB_OPT_SET_1,                true,  "line",                   'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeLineNum,             "Specifies the line number on which to set this breakpoint."},
724 
725     // Comment out this option for the moment, as we don't actually use it, but will in the future.
726     // This way users won't see it, but the infrastructure is left in place.
727     //    { 0, false, "column",     'C', OptionParser::eRequiredArgument, nullptr, "<column>",
728     //    "Set the breakpoint by source location at this particular column."},
729 
730   {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 "
731                                                                                                                                                                                                    "a particular binary, then the address will be converted to a \"file\" "
732                                                                                                                                                                                                    "address, so that the breakpoint will track that binary+offset no matter where "
733                                                                                                                                                                                                    "the binary eventually loads.  Alternately, if you also specify the module - "
734                                                                                                                                                                                                    "with the -s option - then the address will be treated as a file address in "
735                                                                                                                                                                                                    "that module, and resolved accordingly.  Again, this will allow lldb to track "
736                                                                                                                                                                                                    "that offset on subsequent reloads.  The module need not have been loaded at "
737                                                                                                                                                                                                    "the time you specify this breakpoint, and will get resolved when the module "
738                                                                                                                                                                                                    "is loaded."},
739   {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 "
740                                                                                                                                                                                                    "one breakpoint for multiple names"},
741   {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 "
742                                                                                                                                                                                                    "functions.  Can be repeated multiple times."},
743   {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 "
744                                                                                                                                                                                                    "namespaces and all arguments, and for Objective C this means a full function "
745                                                                                                                                                                                                    "prototype with class and selector.  Can be repeated multiple times to make "
746                                                                                                                                                                                                    "one breakpoint for multiple names."},
747   {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 "
748                                                                                                                                                                                                    "make one breakpoint for multiple Selectors."},
749   {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 "
750                                                                                                                                                                                                    "make one breakpoint for multiple methods."},
751   {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 "
752                                                                                                                                                                                                    "the function name(s)."},
753   {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 "
754                                                                                                                                                                                                    "ignored).  Can be repeated multiple times to make one breakpoint for multiple "
755                                                                                                                                                                                                    "symbols."},
756   {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 "
757                                                                                                                                                                                                    "against the source text in a source file or files specified with the -f "
758                                                                                                                                                                                                    "option.  The -f option can be specified more than once.  If no source files "
759                                                                                                                                                                                                    "are specified, uses the current \"default source file\".  If you want to "
760                                                                                                                                                                                                    "match against all source files, pass the \"--all-files\" option."},
761   {LLDB_OPT_SET_9,                false, "all-files",              'A', OptionParser::eNoArgument,       nullptr, nullptr, 0,                                         eArgTypeNone,                "All files are searched for source pattern matches."},
762   {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 "
763                                                                                                                                                                                                    "options, on throw but not catch.)"},
764   {LLDB_OPT_SET_10,               false, "on-throw",               'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeBoolean,             "Set the breakpoint on exception throW."},
765   {LLDB_OPT_SET_10,               false, "on-catch",               'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeBoolean,             "Set the breakpoint on exception catcH."},
766 
767 //  Don't add this option till it actually does something useful...
768 //    { LLDB_OPT_SET_10, false, "exception-typename", 'O', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeTypeName,
769 //        "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" },
770 
771   {LLDB_OPT_EXPR_LANGUAGE,        false, "language",               'L', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeLanguage,            "Specifies the Language to use when interpreting the breakpoint's expression "
772                                                                                                                                                                                                    "(note: currently only implemented for setting breakpoints on identifiers).  "
773                                                                                                                                                                                                    "If not set the target.language setting is used."},
774   {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.  "
775                                                                                                                                                                                                    "If not set the target.skip-prologue setting is used."},
776   {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, "
777                                                                                                                                                                                                    "which prime new targets."},
778   {LLDB_OPT_SET_ALL,              false, "breakpoint-name",        'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeBreakpointName,      "Adds this to the list of names for this breakpoint."},
779   {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.  "
780         "At present this applies the offset directly as given, and doesn't try to align it to instruction boundaries."},
781   {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 "
782                                                                                                                                                                                                    "setting is used."},
783   {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
784         // clang-format on
785 };
786 
787 //-------------------------------------------------------------------------
788 // CommandObjectBreakpointModify
789 //-------------------------------------------------------------------------
790 #pragma mark Modify
791 
792 class CommandObjectBreakpointModify : public CommandObjectParsed {
793 public:
794   CommandObjectBreakpointModify(CommandInterpreter &interpreter)
795       : CommandObjectParsed(interpreter, "breakpoint modify",
796                             "Modify the options on a breakpoint or set of "
797                             "breakpoints in the executable.  "
798                             "If no breakpoint is specified, acts on the last "
799                             "created breakpoint.  "
800                             "With the exception of -e, -d and -i, passing an "
801                             "empty argument clears the modification.",
802                             nullptr),
803         m_options() {
804     CommandArgumentEntry arg;
805     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
806                                       eArgTypeBreakpointIDRange);
807     // Add the entry for the first argument for this command to the object's
808     // arguments vector.
809     m_arguments.push_back(arg);
810   }
811 
812   ~CommandObjectBreakpointModify() override = default;
813 
814   Options *GetOptions() override { return &m_options; }
815 
816   class CommandOptions : public Options {
817   public:
818     CommandOptions()
819         : Options(), m_ignore_count(0), m_thread_id(LLDB_INVALID_THREAD_ID),
820           m_thread_id_passed(false), m_thread_index(UINT32_MAX),
821           m_thread_index_passed(false), m_thread_name(), m_queue_name(),
822           m_condition(), m_one_shot(false), m_enable_passed(false),
823           m_enable_value(false), m_name_passed(false), m_queue_passed(false),
824           m_condition_passed(false), m_one_shot_passed(false),
825           m_use_dummy(false) {}
826 
827     ~CommandOptions() override = default;
828 
829     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
830                          ExecutionContext *execution_context) override {
831       Error error;
832       const int short_option = m_getopt_table[option_idx].val;
833 
834       switch (short_option) {
835       case 'c':
836         if (option_arg != nullptr)
837           m_condition.assign(option_arg);
838         else
839           m_condition.clear();
840         m_condition_passed = true;
841         break;
842       case 'd':
843         m_enable_passed = true;
844         m_enable_value = false;
845         break;
846       case 'D':
847         m_use_dummy = true;
848         break;
849       case 'e':
850         m_enable_passed = true;
851         m_enable_value = true;
852         break;
853       case 'i':
854         m_ignore_count = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0);
855         if (m_ignore_count == UINT32_MAX)
856           error.SetErrorStringWithFormat("invalid ignore count '%s'",
857                                          option_arg);
858         break;
859       case 'o': {
860         bool value, success;
861         value = Args::StringToBoolean(option_arg, false, &success);
862         if (success) {
863           m_one_shot_passed = true;
864           m_one_shot = value;
865         } else
866           error.SetErrorStringWithFormat(
867               "invalid boolean value '%s' passed for -o option", option_arg);
868       } break;
869       case 't':
870         if (option_arg[0] == '\0') {
871           m_thread_id = LLDB_INVALID_THREAD_ID;
872           m_thread_id_passed = true;
873         } else {
874           m_thread_id =
875               StringConvert::ToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0);
876           if (m_thread_id == LLDB_INVALID_THREAD_ID)
877             error.SetErrorStringWithFormat("invalid thread id string '%s'",
878                                            option_arg);
879           else
880             m_thread_id_passed = true;
881         }
882         break;
883       case 'T':
884         if (option_arg != nullptr)
885           m_thread_name.assign(option_arg);
886         else
887           m_thread_name.clear();
888         m_name_passed = true;
889         break;
890       case 'q':
891         if (option_arg != nullptr)
892           m_queue_name.assign(option_arg);
893         else
894           m_queue_name.clear();
895         m_queue_passed = true;
896         break;
897       case 'x':
898         if (option_arg[0] == '\n') {
899           m_thread_index = UINT32_MAX;
900           m_thread_index_passed = true;
901         } else {
902           m_thread_index = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0);
903           if (m_thread_id == UINT32_MAX)
904             error.SetErrorStringWithFormat("invalid thread index string '%s'",
905                                            option_arg);
906           else
907             m_thread_index_passed = true;
908         }
909         break;
910       default:
911         error.SetErrorStringWithFormat("unrecognized option '%c'",
912                                        short_option);
913         break;
914       }
915 
916       return error;
917     }
918 
919     void OptionParsingStarting(ExecutionContext *execution_context) override {
920       m_ignore_count = 0;
921       m_thread_id = LLDB_INVALID_THREAD_ID;
922       m_thread_id_passed = false;
923       m_thread_index = UINT32_MAX;
924       m_thread_index_passed = false;
925       m_thread_name.clear();
926       m_queue_name.clear();
927       m_condition.clear();
928       m_one_shot = false;
929       m_enable_passed = false;
930       m_queue_passed = false;
931       m_name_passed = false;
932       m_condition_passed = false;
933       m_one_shot_passed = false;
934       m_use_dummy = false;
935     }
936 
937     const OptionDefinition *GetDefinitions() override { return g_option_table; }
938 
939     // Options table: Required for subclasses of Options.
940 
941     static OptionDefinition g_option_table[];
942 
943     // Instance variables to hold the values for command options.
944 
945     uint32_t m_ignore_count;
946     lldb::tid_t m_thread_id;
947     bool m_thread_id_passed;
948     uint32_t m_thread_index;
949     bool m_thread_index_passed;
950     std::string m_thread_name;
951     std::string m_queue_name;
952     std::string m_condition;
953     bool m_one_shot;
954     bool m_enable_passed;
955     bool m_enable_value;
956     bool m_name_passed;
957     bool m_queue_passed;
958     bool m_condition_passed;
959     bool m_one_shot_passed;
960     bool m_use_dummy;
961   };
962 
963 protected:
964   bool DoExecute(Args &command, CommandReturnObject &result) override {
965     Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
966     if (target == nullptr) {
967       result.AppendError("Invalid target.  No existing target or breakpoints.");
968       result.SetStatus(eReturnStatusFailed);
969       return false;
970     }
971 
972     std::unique_lock<std::recursive_mutex> lock;
973     target->GetBreakpointList().GetListMutex(lock);
974 
975     BreakpointIDList valid_bp_ids;
976 
977     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
978         command, target, result, &valid_bp_ids);
979 
980     if (result.Succeeded()) {
981       const size_t count = valid_bp_ids.GetSize();
982       for (size_t i = 0; i < count; ++i) {
983         BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
984 
985         if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
986           Breakpoint *bp =
987               target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
988           if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
989             BreakpointLocation *location =
990                 bp->FindLocationByID(cur_bp_id.GetLocationID()).get();
991             if (location) {
992               if (m_options.m_thread_id_passed)
993                 location->SetThreadID(m_options.m_thread_id);
994 
995               if (m_options.m_thread_index_passed)
996                 location->SetThreadIndex(m_options.m_thread_index);
997 
998               if (m_options.m_name_passed)
999                 location->SetThreadName(m_options.m_thread_name.c_str());
1000 
1001               if (m_options.m_queue_passed)
1002                 location->SetQueueName(m_options.m_queue_name.c_str());
1003 
1004               if (m_options.m_ignore_count != 0)
1005                 location->SetIgnoreCount(m_options.m_ignore_count);
1006 
1007               if (m_options.m_enable_passed)
1008                 location->SetEnabled(m_options.m_enable_value);
1009 
1010               if (m_options.m_condition_passed)
1011                 location->SetCondition(m_options.m_condition.c_str());
1012             }
1013           } else {
1014             if (m_options.m_thread_id_passed)
1015               bp->SetThreadID(m_options.m_thread_id);
1016 
1017             if (m_options.m_thread_index_passed)
1018               bp->SetThreadIndex(m_options.m_thread_index);
1019 
1020             if (m_options.m_name_passed)
1021               bp->SetThreadName(m_options.m_thread_name.c_str());
1022 
1023             if (m_options.m_queue_passed)
1024               bp->SetQueueName(m_options.m_queue_name.c_str());
1025 
1026             if (m_options.m_ignore_count != 0)
1027               bp->SetIgnoreCount(m_options.m_ignore_count);
1028 
1029             if (m_options.m_enable_passed)
1030               bp->SetEnabled(m_options.m_enable_value);
1031 
1032             if (m_options.m_condition_passed)
1033               bp->SetCondition(m_options.m_condition.c_str());
1034           }
1035         }
1036       }
1037     }
1038 
1039     return result.Succeeded();
1040   }
1041 
1042 private:
1043   CommandOptions m_options;
1044 };
1045 
1046 #pragma mark Modify::CommandOptions
1047 OptionDefinition
1048     CommandObjectBreakpointModify::CommandOptions::g_option_table[] = {
1049         // clang-format off
1050   {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."},
1051   {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."},
1052   {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."},
1053   {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."},
1054   {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."},
1055   {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."},
1056   {LLDB_OPT_SET_ALL, false, "condition",    'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression,  "The breakpoint stops only if this condition expression evaluates to true."},
1057   {LLDB_OPT_SET_1,   false, "enable",       'e', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,        "Enable the breakpoint."},
1058   {LLDB_OPT_SET_2,   false, "disable",      'd', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,        "Disable the breakpoint."},
1059   {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."},
1060   {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
1061         // clang-format on
1062 };
1063 
1064 //-------------------------------------------------------------------------
1065 // CommandObjectBreakpointEnable
1066 //-------------------------------------------------------------------------
1067 #pragma mark Enable
1068 
1069 class CommandObjectBreakpointEnable : public CommandObjectParsed {
1070 public:
1071   CommandObjectBreakpointEnable(CommandInterpreter &interpreter)
1072       : CommandObjectParsed(interpreter, "enable",
1073                             "Enable the specified disabled breakpoint(s). If "
1074                             "no breakpoints are specified, enable all of them.",
1075                             nullptr) {
1076     CommandArgumentEntry arg;
1077     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1078                                       eArgTypeBreakpointIDRange);
1079     // Add the entry for the first argument for this command to the object's
1080     // arguments vector.
1081     m_arguments.push_back(arg);
1082   }
1083 
1084   ~CommandObjectBreakpointEnable() override = default;
1085 
1086 protected:
1087   bool DoExecute(Args &command, CommandReturnObject &result) override {
1088     Target *target = GetSelectedOrDummyTarget();
1089     if (target == nullptr) {
1090       result.AppendError("Invalid target.  No existing target or breakpoints.");
1091       result.SetStatus(eReturnStatusFailed);
1092       return false;
1093     }
1094 
1095     std::unique_lock<std::recursive_mutex> lock;
1096     target->GetBreakpointList().GetListMutex(lock);
1097 
1098     const BreakpointList &breakpoints = target->GetBreakpointList();
1099 
1100     size_t num_breakpoints = breakpoints.GetSize();
1101 
1102     if (num_breakpoints == 0) {
1103       result.AppendError("No breakpoints exist to be enabled.");
1104       result.SetStatus(eReturnStatusFailed);
1105       return false;
1106     }
1107 
1108     if (command.GetArgumentCount() == 0) {
1109       // No breakpoint selected; enable all currently set breakpoints.
1110       target->EnableAllBreakpoints();
1111       result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64
1112                                      " breakpoints)\n",
1113                                      (uint64_t)num_breakpoints);
1114       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1115     } else {
1116       // Particular breakpoint selected; enable that breakpoint.
1117       BreakpointIDList valid_bp_ids;
1118       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1119           command, target, result, &valid_bp_ids);
1120 
1121       if (result.Succeeded()) {
1122         int enable_count = 0;
1123         int loc_count = 0;
1124         const size_t count = valid_bp_ids.GetSize();
1125         for (size_t i = 0; i < count; ++i) {
1126           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1127 
1128           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1129             Breakpoint *breakpoint =
1130                 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1131             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1132               BreakpointLocation *location =
1133                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1134               if (location) {
1135                 location->SetEnabled(true);
1136                 ++loc_count;
1137               }
1138             } else {
1139               breakpoint->SetEnabled(true);
1140               ++enable_count;
1141             }
1142           }
1143         }
1144         result.AppendMessageWithFormat("%d breakpoints enabled.\n",
1145                                        enable_count + loc_count);
1146         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1147       }
1148     }
1149 
1150     return result.Succeeded();
1151   }
1152 };
1153 
1154 //-------------------------------------------------------------------------
1155 // CommandObjectBreakpointDisable
1156 //-------------------------------------------------------------------------
1157 #pragma mark Disable
1158 
1159 class CommandObjectBreakpointDisable : public CommandObjectParsed {
1160 public:
1161   CommandObjectBreakpointDisable(CommandInterpreter &interpreter)
1162       : CommandObjectParsed(
1163             interpreter, "breakpoint disable",
1164             "Disable the specified breakpoint(s) without deleting "
1165             "them.  If none are specified, disable all "
1166             "breakpoints.",
1167             nullptr) {
1168     SetHelpLong(
1169         "Disable the specified breakpoint(s) without deleting them.  \
1170 If none are specified, disable all breakpoints."
1171         R"(
1172 
1173 )"
1174         "Note: disabling a breakpoint will cause none of its locations to be hit \
1175 regardless of whether individual locations are enabled or disabled.  After the sequence:"
1176         R"(
1177 
1178     (lldb) break disable 1
1179     (lldb) break enable 1.1
1180 
1181 execution will NOT stop at location 1.1.  To achieve that, type:
1182 
1183     (lldb) break disable 1.*
1184     (lldb) break enable 1.1
1185 
1186 )"
1187         "The first command disables all locations for breakpoint 1, \
1188 the second re-enables the first location.");
1189 
1190     CommandArgumentEntry arg;
1191     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1192                                       eArgTypeBreakpointIDRange);
1193     // Add the entry for the first argument for this command to the object's
1194     // arguments vector.
1195     m_arguments.push_back(arg);
1196   }
1197 
1198   ~CommandObjectBreakpointDisable() override = default;
1199 
1200 protected:
1201   bool DoExecute(Args &command, CommandReturnObject &result) override {
1202     Target *target = GetSelectedOrDummyTarget();
1203     if (target == nullptr) {
1204       result.AppendError("Invalid target.  No existing target or breakpoints.");
1205       result.SetStatus(eReturnStatusFailed);
1206       return false;
1207     }
1208 
1209     std::unique_lock<std::recursive_mutex> lock;
1210     target->GetBreakpointList().GetListMutex(lock);
1211 
1212     const BreakpointList &breakpoints = target->GetBreakpointList();
1213     size_t num_breakpoints = breakpoints.GetSize();
1214 
1215     if (num_breakpoints == 0) {
1216       result.AppendError("No breakpoints exist to be disabled.");
1217       result.SetStatus(eReturnStatusFailed);
1218       return false;
1219     }
1220 
1221     if (command.GetArgumentCount() == 0) {
1222       // No breakpoint selected; disable all currently set breakpoints.
1223       target->DisableAllBreakpoints();
1224       result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu64
1225                                      " breakpoints)\n",
1226                                      (uint64_t)num_breakpoints);
1227       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1228     } else {
1229       // Particular breakpoint selected; disable that breakpoint.
1230       BreakpointIDList valid_bp_ids;
1231 
1232       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1233           command, target, result, &valid_bp_ids);
1234 
1235       if (result.Succeeded()) {
1236         int disable_count = 0;
1237         int loc_count = 0;
1238         const size_t count = valid_bp_ids.GetSize();
1239         for (size_t i = 0; i < count; ++i) {
1240           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1241 
1242           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1243             Breakpoint *breakpoint =
1244                 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1245             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1246               BreakpointLocation *location =
1247                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1248               if (location) {
1249                 location->SetEnabled(false);
1250                 ++loc_count;
1251               }
1252             } else {
1253               breakpoint->SetEnabled(false);
1254               ++disable_count;
1255             }
1256           }
1257         }
1258         result.AppendMessageWithFormat("%d breakpoints disabled.\n",
1259                                        disable_count + loc_count);
1260         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1261       }
1262     }
1263 
1264     return result.Succeeded();
1265   }
1266 };
1267 
1268 //-------------------------------------------------------------------------
1269 // CommandObjectBreakpointList
1270 //-------------------------------------------------------------------------
1271 #pragma mark List
1272 
1273 class CommandObjectBreakpointList : public CommandObjectParsed {
1274 public:
1275   CommandObjectBreakpointList(CommandInterpreter &interpreter)
1276       : CommandObjectParsed(
1277             interpreter, "breakpoint list",
1278             "List some or all breakpoints at configurable levels of detail.",
1279             nullptr),
1280         m_options() {
1281     CommandArgumentEntry arg;
1282     CommandArgumentData bp_id_arg;
1283 
1284     // Define the first (and only) variant of this arg.
1285     bp_id_arg.arg_type = eArgTypeBreakpointID;
1286     bp_id_arg.arg_repetition = eArgRepeatOptional;
1287 
1288     // There is only one variant this argument could be; put it into the
1289     // argument entry.
1290     arg.push_back(bp_id_arg);
1291 
1292     // Push the data for the first argument into the m_arguments vector.
1293     m_arguments.push_back(arg);
1294   }
1295 
1296   ~CommandObjectBreakpointList() override = default;
1297 
1298   Options *GetOptions() override { return &m_options; }
1299 
1300   class CommandOptions : public Options {
1301   public:
1302     CommandOptions()
1303         : Options(), m_level(lldb::eDescriptionLevelBrief), m_use_dummy(false) {
1304     }
1305 
1306     ~CommandOptions() override = default;
1307 
1308     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
1309                          ExecutionContext *execution_context) override {
1310       Error error;
1311       const int short_option = m_getopt_table[option_idx].val;
1312 
1313       switch (short_option) {
1314       case 'b':
1315         m_level = lldb::eDescriptionLevelBrief;
1316         break;
1317       case 'D':
1318         m_use_dummy = true;
1319         break;
1320       case 'f':
1321         m_level = lldb::eDescriptionLevelFull;
1322         break;
1323       case 'v':
1324         m_level = lldb::eDescriptionLevelVerbose;
1325         break;
1326       case 'i':
1327         m_internal = true;
1328         break;
1329       default:
1330         error.SetErrorStringWithFormat("unrecognized option '%c'",
1331                                        short_option);
1332         break;
1333       }
1334 
1335       return error;
1336     }
1337 
1338     void OptionParsingStarting(ExecutionContext *execution_context) override {
1339       m_level = lldb::eDescriptionLevelFull;
1340       m_internal = false;
1341       m_use_dummy = false;
1342     }
1343 
1344     const OptionDefinition *GetDefinitions() override { return g_option_table; }
1345 
1346     // Options table: Required for subclasses of Options.
1347 
1348     static OptionDefinition g_option_table[];
1349 
1350     // Instance variables to hold the values for command options.
1351 
1352     lldb::DescriptionLevel m_level;
1353 
1354     bool m_internal;
1355     bool m_use_dummy;
1356   };
1357 
1358 protected:
1359   bool DoExecute(Args &command, CommandReturnObject &result) override {
1360     Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
1361 
1362     if (target == nullptr) {
1363       result.AppendError("Invalid target. No current target or breakpoints.");
1364       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1365       return true;
1366     }
1367 
1368     const BreakpointList &breakpoints =
1369         target->GetBreakpointList(m_options.m_internal);
1370     std::unique_lock<std::recursive_mutex> lock;
1371     target->GetBreakpointList(m_options.m_internal).GetListMutex(lock);
1372 
1373     size_t num_breakpoints = breakpoints.GetSize();
1374 
1375     if (num_breakpoints == 0) {
1376       result.AppendMessage("No breakpoints currently set.");
1377       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1378       return true;
1379     }
1380 
1381     Stream &output_stream = result.GetOutputStream();
1382 
1383     if (command.GetArgumentCount() == 0) {
1384       // No breakpoint selected; show info about all currently set breakpoints.
1385       result.AppendMessage("Current breakpoints:");
1386       for (size_t i = 0; i < num_breakpoints; ++i) {
1387         Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get();
1388         AddBreakpointDescription(&output_stream, breakpoint, m_options.m_level);
1389       }
1390       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1391     } else {
1392       // Particular breakpoints selected; show info about that breakpoint.
1393       BreakpointIDList valid_bp_ids;
1394       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1395           command, target, result, &valid_bp_ids);
1396 
1397       if (result.Succeeded()) {
1398         for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) {
1399           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1400           Breakpoint *breakpoint =
1401               target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1402           AddBreakpointDescription(&output_stream, breakpoint,
1403                                    m_options.m_level);
1404         }
1405         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1406       } else {
1407         result.AppendError("Invalid breakpoint ID.");
1408         result.SetStatus(eReturnStatusFailed);
1409       }
1410     }
1411 
1412     return result.Succeeded();
1413   }
1414 
1415 private:
1416   CommandOptions m_options;
1417 };
1418 
1419 #pragma mark List::CommandOptions
1420 OptionDefinition CommandObjectBreakpointList::CommandOptions::g_option_table[] =
1421     {
1422         // clang-format off
1423     {LLDB_OPT_SET_ALL, false, "internal",          'i', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show debugger internal breakpoints" },
1424     {LLDB_OPT_SET_1,   false, "brief",             'b', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a brief description of the breakpoint (no location info)."},
1425     // FIXME: We need to add an "internal" command, and then add this sort of thing to it.
1426     // But I need to see it for now, and don't want to wait.
1427     {LLDB_OPT_SET_2,   false, "full",              'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a full description of the breakpoint and its locations."},
1428     {LLDB_OPT_SET_3,   false, "verbose",           'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Explain everything we know about the breakpoint (for debugging debugger bugs)."},
1429     {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."},
1430     {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
1431         // clang-format on
1432 };
1433 
1434 //-------------------------------------------------------------------------
1435 // CommandObjectBreakpointClear
1436 //-------------------------------------------------------------------------
1437 #pragma mark Clear
1438 
1439 class CommandObjectBreakpointClear : public CommandObjectParsed {
1440 public:
1441   typedef enum BreakpointClearType {
1442     eClearTypeInvalid,
1443     eClearTypeFileAndLine
1444   } BreakpointClearType;
1445 
1446   CommandObjectBreakpointClear(CommandInterpreter &interpreter)
1447       : CommandObjectParsed(interpreter, "breakpoint clear",
1448                             "Delete or disable breakpoints matching the "
1449                             "specified source file and line.",
1450                             "breakpoint clear <cmd-options>"),
1451         m_options() {}
1452 
1453   ~CommandObjectBreakpointClear() override = default;
1454 
1455   Options *GetOptions() override { return &m_options; }
1456 
1457   class CommandOptions : public Options {
1458   public:
1459     CommandOptions() : Options(), m_filename(), m_line_num(0) {}
1460 
1461     ~CommandOptions() override = default;
1462 
1463     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
1464                          ExecutionContext *execution_context) override {
1465       Error error;
1466       const int short_option = m_getopt_table[option_idx].val;
1467 
1468       switch (short_option) {
1469       case 'f':
1470         m_filename.assign(option_arg);
1471         break;
1472 
1473       case 'l':
1474         m_line_num = StringConvert::ToUInt32(option_arg, 0);
1475         break;
1476 
1477       default:
1478         error.SetErrorStringWithFormat("unrecognized option '%c'",
1479                                        short_option);
1480         break;
1481       }
1482 
1483       return error;
1484     }
1485 
1486     void OptionParsingStarting(ExecutionContext *execution_context) override {
1487       m_filename.clear();
1488       m_line_num = 0;
1489     }
1490 
1491     const OptionDefinition *GetDefinitions() override { return g_option_table; }
1492 
1493     // Options table: Required for subclasses of Options.
1494 
1495     static OptionDefinition g_option_table[];
1496 
1497     // Instance variables to hold the values for command options.
1498 
1499     std::string m_filename;
1500     uint32_t m_line_num;
1501   };
1502 
1503 protected:
1504   bool DoExecute(Args &command, CommandReturnObject &result) override {
1505     Target *target = GetSelectedOrDummyTarget();
1506     if (target == nullptr) {
1507       result.AppendError("Invalid target. No existing target or breakpoints.");
1508       result.SetStatus(eReturnStatusFailed);
1509       return false;
1510     }
1511 
1512     // The following are the various types of breakpoints that could be cleared:
1513     //   1). -f -l (clearing breakpoint by source location)
1514 
1515     BreakpointClearType break_type = eClearTypeInvalid;
1516 
1517     if (m_options.m_line_num != 0)
1518       break_type = eClearTypeFileAndLine;
1519 
1520     std::unique_lock<std::recursive_mutex> lock;
1521     target->GetBreakpointList().GetListMutex(lock);
1522 
1523     BreakpointList &breakpoints = target->GetBreakpointList();
1524     size_t num_breakpoints = breakpoints.GetSize();
1525 
1526     // Early return if there's no breakpoint at all.
1527     if (num_breakpoints == 0) {
1528       result.AppendError("Breakpoint clear: No breakpoint cleared.");
1529       result.SetStatus(eReturnStatusFailed);
1530       return result.Succeeded();
1531     }
1532 
1533     // Find matching breakpoints and delete them.
1534 
1535     // First create a copy of all the IDs.
1536     std::vector<break_id_t> BreakIDs;
1537     for (size_t i = 0; i < num_breakpoints; ++i)
1538       BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID());
1539 
1540     int num_cleared = 0;
1541     StreamString ss;
1542     switch (break_type) {
1543     case eClearTypeFileAndLine: // Breakpoint by source position
1544     {
1545       const ConstString filename(m_options.m_filename.c_str());
1546       BreakpointLocationCollection loc_coll;
1547 
1548       for (size_t i = 0; i < num_breakpoints; ++i) {
1549         Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get();
1550 
1551         if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) {
1552           // If the collection size is 0, it's a full match and we can just
1553           // remove the breakpoint.
1554           if (loc_coll.GetSize() == 0) {
1555             bp->GetDescription(&ss, lldb::eDescriptionLevelBrief);
1556             ss.EOL();
1557             target->RemoveBreakpointByID(bp->GetID());
1558             ++num_cleared;
1559           }
1560         }
1561       }
1562     } break;
1563 
1564     default:
1565       break;
1566     }
1567 
1568     if (num_cleared > 0) {
1569       Stream &output_stream = result.GetOutputStream();
1570       output_stream.Printf("%d breakpoints cleared:\n", num_cleared);
1571       output_stream << ss.GetData();
1572       output_stream.EOL();
1573       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1574     } else {
1575       result.AppendError("Breakpoint clear: No breakpoint cleared.");
1576       result.SetStatus(eReturnStatusFailed);
1577     }
1578 
1579     return result.Succeeded();
1580   }
1581 
1582 private:
1583   CommandOptions m_options;
1584 };
1585 
1586 #pragma mark Clear::CommandOptions
1587 
1588 OptionDefinition
1589     CommandObjectBreakpointClear::CommandOptions::g_option_table[] = {
1590         // clang-format off
1591   {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specify the breakpoint by source location in this particular file."},
1592   {LLDB_OPT_SET_1, true,  "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeLineNum,  "Specify the breakpoint by source location at this particular line."},
1593   {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
1594         // clang-format on
1595 };
1596 
1597 //-------------------------------------------------------------------------
1598 // CommandObjectBreakpointDelete
1599 //-------------------------------------------------------------------------
1600 #pragma mark Delete
1601 
1602 class CommandObjectBreakpointDelete : public CommandObjectParsed {
1603 public:
1604   CommandObjectBreakpointDelete(CommandInterpreter &interpreter)
1605       : CommandObjectParsed(interpreter, "breakpoint delete",
1606                             "Delete the specified breakpoint(s).  If no "
1607                             "breakpoints are specified, delete them all.",
1608                             nullptr),
1609         m_options() {
1610     CommandArgumentEntry arg;
1611     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1612                                       eArgTypeBreakpointIDRange);
1613     // Add the entry for the first argument for this command to the object's
1614     // arguments vector.
1615     m_arguments.push_back(arg);
1616   }
1617 
1618   ~CommandObjectBreakpointDelete() override = default;
1619 
1620   Options *GetOptions() override { return &m_options; }
1621 
1622   class CommandOptions : public Options {
1623   public:
1624     CommandOptions() : Options(), m_use_dummy(false), m_force(false) {}
1625 
1626     ~CommandOptions() override = default;
1627 
1628     Error SetOptionValue(uint32_t option_idx, const char *option_arg,
1629                          ExecutionContext *execution_context) override {
1630       Error error;
1631       const int short_option = m_getopt_table[option_idx].val;
1632 
1633       switch (short_option) {
1634       case 'f':
1635         m_force = true;
1636         break;
1637 
1638       case 'D':
1639         m_use_dummy = true;
1640         break;
1641 
1642       default:
1643         error.SetErrorStringWithFormat("unrecognized option '%c'",
1644                                        short_option);
1645         break;
1646       }
1647 
1648       return error;
1649     }
1650 
1651     void OptionParsingStarting(ExecutionContext *execution_context) override {
1652       m_use_dummy = false;
1653       m_force = false;
1654     }
1655 
1656     const OptionDefinition *GetDefinitions() override { return g_option_table; }
1657 
1658     // Options table: Required for subclasses of Options.
1659 
1660     static OptionDefinition g_option_table[];
1661 
1662     // Instance variables to hold the values for command options.
1663     bool m_use_dummy;
1664     bool m_force;
1665   };
1666 
1667 protected:
1668   bool DoExecute(Args &command, CommandReturnObject &result) override {
1669     Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
1670 
1671     if (target == nullptr) {
1672       result.AppendError("Invalid target. No existing target or breakpoints.");
1673       result.SetStatus(eReturnStatusFailed);
1674       return false;
1675     }
1676 
1677     std::unique_lock<std::recursive_mutex> lock;
1678     target->GetBreakpointList().GetListMutex(lock);
1679 
1680     const BreakpointList &breakpoints = target->GetBreakpointList();
1681 
1682     size_t num_breakpoints = breakpoints.GetSize();
1683 
1684     if (num_breakpoints == 0) {
1685       result.AppendError("No breakpoints exist to be deleted.");
1686       result.SetStatus(eReturnStatusFailed);
1687       return false;
1688     }
1689 
1690     if (command.GetArgumentCount() == 0) {
1691       if (!m_options.m_force &&
1692           !m_interpreter.Confirm(
1693               "About to delete all breakpoints, do you want to do that?",
1694               true)) {
1695         result.AppendMessage("Operation cancelled...");
1696       } else {
1697         target->RemoveAllBreakpoints();
1698         result.AppendMessageWithFormat(
1699             "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n",
1700             (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : "");
1701       }
1702       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1703     } else {
1704       // Particular breakpoint selected; disable that breakpoint.
1705       BreakpointIDList valid_bp_ids;
1706       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1707           command, target, result, &valid_bp_ids);
1708 
1709       if (result.Succeeded()) {
1710         int delete_count = 0;
1711         int disable_count = 0;
1712         const size_t count = valid_bp_ids.GetSize();
1713         for (size_t i = 0; i < count; ++i) {
1714           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1715 
1716           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1717             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1718               Breakpoint *breakpoint =
1719                   target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1720               BreakpointLocation *location =
1721                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1722               // It makes no sense to try to delete individual locations, so we
1723               // disable them instead.
1724               if (location) {
1725                 location->SetEnabled(false);
1726                 ++disable_count;
1727               }
1728             } else {
1729               target->RemoveBreakpointByID(cur_bp_id.GetBreakpointID());
1730               ++delete_count;
1731             }
1732           }
1733         }
1734         result.AppendMessageWithFormat(
1735             "%d breakpoints deleted; %d breakpoint locations disabled.\n",
1736             delete_count, disable_count);
1737         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1738       }
1739     }
1740     return result.Succeeded();
1741   }
1742 
1743 private:
1744   CommandOptions m_options;
1745 };
1746 
1747 OptionDefinition
1748     CommandObjectBreakpointDelete::CommandOptions::g_option_table[] = {
1749         // clang-format off
1750   {LLDB_OPT_SET_1, false, "force",             'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Delete all breakpoints without querying for confirmation."},
1751   {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."},
1752   {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}
1753         // clang-format on
1754 };
1755 
1756 //-------------------------------------------------------------------------
1757 // CommandObjectBreakpointName
1758 //-------------------------------------------------------------------------
1759 
1760 static OptionDefinition g_breakpoint_name_options[] = {
1761     // clang-format off
1762   {LLDB_OPT_SET_1,   false, "name",              'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."},
1763   {LLDB_OPT_SET_2,   false, "breakpoint-id",     'B', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointID,   "Specify a breakpoint ID to use."},
1764   {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."},
1765     // clang-format on
1766 };
1767 class BreakpointNameOptionGroup : public OptionGroup {
1768 public:
1769   BreakpointNameOptionGroup()
1770       : OptionGroup(), m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) {
1771   }
1772 
1773   ~BreakpointNameOptionGroup() override = default;
1774 
1775   uint32_t GetNumDefinitions() override {
1776     return sizeof(g_breakpoint_name_options) / sizeof(OptionDefinition);
1777   }
1778 
1779   const OptionDefinition *GetDefinitions() override {
1780     return g_breakpoint_name_options;
1781   }
1782 
1783   Error SetOptionValue(uint32_t option_idx, const char *option_value,
1784                        ExecutionContext *execution_context) override {
1785     Error error;
1786     const int short_option = g_breakpoint_name_options[option_idx].short_option;
1787 
1788     switch (short_option) {
1789     case 'N':
1790       if (BreakpointID::StringIsBreakpointName(option_value, error) &&
1791           error.Success())
1792         m_name.SetValueFromString(option_value);
1793       break;
1794 
1795     case 'B':
1796       if (m_breakpoint.SetValueFromString(option_value).Fail())
1797         error.SetErrorStringWithFormat(
1798             "unrecognized value \"%s\" for breakpoint", option_value);
1799       break;
1800     case 'D':
1801       if (m_use_dummy.SetValueFromString(option_value).Fail())
1802         error.SetErrorStringWithFormat(
1803             "unrecognized value \"%s\" for use-dummy", option_value);
1804       break;
1805 
1806     default:
1807       error.SetErrorStringWithFormat("unrecognized short option '%c'",
1808                                      short_option);
1809       break;
1810     }
1811     return error;
1812   }
1813 
1814   void OptionParsingStarting(ExecutionContext *execution_context) override {
1815     m_name.Clear();
1816     m_breakpoint.Clear();
1817     m_use_dummy.Clear();
1818     m_use_dummy.SetDefaultValue(false);
1819   }
1820 
1821   OptionValueString m_name;
1822   OptionValueUInt64 m_breakpoint;
1823   OptionValueBoolean m_use_dummy;
1824 };
1825 
1826 class CommandObjectBreakpointNameAdd : public CommandObjectParsed {
1827 public:
1828   CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter)
1829       : CommandObjectParsed(
1830             interpreter, "add", "Add a name to the breakpoints provided.",
1831             "breakpoint name add <command-options> <breakpoint-id-list>"),
1832         m_name_options(), m_option_group() {
1833     // Create the first variant for the first (and only) argument for this
1834     // command.
1835     CommandArgumentEntry arg1;
1836     CommandArgumentData id_arg;
1837     id_arg.arg_type = eArgTypeBreakpointID;
1838     id_arg.arg_repetition = eArgRepeatOptional;
1839     arg1.push_back(id_arg);
1840     m_arguments.push_back(arg1);
1841 
1842     m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
1843     m_option_group.Finalize();
1844   }
1845 
1846   ~CommandObjectBreakpointNameAdd() override = default;
1847 
1848   Options *GetOptions() override { return &m_option_group; }
1849 
1850 protected:
1851   bool DoExecute(Args &command, CommandReturnObject &result) override {
1852     if (!m_name_options.m_name.OptionWasSet()) {
1853       result.SetError("No name option provided.");
1854       return false;
1855     }
1856 
1857     Target *target =
1858         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1859 
1860     if (target == nullptr) {
1861       result.AppendError("Invalid target. No existing target or breakpoints.");
1862       result.SetStatus(eReturnStatusFailed);
1863       return false;
1864     }
1865 
1866     std::unique_lock<std::recursive_mutex> lock;
1867     target->GetBreakpointList().GetListMutex(lock);
1868 
1869     const BreakpointList &breakpoints = target->GetBreakpointList();
1870 
1871     size_t num_breakpoints = breakpoints.GetSize();
1872     if (num_breakpoints == 0) {
1873       result.SetError("No breakpoints, cannot add names.");
1874       result.SetStatus(eReturnStatusFailed);
1875       return false;
1876     }
1877 
1878     // Particular breakpoint selected; disable that breakpoint.
1879     BreakpointIDList valid_bp_ids;
1880     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
1881         command, target, result, &valid_bp_ids);
1882 
1883     if (result.Succeeded()) {
1884       if (valid_bp_ids.GetSize() == 0) {
1885         result.SetError("No breakpoints specified, cannot add names.");
1886         result.SetStatus(eReturnStatusFailed);
1887         return false;
1888       }
1889       size_t num_valid_ids = valid_bp_ids.GetSize();
1890       for (size_t index = 0; index < num_valid_ids; index++) {
1891         lldb::break_id_t bp_id =
1892             valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
1893         BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
1894         Error error; // We don't need to check the error here, since the option
1895                      // parser checked it...
1896         bp_sp->AddName(m_name_options.m_name.GetCurrentValue(), error);
1897       }
1898     }
1899 
1900     return true;
1901   }
1902 
1903 private:
1904   BreakpointNameOptionGroup m_name_options;
1905   OptionGroupOptions m_option_group;
1906 };
1907 
1908 class CommandObjectBreakpointNameDelete : public CommandObjectParsed {
1909 public:
1910   CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter)
1911       : CommandObjectParsed(
1912             interpreter, "delete",
1913             "Delete a name from the breakpoints provided.",
1914             "breakpoint name delete <command-options> <breakpoint-id-list>"),
1915         m_name_options(), m_option_group() {
1916     // Create the first variant for the first (and only) argument for this
1917     // command.
1918     CommandArgumentEntry arg1;
1919     CommandArgumentData id_arg;
1920     id_arg.arg_type = eArgTypeBreakpointID;
1921     id_arg.arg_repetition = eArgRepeatOptional;
1922     arg1.push_back(id_arg);
1923     m_arguments.push_back(arg1);
1924 
1925     m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
1926     m_option_group.Finalize();
1927   }
1928 
1929   ~CommandObjectBreakpointNameDelete() override = default;
1930 
1931   Options *GetOptions() override { return &m_option_group; }
1932 
1933 protected:
1934   bool DoExecute(Args &command, CommandReturnObject &result) override {
1935     if (!m_name_options.m_name.OptionWasSet()) {
1936       result.SetError("No name option provided.");
1937       return false;
1938     }
1939 
1940     Target *target =
1941         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1942 
1943     if (target == nullptr) {
1944       result.AppendError("Invalid target. No existing target or breakpoints.");
1945       result.SetStatus(eReturnStatusFailed);
1946       return false;
1947     }
1948 
1949     std::unique_lock<std::recursive_mutex> lock;
1950     target->GetBreakpointList().GetListMutex(lock);
1951 
1952     const BreakpointList &breakpoints = target->GetBreakpointList();
1953 
1954     size_t num_breakpoints = breakpoints.GetSize();
1955     if (num_breakpoints == 0) {
1956       result.SetError("No breakpoints, cannot delete names.");
1957       result.SetStatus(eReturnStatusFailed);
1958       return false;
1959     }
1960 
1961     // Particular breakpoint selected; disable that breakpoint.
1962     BreakpointIDList valid_bp_ids;
1963     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
1964         command, target, result, &valid_bp_ids);
1965 
1966     if (result.Succeeded()) {
1967       if (valid_bp_ids.GetSize() == 0) {
1968         result.SetError("No breakpoints specified, cannot delete names.");
1969         result.SetStatus(eReturnStatusFailed);
1970         return false;
1971       }
1972       size_t num_valid_ids = valid_bp_ids.GetSize();
1973       for (size_t index = 0; index < num_valid_ids; index++) {
1974         lldb::break_id_t bp_id =
1975             valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
1976         BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
1977         bp_sp->RemoveName(m_name_options.m_name.GetCurrentValue());
1978       }
1979     }
1980 
1981     return true;
1982   }
1983 
1984 private:
1985   BreakpointNameOptionGroup m_name_options;
1986   OptionGroupOptions m_option_group;
1987 };
1988 
1989 class CommandObjectBreakpointNameList : public CommandObjectParsed {
1990 public:
1991   CommandObjectBreakpointNameList(CommandInterpreter &interpreter)
1992       : CommandObjectParsed(interpreter, "list",
1993                             "List either the names for a breakpoint or the "
1994                             "breakpoints for a given name.",
1995                             "breakpoint name list <command-options>"),
1996         m_name_options(), m_option_group() {
1997     m_option_group.Append(&m_name_options);
1998     m_option_group.Finalize();
1999   }
2000 
2001   ~CommandObjectBreakpointNameList() override = default;
2002 
2003   Options *GetOptions() override { return &m_option_group; }
2004 
2005 protected:
2006   bool DoExecute(Args &command, CommandReturnObject &result) override {
2007     Target *target =
2008         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
2009 
2010     if (target == nullptr) {
2011       result.AppendError("Invalid target. No existing target or breakpoints.");
2012       result.SetStatus(eReturnStatusFailed);
2013       return false;
2014     }
2015 
2016     if (m_name_options.m_name.OptionWasSet()) {
2017       const char *name = m_name_options.m_name.GetCurrentValue();
2018       std::unique_lock<std::recursive_mutex> lock;
2019       target->GetBreakpointList().GetListMutex(lock);
2020 
2021       BreakpointList &breakpoints = target->GetBreakpointList();
2022       for (BreakpointSP bp_sp : breakpoints.Breakpoints()) {
2023         if (bp_sp->MatchesName(name)) {
2024           StreamString s;
2025           bp_sp->GetDescription(&s, eDescriptionLevelBrief);
2026           s.EOL();
2027           result.AppendMessage(s.GetData());
2028         }
2029       }
2030 
2031     } else if (m_name_options.m_breakpoint.OptionWasSet()) {
2032       BreakpointSP bp_sp = target->GetBreakpointList().FindBreakpointByID(
2033           m_name_options.m_breakpoint.GetCurrentValue());
2034       if (bp_sp) {
2035         std::vector<std::string> names;
2036         bp_sp->GetNames(names);
2037         result.AppendMessage("Names:");
2038         for (auto name : names)
2039           result.AppendMessageWithFormat("    %s\n", name.c_str());
2040       } else {
2041         result.AppendErrorWithFormat(
2042             "Could not find breakpoint %" PRId64 ".\n",
2043             m_name_options.m_breakpoint.GetCurrentValue());
2044         result.SetStatus(eReturnStatusFailed);
2045         return false;
2046       }
2047     } else {
2048       result.SetError("Must specify -N or -B option to list.");
2049       result.SetStatus(eReturnStatusFailed);
2050       return false;
2051     }
2052     return true;
2053   }
2054 
2055 private:
2056   BreakpointNameOptionGroup m_name_options;
2057   OptionGroupOptions m_option_group;
2058 };
2059 
2060 //-------------------------------------------------------------------------
2061 // CommandObjectMultiwordBreakpoint
2062 //-------------------------------------------------------------------------
2063 class CommandObjectBreakpointName : public CommandObjectMultiword {
2064 public:
2065   CommandObjectBreakpointName(CommandInterpreter &interpreter)
2066       : CommandObjectMultiword(
2067             interpreter, "name", "Commands to manage name tags for breakpoints",
2068             "breakpoint name <subcommand> [<command-options>]") {
2069     CommandObjectSP add_command_object(
2070         new CommandObjectBreakpointNameAdd(interpreter));
2071     CommandObjectSP delete_command_object(
2072         new CommandObjectBreakpointNameDelete(interpreter));
2073     CommandObjectSP list_command_object(
2074         new CommandObjectBreakpointNameList(interpreter));
2075 
2076     LoadSubCommand("add", add_command_object);
2077     LoadSubCommand("delete", delete_command_object);
2078     LoadSubCommand("list", list_command_object);
2079   }
2080 
2081   ~CommandObjectBreakpointName() override = default;
2082 };
2083 
2084 //-------------------------------------------------------------------------
2085 // CommandObjectMultiwordBreakpoint
2086 //-------------------------------------------------------------------------
2087 #pragma mark MultiwordBreakpoint
2088 
2089 CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
2090     CommandInterpreter &interpreter)
2091     : CommandObjectMultiword(
2092           interpreter, "breakpoint",
2093           "Commands for operating on breakpoints (see 'help b' for shorthand.)",
2094           "breakpoint <subcommand> [<command-options>]") {
2095   CommandObjectSP list_command_object(
2096       new CommandObjectBreakpointList(interpreter));
2097   CommandObjectSP enable_command_object(
2098       new CommandObjectBreakpointEnable(interpreter));
2099   CommandObjectSP disable_command_object(
2100       new CommandObjectBreakpointDisable(interpreter));
2101   CommandObjectSP clear_command_object(
2102       new CommandObjectBreakpointClear(interpreter));
2103   CommandObjectSP delete_command_object(
2104       new CommandObjectBreakpointDelete(interpreter));
2105   CommandObjectSP set_command_object(
2106       new CommandObjectBreakpointSet(interpreter));
2107   CommandObjectSP command_command_object(
2108       new CommandObjectBreakpointCommand(interpreter));
2109   CommandObjectSP modify_command_object(
2110       new CommandObjectBreakpointModify(interpreter));
2111   CommandObjectSP name_command_object(
2112       new CommandObjectBreakpointName(interpreter));
2113 
2114   list_command_object->SetCommandName("breakpoint list");
2115   enable_command_object->SetCommandName("breakpoint enable");
2116   disable_command_object->SetCommandName("breakpoint disable");
2117   clear_command_object->SetCommandName("breakpoint clear");
2118   delete_command_object->SetCommandName("breakpoint delete");
2119   set_command_object->SetCommandName("breakpoint set");
2120   command_command_object->SetCommandName("breakpoint command");
2121   modify_command_object->SetCommandName("breakpoint modify");
2122   name_command_object->SetCommandName("breakpoint name");
2123 
2124   LoadSubCommand("list", list_command_object);
2125   LoadSubCommand("enable", enable_command_object);
2126   LoadSubCommand("disable", disable_command_object);
2127   LoadSubCommand("clear", clear_command_object);
2128   LoadSubCommand("delete", delete_command_object);
2129   LoadSubCommand("set", set_command_object);
2130   LoadSubCommand("command", command_command_object);
2131   LoadSubCommand("modify", modify_command_object);
2132   LoadSubCommand("name", name_command_object);
2133 }
2134 
2135 CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default;
2136 
2137 void CommandObjectMultiwordBreakpoint::VerifyIDs(Args &args, Target *target,
2138                                                  bool allow_locations,
2139                                                  CommandReturnObject &result,
2140                                                  BreakpointIDList *valid_ids) {
2141   // args can be strings representing 1). integers (for breakpoint ids)
2142   //                                  2). the full breakpoint & location
2143   //                                  canonical representation
2144   //                                  3). the word "to" or a hyphen,
2145   //                                  representing a range (in which case there
2146   //                                      had *better* be an entry both before &
2147   //                                      after of one of the first two types.
2148   //                                  4). A breakpoint name
2149   // If args is empty, we will use the last created breakpoint (if there is
2150   // one.)
2151 
2152   Args temp_args;
2153 
2154   if (args.GetArgumentCount() == 0) {
2155     if (target->GetLastCreatedBreakpoint()) {
2156       valid_ids->AddBreakpointID(BreakpointID(
2157           target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID));
2158       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2159     } else {
2160       result.AppendError(
2161           "No breakpoint specified and no last created breakpoint.");
2162       result.SetStatus(eReturnStatusFailed);
2163     }
2164     return;
2165   }
2166 
2167   // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff
2168   // directly from the old ARGS to
2169   // the new TEMP_ARGS.  Do not copy breakpoint id range strings over; instead
2170   // generate a list of strings for
2171   // all the breakpoint ids in the range, and shove all of those breakpoint id
2172   // strings into TEMP_ARGS.
2173 
2174   BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations,
2175                                            result, temp_args);
2176 
2177   // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual
2178   // BreakpointIDList:
2179 
2180   valid_ids->InsertStringArray(temp_args.GetConstArgumentVector(),
2181                                temp_args.GetArgumentCount(), result);
2182 
2183   // At this point,  all of the breakpoint ids that the user passed in have been
2184   // converted to breakpoint IDs
2185   // and put into valid_ids.
2186 
2187   if (result.Succeeded()) {
2188     // Now that we've converted everything from args into a list of breakpoint
2189     // ids, go through our tentative list
2190     // of breakpoint id's and verify that they correspond to valid/currently set
2191     // breakpoints.
2192 
2193     const size_t count = valid_ids->GetSize();
2194     for (size_t i = 0; i < count; ++i) {
2195       BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex(i);
2196       Breakpoint *breakpoint =
2197           target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
2198       if (breakpoint != nullptr) {
2199         const size_t num_locations = breakpoint->GetNumLocations();
2200         if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) {
2201           StreamString id_str;
2202           BreakpointID::GetCanonicalReference(
2203               &id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
2204           i = valid_ids->GetSize() + 1;
2205           result.AppendErrorWithFormat(
2206               "'%s' is not a currently valid breakpoint/location id.\n",
2207               id_str.GetData());
2208           result.SetStatus(eReturnStatusFailed);
2209         }
2210       } else {
2211         i = valid_ids->GetSize() + 1;
2212         result.AppendErrorWithFormat(
2213             "'%d' is not a currently valid breakpoint ID.\n",
2214             cur_bp_id.GetBreakpointID());
2215         result.SetStatus(eReturnStatusFailed);
2216       }
2217     }
2218   }
2219 }
2220