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