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