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