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