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