xref: /openbsd-src/gnu/llvm/lldb/source/Commands/CommandObjectBreakpoint.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- CommandObjectBreakpoint.cpp ---------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "CommandObjectBreakpoint.h"
10061da546Spatrick #include "CommandObjectBreakpointCommand.h"
11061da546Spatrick #include "lldb/Breakpoint/Breakpoint.h"
12061da546Spatrick #include "lldb/Breakpoint/BreakpointIDList.h"
13061da546Spatrick #include "lldb/Breakpoint/BreakpointLocation.h"
14061da546Spatrick #include "lldb/Host/OptionParser.h"
15061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
16*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
18061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
19061da546Spatrick #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
20061da546Spatrick #include "lldb/Interpreter/OptionValueBoolean.h"
21be691f3bSpatrick #include "lldb/Interpreter/OptionValueFileColonLine.h"
22061da546Spatrick #include "lldb/Interpreter/OptionValueString.h"
23061da546Spatrick #include "lldb/Interpreter/OptionValueUInt64.h"
24061da546Spatrick #include "lldb/Interpreter/Options.h"
25061da546Spatrick #include "lldb/Target/Language.h"
26061da546Spatrick #include "lldb/Target/StackFrame.h"
27061da546Spatrick #include "lldb/Target/Target.h"
28061da546Spatrick #include "lldb/Target/ThreadSpec.h"
29061da546Spatrick #include "lldb/Utility/RegularExpression.h"
30061da546Spatrick #include "lldb/Utility/StreamString.h"
31061da546Spatrick 
32061da546Spatrick #include <memory>
33*f6aab3d8Srobert #include <optional>
34061da546Spatrick #include <vector>
35061da546Spatrick 
36061da546Spatrick using namespace lldb;
37061da546Spatrick using namespace lldb_private;
38061da546Spatrick 
AddBreakpointDescription(Stream * s,Breakpoint * bp,lldb::DescriptionLevel level)39061da546Spatrick static void AddBreakpointDescription(Stream *s, Breakpoint *bp,
40061da546Spatrick                                      lldb::DescriptionLevel level) {
41061da546Spatrick   s->IndentMore();
42061da546Spatrick   bp->GetDescription(s, level, true);
43061da546Spatrick   s->IndentLess();
44061da546Spatrick   s->EOL();
45061da546Spatrick }
46061da546Spatrick 
47061da546Spatrick // Modifiable Breakpoint Options
48061da546Spatrick #pragma mark Modify::CommandOptions
49061da546Spatrick #define LLDB_OPTIONS_breakpoint_modify
50061da546Spatrick #include "CommandOptions.inc"
51061da546Spatrick 
52061da546Spatrick class lldb_private::BreakpointOptionGroup : public OptionGroup {
53061da546Spatrick public:
BreakpointOptionGroup()54*f6aab3d8Srobert   BreakpointOptionGroup() : m_bp_opts(false) {}
55061da546Spatrick 
56061da546Spatrick   ~BreakpointOptionGroup() override = default;
57061da546Spatrick 
GetDefinitions()58061da546Spatrick   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
59*f6aab3d8Srobert     return llvm::ArrayRef(g_breakpoint_modify_options);
60061da546Spatrick   }
61061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)62061da546Spatrick   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
63061da546Spatrick                         ExecutionContext *execution_context) override {
64061da546Spatrick     Status error;
65061da546Spatrick     const int short_option =
66061da546Spatrick         g_breakpoint_modify_options[option_idx].short_option;
67061da546Spatrick 
68061da546Spatrick     switch (short_option) {
69061da546Spatrick     case 'c':
70061da546Spatrick       // Normally an empty breakpoint condition marks is as unset. But we need
71061da546Spatrick       // to say it was passed in.
72061da546Spatrick       m_bp_opts.SetCondition(option_arg.str().c_str());
73061da546Spatrick       m_bp_opts.m_set_flags.Set(BreakpointOptions::eCondition);
74061da546Spatrick       break;
75061da546Spatrick     case 'C':
76dda28197Spatrick       m_commands.push_back(std::string(option_arg));
77061da546Spatrick       break;
78061da546Spatrick     case 'd':
79061da546Spatrick       m_bp_opts.SetEnabled(false);
80061da546Spatrick       break;
81061da546Spatrick     case 'e':
82061da546Spatrick       m_bp_opts.SetEnabled(true);
83061da546Spatrick       break;
84061da546Spatrick     case 'G': {
85061da546Spatrick       bool value, success;
86061da546Spatrick       value = OptionArgParser::ToBoolean(option_arg, false, &success);
87061da546Spatrick       if (success) {
88061da546Spatrick         m_bp_opts.SetAutoContinue(value);
89061da546Spatrick       } else
90061da546Spatrick         error.SetErrorStringWithFormat(
91061da546Spatrick             "invalid boolean value '%s' passed for -G option",
92061da546Spatrick             option_arg.str().c_str());
93061da546Spatrick     } break;
94061da546Spatrick     case 'i': {
95061da546Spatrick       uint32_t ignore_count;
96061da546Spatrick       if (option_arg.getAsInteger(0, ignore_count))
97061da546Spatrick         error.SetErrorStringWithFormat("invalid ignore count '%s'",
98061da546Spatrick                                        option_arg.str().c_str());
99061da546Spatrick       else
100061da546Spatrick         m_bp_opts.SetIgnoreCount(ignore_count);
101061da546Spatrick     } break;
102061da546Spatrick     case 'o': {
103061da546Spatrick       bool value, success;
104061da546Spatrick       value = OptionArgParser::ToBoolean(option_arg, false, &success);
105061da546Spatrick       if (success) {
106061da546Spatrick         m_bp_opts.SetOneShot(value);
107061da546Spatrick       } else
108061da546Spatrick         error.SetErrorStringWithFormat(
109061da546Spatrick             "invalid boolean value '%s' passed for -o option",
110061da546Spatrick             option_arg.str().c_str());
111061da546Spatrick     } break;
112061da546Spatrick     case 't': {
113061da546Spatrick       lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID;
114*f6aab3d8Srobert       if (option_arg == "current") {
115*f6aab3d8Srobert         if (!execution_context) {
116*f6aab3d8Srobert           error.SetErrorStringWithFormat("No context to determine current "
117*f6aab3d8Srobert                                          "thread");
118*f6aab3d8Srobert         } else {
119*f6aab3d8Srobert           ThreadSP ctx_thread_sp = execution_context->GetThreadSP();
120*f6aab3d8Srobert           if (!ctx_thread_sp || !ctx_thread_sp->IsValid()) {
121*f6aab3d8Srobert             error.SetErrorStringWithFormat("No currently selected thread");
122*f6aab3d8Srobert           } else {
123*f6aab3d8Srobert             thread_id = ctx_thread_sp->GetID();
124*f6aab3d8Srobert           }
125*f6aab3d8Srobert         }
126*f6aab3d8Srobert       } else if (option_arg.getAsInteger(0, thread_id)) {
127061da546Spatrick         error.SetErrorStringWithFormat("invalid thread id string '%s'",
128061da546Spatrick                                        option_arg.str().c_str());
129061da546Spatrick       }
130*f6aab3d8Srobert       if (thread_id != LLDB_INVALID_THREAD_ID)
131061da546Spatrick         m_bp_opts.SetThreadID(thread_id);
132061da546Spatrick     } break;
133061da546Spatrick     case 'T':
134061da546Spatrick       m_bp_opts.GetThreadSpec()->SetName(option_arg.str().c_str());
135061da546Spatrick       break;
136061da546Spatrick     case 'q':
137061da546Spatrick       m_bp_opts.GetThreadSpec()->SetQueueName(option_arg.str().c_str());
138061da546Spatrick       break;
139061da546Spatrick     case 'x': {
140061da546Spatrick       uint32_t thread_index = UINT32_MAX;
141*f6aab3d8Srobert       if (option_arg.getAsInteger(0, thread_index)) {
142061da546Spatrick         error.SetErrorStringWithFormat("invalid thread index string '%s'",
143061da546Spatrick                                        option_arg.str().c_str());
144*f6aab3d8Srobert       } else {
145061da546Spatrick         m_bp_opts.GetThreadSpec()->SetIndex(thread_index);
146*f6aab3d8Srobert       }
147061da546Spatrick     } break;
148061da546Spatrick     default:
149061da546Spatrick       llvm_unreachable("Unimplemented option");
150061da546Spatrick     }
151061da546Spatrick 
152061da546Spatrick     return error;
153061da546Spatrick   }
154061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)155061da546Spatrick   void OptionParsingStarting(ExecutionContext *execution_context) override {
156061da546Spatrick     m_bp_opts.Clear();
157061da546Spatrick     m_commands.clear();
158061da546Spatrick   }
159061da546Spatrick 
OptionParsingFinished(ExecutionContext * execution_context)160061da546Spatrick   Status OptionParsingFinished(ExecutionContext *execution_context) override {
161061da546Spatrick     if (!m_commands.empty()) {
162061da546Spatrick       auto cmd_data = std::make_unique<BreakpointOptions::CommandData>();
163061da546Spatrick 
164061da546Spatrick       for (std::string &str : m_commands)
165061da546Spatrick         cmd_data->user_source.AppendString(str);
166061da546Spatrick 
167061da546Spatrick       cmd_data->stop_on_error = true;
168061da546Spatrick       m_bp_opts.SetCommandDataCallback(cmd_data);
169061da546Spatrick     }
170061da546Spatrick     return Status();
171061da546Spatrick   }
172061da546Spatrick 
GetBreakpointOptions()173061da546Spatrick   const BreakpointOptions &GetBreakpointOptions() { return m_bp_opts; }
174061da546Spatrick 
175061da546Spatrick   std::vector<std::string> m_commands;
176061da546Spatrick   BreakpointOptions m_bp_opts;
177061da546Spatrick };
178061da546Spatrick 
179061da546Spatrick #define LLDB_OPTIONS_breakpoint_dummy
180061da546Spatrick #include "CommandOptions.inc"
181061da546Spatrick 
182061da546Spatrick class BreakpointDummyOptionGroup : public OptionGroup {
183061da546Spatrick public:
184*f6aab3d8Srobert   BreakpointDummyOptionGroup() = default;
185061da546Spatrick 
186061da546Spatrick   ~BreakpointDummyOptionGroup() override = default;
187061da546Spatrick 
GetDefinitions()188061da546Spatrick   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
189*f6aab3d8Srobert     return llvm::ArrayRef(g_breakpoint_dummy_options);
190061da546Spatrick   }
191061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)192061da546Spatrick   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
193061da546Spatrick                         ExecutionContext *execution_context) override {
194061da546Spatrick     Status error;
195061da546Spatrick     const int short_option =
196061da546Spatrick         g_breakpoint_dummy_options[option_idx].short_option;
197061da546Spatrick 
198061da546Spatrick     switch (short_option) {
199061da546Spatrick     case 'D':
200061da546Spatrick       m_use_dummy = true;
201061da546Spatrick       break;
202061da546Spatrick     default:
203061da546Spatrick       llvm_unreachable("Unimplemented option");
204061da546Spatrick     }
205061da546Spatrick 
206061da546Spatrick     return error;
207061da546Spatrick   }
208061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)209061da546Spatrick   void OptionParsingStarting(ExecutionContext *execution_context) override {
210061da546Spatrick     m_use_dummy = false;
211061da546Spatrick   }
212061da546Spatrick 
213061da546Spatrick   bool m_use_dummy;
214061da546Spatrick };
215061da546Spatrick 
216061da546Spatrick #define LLDB_OPTIONS_breakpoint_set
217061da546Spatrick #include "CommandOptions.inc"
218061da546Spatrick 
219061da546Spatrick // CommandObjectBreakpointSet
220061da546Spatrick 
221061da546Spatrick class CommandObjectBreakpointSet : public CommandObjectParsed {
222061da546Spatrick public:
223061da546Spatrick   enum BreakpointSetType {
224061da546Spatrick     eSetTypeInvalid,
225061da546Spatrick     eSetTypeFileAndLine,
226061da546Spatrick     eSetTypeAddress,
227061da546Spatrick     eSetTypeFunctionName,
228061da546Spatrick     eSetTypeFunctionRegexp,
229061da546Spatrick     eSetTypeSourceRegexp,
230061da546Spatrick     eSetTypeException,
231061da546Spatrick     eSetTypeScripted,
232061da546Spatrick   };
233061da546Spatrick 
CommandObjectBreakpointSet(CommandInterpreter & interpreter)234061da546Spatrick   CommandObjectBreakpointSet(CommandInterpreter &interpreter)
235061da546Spatrick       : CommandObjectParsed(
236061da546Spatrick             interpreter, "breakpoint set",
237061da546Spatrick             "Sets a breakpoint or set of breakpoints in the executable.",
238061da546Spatrick             "breakpoint set <cmd-options>"),
239*f6aab3d8Srobert         m_python_class_options("scripted breakpoint", true, 'P') {
240061da546Spatrick     // We're picking up all the normal options, commands and disable.
241061da546Spatrick     m_all_options.Append(&m_python_class_options,
242061da546Spatrick                          LLDB_OPT_SET_1 | LLDB_OPT_SET_2, LLDB_OPT_SET_11);
243061da546Spatrick     m_all_options.Append(&m_bp_opts,
244061da546Spatrick                          LLDB_OPT_SET_1 | LLDB_OPT_SET_3 | LLDB_OPT_SET_4,
245061da546Spatrick                          LLDB_OPT_SET_ALL);
246061da546Spatrick     m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
247061da546Spatrick     m_all_options.Append(&m_options);
248061da546Spatrick     m_all_options.Finalize();
249061da546Spatrick   }
250061da546Spatrick 
251061da546Spatrick   ~CommandObjectBreakpointSet() override = default;
252061da546Spatrick 
GetOptions()253061da546Spatrick   Options *GetOptions() override { return &m_all_options; }
254061da546Spatrick 
255061da546Spatrick   class CommandOptions : public OptionGroup {
256061da546Spatrick   public:
257*f6aab3d8Srobert     CommandOptions() = default;
258061da546Spatrick 
259061da546Spatrick     ~CommandOptions() override = default;
260061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)261061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
262061da546Spatrick                           ExecutionContext *execution_context) override {
263061da546Spatrick       Status error;
264061da546Spatrick       const int short_option =
265061da546Spatrick           g_breakpoint_set_options[option_idx].short_option;
266061da546Spatrick 
267061da546Spatrick       switch (short_option) {
268061da546Spatrick       case 'a': {
269061da546Spatrick         m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg,
270061da546Spatrick                                                  LLDB_INVALID_ADDRESS, &error);
271061da546Spatrick       } break;
272061da546Spatrick 
273061da546Spatrick       case 'A':
274061da546Spatrick         m_all_files = true;
275061da546Spatrick         break;
276061da546Spatrick 
277061da546Spatrick       case 'b':
278dda28197Spatrick         m_func_names.push_back(std::string(option_arg));
279061da546Spatrick         m_func_name_type_mask |= eFunctionNameTypeBase;
280061da546Spatrick         break;
281061da546Spatrick 
282dda28197Spatrick       case 'u':
283061da546Spatrick         if (option_arg.getAsInteger(0, m_column))
284061da546Spatrick           error.SetErrorStringWithFormat("invalid column number: %s",
285061da546Spatrick                                          option_arg.str().c_str());
286061da546Spatrick         break;
287061da546Spatrick 
288061da546Spatrick       case 'E': {
289061da546Spatrick         LanguageType language = Language::GetLanguageTypeFromString(option_arg);
290061da546Spatrick 
291061da546Spatrick         switch (language) {
292061da546Spatrick         case eLanguageTypeC89:
293061da546Spatrick         case eLanguageTypeC:
294061da546Spatrick         case eLanguageTypeC99:
295061da546Spatrick         case eLanguageTypeC11:
296061da546Spatrick           m_exception_language = eLanguageTypeC;
297061da546Spatrick           break;
298061da546Spatrick         case eLanguageTypeC_plus_plus:
299061da546Spatrick         case eLanguageTypeC_plus_plus_03:
300061da546Spatrick         case eLanguageTypeC_plus_plus_11:
301061da546Spatrick         case eLanguageTypeC_plus_plus_14:
302061da546Spatrick           m_exception_language = eLanguageTypeC_plus_plus;
303061da546Spatrick           break;
304061da546Spatrick         case eLanguageTypeObjC:
305061da546Spatrick           m_exception_language = eLanguageTypeObjC;
306061da546Spatrick           break;
307061da546Spatrick         case eLanguageTypeObjC_plus_plus:
308061da546Spatrick           error.SetErrorStringWithFormat(
309061da546Spatrick               "Set exception breakpoints separately for c++ and objective-c");
310061da546Spatrick           break;
311061da546Spatrick         case eLanguageTypeUnknown:
312061da546Spatrick           error.SetErrorStringWithFormat(
313061da546Spatrick               "Unknown language type: '%s' for exception breakpoint",
314061da546Spatrick               option_arg.str().c_str());
315061da546Spatrick           break;
316061da546Spatrick         default:
317061da546Spatrick           error.SetErrorStringWithFormat(
318061da546Spatrick               "Unsupported language type: '%s' for exception breakpoint",
319061da546Spatrick               option_arg.str().c_str());
320061da546Spatrick         }
321061da546Spatrick       } break;
322061da546Spatrick 
323061da546Spatrick       case 'f':
324061da546Spatrick         m_filenames.AppendIfUnique(FileSpec(option_arg));
325061da546Spatrick         break;
326061da546Spatrick 
327061da546Spatrick       case 'F':
328dda28197Spatrick         m_func_names.push_back(std::string(option_arg));
329061da546Spatrick         m_func_name_type_mask |= eFunctionNameTypeFull;
330061da546Spatrick         break;
331061da546Spatrick 
332061da546Spatrick       case 'h': {
333061da546Spatrick         bool success;
334061da546Spatrick         m_catch_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
335061da546Spatrick         if (!success)
336061da546Spatrick           error.SetErrorStringWithFormat(
337061da546Spatrick               "Invalid boolean value for on-catch option: '%s'",
338061da546Spatrick               option_arg.str().c_str());
339061da546Spatrick       } break;
340061da546Spatrick 
341061da546Spatrick       case 'H':
342061da546Spatrick         m_hardware = true;
343061da546Spatrick         break;
344061da546Spatrick 
345061da546Spatrick       case 'K': {
346061da546Spatrick         bool success;
347061da546Spatrick         bool value;
348061da546Spatrick         value = OptionArgParser::ToBoolean(option_arg, true, &success);
349061da546Spatrick         if (value)
350061da546Spatrick           m_skip_prologue = eLazyBoolYes;
351061da546Spatrick         else
352061da546Spatrick           m_skip_prologue = eLazyBoolNo;
353061da546Spatrick 
354061da546Spatrick         if (!success)
355061da546Spatrick           error.SetErrorStringWithFormat(
356061da546Spatrick               "Invalid boolean value for skip prologue option: '%s'",
357061da546Spatrick               option_arg.str().c_str());
358061da546Spatrick       } break;
359061da546Spatrick 
360061da546Spatrick       case 'l':
361061da546Spatrick         if (option_arg.getAsInteger(0, m_line_num))
362061da546Spatrick           error.SetErrorStringWithFormat("invalid line number: %s.",
363061da546Spatrick                                          option_arg.str().c_str());
364061da546Spatrick         break;
365061da546Spatrick 
366061da546Spatrick       case 'L':
367061da546Spatrick         m_language = Language::GetLanguageTypeFromString(option_arg);
368061da546Spatrick         if (m_language == eLanguageTypeUnknown)
369061da546Spatrick           error.SetErrorStringWithFormat(
370061da546Spatrick               "Unknown language type: '%s' for breakpoint",
371061da546Spatrick               option_arg.str().c_str());
372061da546Spatrick         break;
373061da546Spatrick 
374061da546Spatrick       case 'm': {
375061da546Spatrick         bool success;
376061da546Spatrick         bool value;
377061da546Spatrick         value = OptionArgParser::ToBoolean(option_arg, true, &success);
378061da546Spatrick         if (value)
379061da546Spatrick           m_move_to_nearest_code = eLazyBoolYes;
380061da546Spatrick         else
381061da546Spatrick           m_move_to_nearest_code = eLazyBoolNo;
382061da546Spatrick 
383061da546Spatrick         if (!success)
384061da546Spatrick           error.SetErrorStringWithFormat(
385061da546Spatrick               "Invalid boolean value for move-to-nearest-code option: '%s'",
386061da546Spatrick               option_arg.str().c_str());
387061da546Spatrick         break;
388061da546Spatrick       }
389061da546Spatrick 
390061da546Spatrick       case 'M':
391dda28197Spatrick         m_func_names.push_back(std::string(option_arg));
392061da546Spatrick         m_func_name_type_mask |= eFunctionNameTypeMethod;
393061da546Spatrick         break;
394061da546Spatrick 
395061da546Spatrick       case 'n':
396dda28197Spatrick         m_func_names.push_back(std::string(option_arg));
397061da546Spatrick         m_func_name_type_mask |= eFunctionNameTypeAuto;
398061da546Spatrick         break;
399061da546Spatrick 
400061da546Spatrick       case 'N': {
401061da546Spatrick         if (BreakpointID::StringIsBreakpointName(option_arg, error))
402dda28197Spatrick           m_breakpoint_names.push_back(std::string(option_arg));
403061da546Spatrick         else
404061da546Spatrick           error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
405061da546Spatrick                                          option_arg.str().c_str());
406061da546Spatrick         break;
407061da546Spatrick       }
408061da546Spatrick 
409061da546Spatrick       case 'R': {
410061da546Spatrick         lldb::addr_t tmp_offset_addr;
411061da546Spatrick         tmp_offset_addr = OptionArgParser::ToAddress(execution_context,
412061da546Spatrick                                                      option_arg, 0, &error);
413061da546Spatrick         if (error.Success())
414061da546Spatrick           m_offset_addr = tmp_offset_addr;
415061da546Spatrick       } break;
416061da546Spatrick 
417061da546Spatrick       case 'O':
418061da546Spatrick         m_exception_extra_args.AppendArgument("-O");
419061da546Spatrick         m_exception_extra_args.AppendArgument(option_arg);
420061da546Spatrick         break;
421061da546Spatrick 
422061da546Spatrick       case 'p':
423dda28197Spatrick         m_source_text_regexp.assign(std::string(option_arg));
424061da546Spatrick         break;
425061da546Spatrick 
426061da546Spatrick       case 'r':
427dda28197Spatrick         m_func_regexp.assign(std::string(option_arg));
428061da546Spatrick         break;
429061da546Spatrick 
430061da546Spatrick       case 's':
431061da546Spatrick         m_modules.AppendIfUnique(FileSpec(option_arg));
432061da546Spatrick         break;
433061da546Spatrick 
434061da546Spatrick       case 'S':
435dda28197Spatrick         m_func_names.push_back(std::string(option_arg));
436061da546Spatrick         m_func_name_type_mask |= eFunctionNameTypeSelector;
437061da546Spatrick         break;
438061da546Spatrick 
439061da546Spatrick       case 'w': {
440061da546Spatrick         bool success;
441061da546Spatrick         m_throw_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
442061da546Spatrick         if (!success)
443061da546Spatrick           error.SetErrorStringWithFormat(
444061da546Spatrick               "Invalid boolean value for on-throw option: '%s'",
445061da546Spatrick               option_arg.str().c_str());
446061da546Spatrick       } break;
447061da546Spatrick 
448061da546Spatrick       case 'X':
449dda28197Spatrick         m_source_regex_func_names.insert(std::string(option_arg));
450061da546Spatrick         break;
451061da546Spatrick 
452be691f3bSpatrick       case 'y':
453be691f3bSpatrick       {
454be691f3bSpatrick         OptionValueFileColonLine value;
455be691f3bSpatrick         Status fcl_err = value.SetValueFromString(option_arg);
456be691f3bSpatrick         if (!fcl_err.Success()) {
457be691f3bSpatrick           error.SetErrorStringWithFormat(
458be691f3bSpatrick               "Invalid value for file:line specifier: %s",
459be691f3bSpatrick               fcl_err.AsCString());
460be691f3bSpatrick         } else {
461be691f3bSpatrick           m_filenames.AppendIfUnique(value.GetFileSpec());
462be691f3bSpatrick           m_line_num = value.GetLineNumber();
463be691f3bSpatrick           m_column = value.GetColumnNumber();
464be691f3bSpatrick         }
465be691f3bSpatrick       } break;
466be691f3bSpatrick 
467061da546Spatrick       default:
468061da546Spatrick         llvm_unreachable("Unimplemented option");
469061da546Spatrick       }
470061da546Spatrick 
471061da546Spatrick       return error;
472061da546Spatrick     }
473061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)474061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
475061da546Spatrick       m_filenames.Clear();
476061da546Spatrick       m_line_num = 0;
477061da546Spatrick       m_column = 0;
478061da546Spatrick       m_func_names.clear();
479061da546Spatrick       m_func_name_type_mask = eFunctionNameTypeNone;
480061da546Spatrick       m_func_regexp.clear();
481061da546Spatrick       m_source_text_regexp.clear();
482061da546Spatrick       m_modules.Clear();
483061da546Spatrick       m_load_addr = LLDB_INVALID_ADDRESS;
484061da546Spatrick       m_offset_addr = 0;
485061da546Spatrick       m_catch_bp = false;
486061da546Spatrick       m_throw_bp = true;
487061da546Spatrick       m_hardware = false;
488061da546Spatrick       m_exception_language = eLanguageTypeUnknown;
489061da546Spatrick       m_language = lldb::eLanguageTypeUnknown;
490061da546Spatrick       m_skip_prologue = eLazyBoolCalculate;
491061da546Spatrick       m_breakpoint_names.clear();
492061da546Spatrick       m_all_files = false;
493061da546Spatrick       m_exception_extra_args.Clear();
494061da546Spatrick       m_move_to_nearest_code = eLazyBoolCalculate;
495061da546Spatrick       m_source_regex_func_names.clear();
496061da546Spatrick       m_current_key.clear();
497061da546Spatrick     }
498061da546Spatrick 
GetDefinitions()499061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
500*f6aab3d8Srobert       return llvm::ArrayRef(g_breakpoint_set_options);
501061da546Spatrick     }
502061da546Spatrick 
503061da546Spatrick     // Instance variables to hold the values for command options.
504061da546Spatrick 
505061da546Spatrick     std::string m_condition;
506061da546Spatrick     FileSpecList m_filenames;
507be691f3bSpatrick     uint32_t m_line_num = 0;
508be691f3bSpatrick     uint32_t m_column = 0;
509061da546Spatrick     std::vector<std::string> m_func_names;
510061da546Spatrick     std::vector<std::string> m_breakpoint_names;
511be691f3bSpatrick     lldb::FunctionNameType m_func_name_type_mask = eFunctionNameTypeNone;
512061da546Spatrick     std::string m_func_regexp;
513061da546Spatrick     std::string m_source_text_regexp;
514061da546Spatrick     FileSpecList m_modules;
515be691f3bSpatrick     lldb::addr_t m_load_addr = 0;
516061da546Spatrick     lldb::addr_t m_offset_addr;
517be691f3bSpatrick     bool m_catch_bp = false;
518be691f3bSpatrick     bool m_throw_bp = true;
519be691f3bSpatrick     bool m_hardware = false; // Request to use hardware breakpoints
520be691f3bSpatrick     lldb::LanguageType m_exception_language = eLanguageTypeUnknown;
521be691f3bSpatrick     lldb::LanguageType m_language = lldb::eLanguageTypeUnknown;
522be691f3bSpatrick     LazyBool m_skip_prologue = eLazyBoolCalculate;
523be691f3bSpatrick     bool m_all_files = false;
524061da546Spatrick     Args m_exception_extra_args;
525be691f3bSpatrick     LazyBool m_move_to_nearest_code = eLazyBoolCalculate;
526061da546Spatrick     std::unordered_set<std::string> m_source_regex_func_names;
527061da546Spatrick     std::string m_current_key;
528061da546Spatrick   };
529061da546Spatrick 
530061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)531061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
532061da546Spatrick     Target &target = GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy);
533061da546Spatrick 
534061da546Spatrick     // The following are the various types of breakpoints that could be set:
535061da546Spatrick     //   1).  -f -l -p  [-s -g]   (setting breakpoint by source location)
536061da546Spatrick     //   2).  -a  [-s -g]         (setting breakpoint by address)
537061da546Spatrick     //   3).  -n  [-s -g]         (setting breakpoint by function name)
538061da546Spatrick     //   4).  -r  [-s -g]         (setting breakpoint by function name regular
539061da546Spatrick     //   expression)
540061da546Spatrick     //   5).  -p -f               (setting a breakpoint by comparing a reg-exp
541061da546Spatrick     //   to source text)
542061da546Spatrick     //   6).  -E [-w -h]          (setting a breakpoint for exceptions for a
543061da546Spatrick     //   given language.)
544061da546Spatrick 
545061da546Spatrick     BreakpointSetType break_type = eSetTypeInvalid;
546061da546Spatrick 
547061da546Spatrick     if (!m_python_class_options.GetName().empty())
548061da546Spatrick       break_type = eSetTypeScripted;
549061da546Spatrick     else if (m_options.m_line_num != 0)
550061da546Spatrick       break_type = eSetTypeFileAndLine;
551061da546Spatrick     else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
552061da546Spatrick       break_type = eSetTypeAddress;
553061da546Spatrick     else if (!m_options.m_func_names.empty())
554061da546Spatrick       break_type = eSetTypeFunctionName;
555061da546Spatrick     else if (!m_options.m_func_regexp.empty())
556061da546Spatrick       break_type = eSetTypeFunctionRegexp;
557061da546Spatrick     else if (!m_options.m_source_text_regexp.empty())
558061da546Spatrick       break_type = eSetTypeSourceRegexp;
559061da546Spatrick     else if (m_options.m_exception_language != eLanguageTypeUnknown)
560061da546Spatrick       break_type = eSetTypeException;
561061da546Spatrick 
562061da546Spatrick     BreakpointSP bp_sp = nullptr;
563061da546Spatrick     FileSpec module_spec;
564061da546Spatrick     const bool internal = false;
565061da546Spatrick 
566061da546Spatrick     // If the user didn't specify skip-prologue, having an offset should turn
567061da546Spatrick     // that off.
568061da546Spatrick     if (m_options.m_offset_addr != 0 &&
569061da546Spatrick         m_options.m_skip_prologue == eLazyBoolCalculate)
570061da546Spatrick       m_options.m_skip_prologue = eLazyBoolNo;
571061da546Spatrick 
572061da546Spatrick     switch (break_type) {
573061da546Spatrick     case eSetTypeFileAndLine: // Breakpoint by source position
574061da546Spatrick     {
575061da546Spatrick       FileSpec file;
576061da546Spatrick       const size_t num_files = m_options.m_filenames.GetSize();
577061da546Spatrick       if (num_files == 0) {
578061da546Spatrick         if (!GetDefaultFile(target, file, result)) {
579061da546Spatrick           result.AppendError("No file supplied and no default file available.");
580061da546Spatrick           return false;
581061da546Spatrick         }
582061da546Spatrick       } else if (num_files > 1) {
583061da546Spatrick         result.AppendError("Only one file at a time is allowed for file and "
584061da546Spatrick                            "line breakpoints.");
585061da546Spatrick         return false;
586061da546Spatrick       } else
587061da546Spatrick         file = m_options.m_filenames.GetFileSpecAtIndex(0);
588061da546Spatrick 
589061da546Spatrick       // Only check for inline functions if
590061da546Spatrick       LazyBool check_inlines = eLazyBoolCalculate;
591061da546Spatrick 
592061da546Spatrick       bp_sp = target.CreateBreakpoint(
593061da546Spatrick           &(m_options.m_modules), file, m_options.m_line_num,
594061da546Spatrick           m_options.m_column, m_options.m_offset_addr, check_inlines,
595061da546Spatrick           m_options.m_skip_prologue, internal, m_options.m_hardware,
596061da546Spatrick           m_options.m_move_to_nearest_code);
597061da546Spatrick     } break;
598061da546Spatrick 
599061da546Spatrick     case eSetTypeAddress: // Breakpoint by address
600061da546Spatrick     {
601061da546Spatrick       // If a shared library has been specified, make an lldb_private::Address
602061da546Spatrick       // with the library, and use that.  That way the address breakpoint
603061da546Spatrick       //  will track the load location of the library.
604061da546Spatrick       size_t num_modules_specified = m_options.m_modules.GetSize();
605061da546Spatrick       if (num_modules_specified == 1) {
606061da546Spatrick         const FileSpec *file_spec =
607061da546Spatrick             m_options.m_modules.GetFileSpecPointerAtIndex(0);
608061da546Spatrick         bp_sp = target.CreateAddressInModuleBreakpoint(
609061da546Spatrick             m_options.m_load_addr, internal, file_spec, m_options.m_hardware);
610061da546Spatrick       } else if (num_modules_specified == 0) {
611061da546Spatrick         bp_sp = target.CreateBreakpoint(m_options.m_load_addr, internal,
612061da546Spatrick                                         m_options.m_hardware);
613061da546Spatrick       } else {
614061da546Spatrick         result.AppendError("Only one shared library can be specified for "
615061da546Spatrick                            "address breakpoints.");
616061da546Spatrick         return false;
617061da546Spatrick       }
618061da546Spatrick       break;
619061da546Spatrick     }
620061da546Spatrick     case eSetTypeFunctionName: // Breakpoint by function name
621061da546Spatrick     {
622061da546Spatrick       FunctionNameType name_type_mask = m_options.m_func_name_type_mask;
623061da546Spatrick 
624061da546Spatrick       if (name_type_mask == 0)
625061da546Spatrick         name_type_mask = eFunctionNameTypeAuto;
626061da546Spatrick 
627061da546Spatrick       bp_sp = target.CreateBreakpoint(
628061da546Spatrick           &(m_options.m_modules), &(m_options.m_filenames),
629061da546Spatrick           m_options.m_func_names, name_type_mask, m_options.m_language,
630061da546Spatrick           m_options.m_offset_addr, m_options.m_skip_prologue, internal,
631061da546Spatrick           m_options.m_hardware);
632061da546Spatrick     } break;
633061da546Spatrick 
634061da546Spatrick     case eSetTypeFunctionRegexp: // Breakpoint by regular expression function
635061da546Spatrick                                  // name
636061da546Spatrick     {
637061da546Spatrick       RegularExpression regexp(m_options.m_func_regexp);
638061da546Spatrick       if (llvm::Error err = regexp.GetError()) {
639061da546Spatrick         result.AppendErrorWithFormat(
640dda28197Spatrick             "Function name regular expression could not be compiled: %s",
641061da546Spatrick             llvm::toString(std::move(err)).c_str());
642dda28197Spatrick         // Check if the incorrect regex looks like a globbing expression and
643dda28197Spatrick         // warn the user about it.
644dda28197Spatrick         if (!m_options.m_func_regexp.empty()) {
645dda28197Spatrick           if (m_options.m_func_regexp[0] == '*' ||
646dda28197Spatrick               m_options.m_func_regexp[0] == '?')
647dda28197Spatrick             result.AppendWarning(
648dda28197Spatrick                 "Function name regex does not accept glob patterns.");
649dda28197Spatrick         }
650061da546Spatrick         return false;
651061da546Spatrick       }
652061da546Spatrick 
653061da546Spatrick       bp_sp = target.CreateFuncRegexBreakpoint(
654061da546Spatrick           &(m_options.m_modules), &(m_options.m_filenames), std::move(regexp),
655061da546Spatrick           m_options.m_language, m_options.m_skip_prologue, internal,
656061da546Spatrick           m_options.m_hardware);
657061da546Spatrick     } break;
658061da546Spatrick     case eSetTypeSourceRegexp: // Breakpoint by regexp on source text.
659061da546Spatrick     {
660061da546Spatrick       const size_t num_files = m_options.m_filenames.GetSize();
661061da546Spatrick 
662061da546Spatrick       if (num_files == 0 && !m_options.m_all_files) {
663061da546Spatrick         FileSpec file;
664061da546Spatrick         if (!GetDefaultFile(target, file, result)) {
665061da546Spatrick           result.AppendError(
666061da546Spatrick               "No files provided and could not find default file.");
667061da546Spatrick           return false;
668061da546Spatrick         } else {
669061da546Spatrick           m_options.m_filenames.Append(file);
670061da546Spatrick         }
671061da546Spatrick       }
672061da546Spatrick 
673061da546Spatrick       RegularExpression regexp(m_options.m_source_text_regexp);
674061da546Spatrick       if (llvm::Error err = regexp.GetError()) {
675061da546Spatrick         result.AppendErrorWithFormat(
676061da546Spatrick             "Source text regular expression could not be compiled: \"%s\"",
677061da546Spatrick             llvm::toString(std::move(err)).c_str());
678061da546Spatrick         return false;
679061da546Spatrick       }
680061da546Spatrick       bp_sp = target.CreateSourceRegexBreakpoint(
681061da546Spatrick           &(m_options.m_modules), &(m_options.m_filenames),
682061da546Spatrick           m_options.m_source_regex_func_names, std::move(regexp), internal,
683061da546Spatrick           m_options.m_hardware, m_options.m_move_to_nearest_code);
684061da546Spatrick     } break;
685061da546Spatrick     case eSetTypeException: {
686061da546Spatrick       Status precond_error;
687061da546Spatrick       bp_sp = target.CreateExceptionBreakpoint(
688061da546Spatrick           m_options.m_exception_language, m_options.m_catch_bp,
689061da546Spatrick           m_options.m_throw_bp, internal, &m_options.m_exception_extra_args,
690061da546Spatrick           &precond_error);
691061da546Spatrick       if (precond_error.Fail()) {
692061da546Spatrick         result.AppendErrorWithFormat(
693061da546Spatrick             "Error setting extra exception arguments: %s",
694061da546Spatrick             precond_error.AsCString());
695061da546Spatrick         target.RemoveBreakpointByID(bp_sp->GetID());
696061da546Spatrick         return false;
697061da546Spatrick       }
698061da546Spatrick     } break;
699061da546Spatrick     case eSetTypeScripted: {
700061da546Spatrick 
701061da546Spatrick       Status error;
702061da546Spatrick       bp_sp = target.CreateScriptedBreakpoint(
703061da546Spatrick           m_python_class_options.GetName().c_str(), &(m_options.m_modules),
704061da546Spatrick           &(m_options.m_filenames), false, m_options.m_hardware,
705061da546Spatrick           m_python_class_options.GetStructuredData(), &error);
706061da546Spatrick       if (error.Fail()) {
707061da546Spatrick         result.AppendErrorWithFormat(
708061da546Spatrick             "Error setting extra exception arguments: %s", error.AsCString());
709061da546Spatrick         target.RemoveBreakpointByID(bp_sp->GetID());
710061da546Spatrick         return false;
711061da546Spatrick       }
712061da546Spatrick     } break;
713061da546Spatrick     default:
714061da546Spatrick       break;
715061da546Spatrick     }
716061da546Spatrick 
717061da546Spatrick     // Now set the various options that were passed in:
718061da546Spatrick     if (bp_sp) {
719be691f3bSpatrick       bp_sp->GetOptions().CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
720061da546Spatrick 
721061da546Spatrick       if (!m_options.m_breakpoint_names.empty()) {
722061da546Spatrick         Status name_error;
723061da546Spatrick         for (auto name : m_options.m_breakpoint_names) {
724061da546Spatrick           target.AddNameToBreakpoint(bp_sp, name.c_str(), name_error);
725061da546Spatrick           if (name_error.Fail()) {
726061da546Spatrick             result.AppendErrorWithFormat("Invalid breakpoint name: %s",
727061da546Spatrick                                          name.c_str());
728061da546Spatrick             target.RemoveBreakpointByID(bp_sp->GetID());
729061da546Spatrick             return false;
730061da546Spatrick           }
731061da546Spatrick         }
732061da546Spatrick       }
733061da546Spatrick     }
734061da546Spatrick 
735061da546Spatrick     if (bp_sp) {
736061da546Spatrick       Stream &output_stream = result.GetOutputStream();
737061da546Spatrick       const bool show_locations = false;
738061da546Spatrick       bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
739061da546Spatrick                             show_locations);
740061da546Spatrick       if (&target == &GetDummyTarget())
741061da546Spatrick         output_stream.Printf("Breakpoint set in dummy target, will get copied "
742061da546Spatrick                              "into future targets.\n");
743061da546Spatrick       else {
744061da546Spatrick         // Don't print out this warning for exception breakpoints.  They can
745061da546Spatrick         // get set before the target is set, but we won't know how to actually
746061da546Spatrick         // set the breakpoint till we run.
747061da546Spatrick         if (bp_sp->GetNumLocations() == 0 && break_type != eSetTypeException) {
748061da546Spatrick           output_stream.Printf("WARNING:  Unable to resolve breakpoint to any "
749061da546Spatrick                                "actual locations.\n");
750061da546Spatrick         }
751061da546Spatrick       }
752061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishResult);
753061da546Spatrick     } else if (!bp_sp) {
754061da546Spatrick       result.AppendError("Breakpoint creation failed: No breakpoint created.");
755061da546Spatrick     }
756061da546Spatrick 
757061da546Spatrick     return result.Succeeded();
758061da546Spatrick   }
759061da546Spatrick 
760061da546Spatrick private:
GetDefaultFile(Target & target,FileSpec & file,CommandReturnObject & result)761061da546Spatrick   bool GetDefaultFile(Target &target, FileSpec &file,
762061da546Spatrick                       CommandReturnObject &result) {
763061da546Spatrick     uint32_t default_line;
764061da546Spatrick     // First use the Source Manager's default file. Then use the current stack
765061da546Spatrick     // frame's file.
766061da546Spatrick     if (!target.GetSourceManager().GetDefaultFileAndLine(file, default_line)) {
767061da546Spatrick       StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
768061da546Spatrick       if (cur_frame == nullptr) {
769061da546Spatrick         result.AppendError(
770061da546Spatrick             "No selected frame to use to find the default file.");
771061da546Spatrick         return false;
772061da546Spatrick       } else if (!cur_frame->HasDebugInformation()) {
773061da546Spatrick         result.AppendError("Cannot use the selected frame to find the default "
774061da546Spatrick                            "file, it has no debug info.");
775061da546Spatrick         return false;
776061da546Spatrick       } else {
777061da546Spatrick         const SymbolContext &sc =
778061da546Spatrick             cur_frame->GetSymbolContext(eSymbolContextLineEntry);
779061da546Spatrick         if (sc.line_entry.file) {
780061da546Spatrick           file = sc.line_entry.file;
781061da546Spatrick         } else {
782061da546Spatrick           result.AppendError("Can't find the file for the selected frame to "
783061da546Spatrick                              "use as the default file.");
784061da546Spatrick           return false;
785061da546Spatrick         }
786061da546Spatrick       }
787061da546Spatrick     }
788061da546Spatrick     return true;
789061da546Spatrick   }
790061da546Spatrick 
791061da546Spatrick   BreakpointOptionGroup m_bp_opts;
792061da546Spatrick   BreakpointDummyOptionGroup m_dummy_options;
793061da546Spatrick   OptionGroupPythonClassWithDict m_python_class_options;
794061da546Spatrick   CommandOptions m_options;
795061da546Spatrick   OptionGroupOptions m_all_options;
796061da546Spatrick };
797061da546Spatrick 
798061da546Spatrick // CommandObjectBreakpointModify
799061da546Spatrick #pragma mark Modify
800061da546Spatrick 
801061da546Spatrick class CommandObjectBreakpointModify : public CommandObjectParsed {
802061da546Spatrick public:
CommandObjectBreakpointModify(CommandInterpreter & interpreter)803061da546Spatrick   CommandObjectBreakpointModify(CommandInterpreter &interpreter)
804061da546Spatrick       : CommandObjectParsed(interpreter, "breakpoint modify",
805061da546Spatrick                             "Modify the options on a breakpoint or set of "
806061da546Spatrick                             "breakpoints in the executable.  "
807061da546Spatrick                             "If no breakpoint is specified, acts on the last "
808061da546Spatrick                             "created breakpoint.  "
809061da546Spatrick                             "With the exception of -e, -d and -i, passing an "
810061da546Spatrick                             "empty argument clears the modification.",
811*f6aab3d8Srobert                             nullptr) {
812061da546Spatrick     CommandArgumentEntry arg;
813061da546Spatrick     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
814061da546Spatrick                                       eArgTypeBreakpointIDRange);
815061da546Spatrick     // Add the entry for the first argument for this command to the object's
816061da546Spatrick     // arguments vector.
817061da546Spatrick     m_arguments.push_back(arg);
818061da546Spatrick 
819061da546Spatrick     m_options.Append(&m_bp_opts,
820061da546Spatrick                      LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3,
821061da546Spatrick                      LLDB_OPT_SET_ALL);
822061da546Spatrick     m_options.Append(&m_dummy_opts, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
823061da546Spatrick     m_options.Finalize();
824061da546Spatrick   }
825061da546Spatrick 
826061da546Spatrick   ~CommandObjectBreakpointModify() override = default;
827061da546Spatrick 
828dda28197Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)829dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
830dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
831dda28197Spatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
832dda28197Spatrick         GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
833dda28197Spatrick         request, nullptr);
834dda28197Spatrick   }
835dda28197Spatrick 
GetOptions()836061da546Spatrick   Options *GetOptions() override { return &m_options; }
837061da546Spatrick 
838061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)839061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
840061da546Spatrick     Target &target = GetSelectedOrDummyTarget(m_dummy_opts.m_use_dummy);
841061da546Spatrick 
842061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
843061da546Spatrick     target.GetBreakpointList().GetListMutex(lock);
844061da546Spatrick 
845061da546Spatrick     BreakpointIDList valid_bp_ids;
846061da546Spatrick 
847061da546Spatrick     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
848061da546Spatrick         command, &target, result, &valid_bp_ids,
849061da546Spatrick         BreakpointName::Permissions::PermissionKinds::disablePerm);
850061da546Spatrick 
851061da546Spatrick     if (result.Succeeded()) {
852061da546Spatrick       const size_t count = valid_bp_ids.GetSize();
853061da546Spatrick       for (size_t i = 0; i < count; ++i) {
854061da546Spatrick         BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
855061da546Spatrick 
856061da546Spatrick         if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
857061da546Spatrick           Breakpoint *bp =
858061da546Spatrick               target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
859061da546Spatrick           if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
860061da546Spatrick             BreakpointLocation *location =
861061da546Spatrick                 bp->FindLocationByID(cur_bp_id.GetLocationID()).get();
862061da546Spatrick             if (location)
863be691f3bSpatrick               location->GetLocationOptions().CopyOverSetOptions(
864061da546Spatrick                   m_bp_opts.GetBreakpointOptions());
865061da546Spatrick           } else {
866be691f3bSpatrick             bp->GetOptions().CopyOverSetOptions(
867061da546Spatrick                 m_bp_opts.GetBreakpointOptions());
868061da546Spatrick           }
869061da546Spatrick         }
870061da546Spatrick       }
871061da546Spatrick     }
872061da546Spatrick 
873061da546Spatrick     return result.Succeeded();
874061da546Spatrick   }
875061da546Spatrick 
876061da546Spatrick private:
877061da546Spatrick   BreakpointOptionGroup m_bp_opts;
878061da546Spatrick   BreakpointDummyOptionGroup m_dummy_opts;
879061da546Spatrick   OptionGroupOptions m_options;
880061da546Spatrick };
881061da546Spatrick 
882061da546Spatrick // CommandObjectBreakpointEnable
883061da546Spatrick #pragma mark Enable
884061da546Spatrick 
885061da546Spatrick class CommandObjectBreakpointEnable : public CommandObjectParsed {
886061da546Spatrick public:
CommandObjectBreakpointEnable(CommandInterpreter & interpreter)887061da546Spatrick   CommandObjectBreakpointEnable(CommandInterpreter &interpreter)
888061da546Spatrick       : CommandObjectParsed(interpreter, "enable",
889061da546Spatrick                             "Enable the specified disabled breakpoint(s). If "
890061da546Spatrick                             "no breakpoints are specified, enable all of them.",
891061da546Spatrick                             nullptr) {
892061da546Spatrick     CommandArgumentEntry arg;
893061da546Spatrick     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
894061da546Spatrick                                       eArgTypeBreakpointIDRange);
895061da546Spatrick     // Add the entry for the first argument for this command to the object's
896061da546Spatrick     // arguments vector.
897061da546Spatrick     m_arguments.push_back(arg);
898061da546Spatrick   }
899061da546Spatrick 
900061da546Spatrick   ~CommandObjectBreakpointEnable() override = default;
901061da546Spatrick 
902dda28197Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)903dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
904dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
905dda28197Spatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
906dda28197Spatrick         GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
907dda28197Spatrick         request, nullptr);
908dda28197Spatrick   }
909dda28197Spatrick 
910061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)911061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
912061da546Spatrick     Target &target = GetSelectedOrDummyTarget();
913061da546Spatrick 
914061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
915061da546Spatrick     target.GetBreakpointList().GetListMutex(lock);
916061da546Spatrick 
917061da546Spatrick     const BreakpointList &breakpoints = target.GetBreakpointList();
918061da546Spatrick 
919061da546Spatrick     size_t num_breakpoints = breakpoints.GetSize();
920061da546Spatrick 
921061da546Spatrick     if (num_breakpoints == 0) {
922061da546Spatrick       result.AppendError("No breakpoints exist to be enabled.");
923061da546Spatrick       return false;
924061da546Spatrick     }
925061da546Spatrick 
926061da546Spatrick     if (command.empty()) {
927061da546Spatrick       // No breakpoint selected; enable all currently set breakpoints.
928061da546Spatrick       target.EnableAllowedBreakpoints();
929061da546Spatrick       result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64
930061da546Spatrick                                      " breakpoints)\n",
931061da546Spatrick                                      (uint64_t)num_breakpoints);
932061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
933061da546Spatrick     } else {
934061da546Spatrick       // Particular breakpoint selected; enable that breakpoint.
935061da546Spatrick       BreakpointIDList valid_bp_ids;
936061da546Spatrick       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
937061da546Spatrick           command, &target, result, &valid_bp_ids,
938061da546Spatrick           BreakpointName::Permissions::PermissionKinds::disablePerm);
939061da546Spatrick 
940061da546Spatrick       if (result.Succeeded()) {
941061da546Spatrick         int enable_count = 0;
942061da546Spatrick         int loc_count = 0;
943061da546Spatrick         const size_t count = valid_bp_ids.GetSize();
944061da546Spatrick         for (size_t i = 0; i < count; ++i) {
945061da546Spatrick           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
946061da546Spatrick 
947061da546Spatrick           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
948061da546Spatrick             Breakpoint *breakpoint =
949061da546Spatrick                 target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
950061da546Spatrick             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
951061da546Spatrick               BreakpointLocation *location =
952061da546Spatrick                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
953061da546Spatrick               if (location) {
954061da546Spatrick                 location->SetEnabled(true);
955061da546Spatrick                 ++loc_count;
956061da546Spatrick               }
957061da546Spatrick             } else {
958061da546Spatrick               breakpoint->SetEnabled(true);
959061da546Spatrick               ++enable_count;
960061da546Spatrick             }
961061da546Spatrick           }
962061da546Spatrick         }
963061da546Spatrick         result.AppendMessageWithFormat("%d breakpoints enabled.\n",
964061da546Spatrick                                        enable_count + loc_count);
965061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
966061da546Spatrick       }
967061da546Spatrick     }
968061da546Spatrick 
969061da546Spatrick     return result.Succeeded();
970061da546Spatrick   }
971061da546Spatrick };
972061da546Spatrick 
973061da546Spatrick // CommandObjectBreakpointDisable
974061da546Spatrick #pragma mark Disable
975061da546Spatrick 
976061da546Spatrick class CommandObjectBreakpointDisable : public CommandObjectParsed {
977061da546Spatrick public:
CommandObjectBreakpointDisable(CommandInterpreter & interpreter)978061da546Spatrick   CommandObjectBreakpointDisable(CommandInterpreter &interpreter)
979061da546Spatrick       : CommandObjectParsed(
980061da546Spatrick             interpreter, "breakpoint disable",
981061da546Spatrick             "Disable the specified breakpoint(s) without deleting "
982061da546Spatrick             "them.  If none are specified, disable all "
983061da546Spatrick             "breakpoints.",
984061da546Spatrick             nullptr) {
985061da546Spatrick     SetHelpLong(
986061da546Spatrick         "Disable the specified breakpoint(s) without deleting them.  \
987061da546Spatrick If none are specified, disable all breakpoints."
988061da546Spatrick         R"(
989061da546Spatrick 
990061da546Spatrick )"
991061da546Spatrick         "Note: disabling a breakpoint will cause none of its locations to be hit \
992061da546Spatrick regardless of whether individual locations are enabled or disabled.  After the sequence:"
993061da546Spatrick         R"(
994061da546Spatrick 
995061da546Spatrick     (lldb) break disable 1
996061da546Spatrick     (lldb) break enable 1.1
997061da546Spatrick 
998061da546Spatrick execution will NOT stop at location 1.1.  To achieve that, type:
999061da546Spatrick 
1000061da546Spatrick     (lldb) break disable 1.*
1001061da546Spatrick     (lldb) break enable 1.1
1002061da546Spatrick 
1003061da546Spatrick )"
1004061da546Spatrick         "The first command disables all locations for breakpoint 1, \
1005061da546Spatrick the second re-enables the first location.");
1006061da546Spatrick 
1007061da546Spatrick     CommandArgumentEntry arg;
1008061da546Spatrick     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1009061da546Spatrick                                       eArgTypeBreakpointIDRange);
1010061da546Spatrick     // Add the entry for the first argument for this command to the object's
1011061da546Spatrick     // arguments vector.
1012061da546Spatrick     m_arguments.push_back(arg);
1013061da546Spatrick   }
1014061da546Spatrick 
1015061da546Spatrick   ~CommandObjectBreakpointDisable() override = default;
1016061da546Spatrick 
1017dda28197Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1018dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
1019dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
1020dda28197Spatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
1021dda28197Spatrick         GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
1022dda28197Spatrick         request, nullptr);
1023dda28197Spatrick   }
1024dda28197Spatrick 
1025061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1026061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1027061da546Spatrick     Target &target = GetSelectedOrDummyTarget();
1028061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
1029061da546Spatrick     target.GetBreakpointList().GetListMutex(lock);
1030061da546Spatrick 
1031061da546Spatrick     const BreakpointList &breakpoints = target.GetBreakpointList();
1032061da546Spatrick     size_t num_breakpoints = breakpoints.GetSize();
1033061da546Spatrick 
1034061da546Spatrick     if (num_breakpoints == 0) {
1035061da546Spatrick       result.AppendError("No breakpoints exist to be disabled.");
1036061da546Spatrick       return false;
1037061da546Spatrick     }
1038061da546Spatrick 
1039061da546Spatrick     if (command.empty()) {
1040061da546Spatrick       // No breakpoint selected; disable all currently set breakpoints.
1041061da546Spatrick       target.DisableAllowedBreakpoints();
1042061da546Spatrick       result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu64
1043061da546Spatrick                                      " breakpoints)\n",
1044061da546Spatrick                                      (uint64_t)num_breakpoints);
1045061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1046061da546Spatrick     } else {
1047061da546Spatrick       // Particular breakpoint selected; disable that breakpoint.
1048061da546Spatrick       BreakpointIDList valid_bp_ids;
1049061da546Spatrick 
1050061da546Spatrick       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1051061da546Spatrick           command, &target, result, &valid_bp_ids,
1052061da546Spatrick           BreakpointName::Permissions::PermissionKinds::disablePerm);
1053061da546Spatrick 
1054061da546Spatrick       if (result.Succeeded()) {
1055061da546Spatrick         int disable_count = 0;
1056061da546Spatrick         int loc_count = 0;
1057061da546Spatrick         const size_t count = valid_bp_ids.GetSize();
1058061da546Spatrick         for (size_t i = 0; i < count; ++i) {
1059061da546Spatrick           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1060061da546Spatrick 
1061061da546Spatrick           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1062061da546Spatrick             Breakpoint *breakpoint =
1063061da546Spatrick                 target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1064061da546Spatrick             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1065061da546Spatrick               BreakpointLocation *location =
1066061da546Spatrick                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1067061da546Spatrick               if (location) {
1068061da546Spatrick                 location->SetEnabled(false);
1069061da546Spatrick                 ++loc_count;
1070061da546Spatrick               }
1071061da546Spatrick             } else {
1072061da546Spatrick               breakpoint->SetEnabled(false);
1073061da546Spatrick               ++disable_count;
1074061da546Spatrick             }
1075061da546Spatrick           }
1076061da546Spatrick         }
1077061da546Spatrick         result.AppendMessageWithFormat("%d breakpoints disabled.\n",
1078061da546Spatrick                                        disable_count + loc_count);
1079061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1080061da546Spatrick       }
1081061da546Spatrick     }
1082061da546Spatrick 
1083061da546Spatrick     return result.Succeeded();
1084061da546Spatrick   }
1085061da546Spatrick };
1086061da546Spatrick 
1087061da546Spatrick // CommandObjectBreakpointList
1088061da546Spatrick 
1089061da546Spatrick #pragma mark List::CommandOptions
1090061da546Spatrick #define LLDB_OPTIONS_breakpoint_list
1091061da546Spatrick #include "CommandOptions.inc"
1092061da546Spatrick 
1093061da546Spatrick #pragma mark List
1094061da546Spatrick 
1095061da546Spatrick class CommandObjectBreakpointList : public CommandObjectParsed {
1096061da546Spatrick public:
CommandObjectBreakpointList(CommandInterpreter & interpreter)1097061da546Spatrick   CommandObjectBreakpointList(CommandInterpreter &interpreter)
1098061da546Spatrick       : CommandObjectParsed(
1099061da546Spatrick             interpreter, "breakpoint list",
1100061da546Spatrick             "List some or all breakpoints at configurable levels of detail.",
1101*f6aab3d8Srobert             nullptr) {
1102061da546Spatrick     CommandArgumentEntry arg;
1103061da546Spatrick     CommandArgumentData bp_id_arg;
1104061da546Spatrick 
1105061da546Spatrick     // Define the first (and only) variant of this arg.
1106061da546Spatrick     bp_id_arg.arg_type = eArgTypeBreakpointID;
1107061da546Spatrick     bp_id_arg.arg_repetition = eArgRepeatOptional;
1108061da546Spatrick 
1109061da546Spatrick     // There is only one variant this argument could be; put it into the
1110061da546Spatrick     // argument entry.
1111061da546Spatrick     arg.push_back(bp_id_arg);
1112061da546Spatrick 
1113061da546Spatrick     // Push the data for the first argument into the m_arguments vector.
1114061da546Spatrick     m_arguments.push_back(arg);
1115061da546Spatrick   }
1116061da546Spatrick 
1117061da546Spatrick   ~CommandObjectBreakpointList() override = default;
1118061da546Spatrick 
GetOptions()1119061da546Spatrick   Options *GetOptions() override { return &m_options; }
1120061da546Spatrick 
1121061da546Spatrick   class CommandOptions : public Options {
1122061da546Spatrick   public:
1123*f6aab3d8Srobert     CommandOptions() = default;
1124061da546Spatrick 
1125061da546Spatrick     ~CommandOptions() override = default;
1126061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1127061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1128061da546Spatrick                           ExecutionContext *execution_context) override {
1129061da546Spatrick       Status error;
1130061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
1131061da546Spatrick 
1132061da546Spatrick       switch (short_option) {
1133061da546Spatrick       case 'b':
1134061da546Spatrick         m_level = lldb::eDescriptionLevelBrief;
1135061da546Spatrick         break;
1136061da546Spatrick       case 'D':
1137061da546Spatrick         m_use_dummy = true;
1138061da546Spatrick         break;
1139061da546Spatrick       case 'f':
1140061da546Spatrick         m_level = lldb::eDescriptionLevelFull;
1141061da546Spatrick         break;
1142061da546Spatrick       case 'v':
1143061da546Spatrick         m_level = lldb::eDescriptionLevelVerbose;
1144061da546Spatrick         break;
1145061da546Spatrick       case 'i':
1146061da546Spatrick         m_internal = true;
1147061da546Spatrick         break;
1148061da546Spatrick       default:
1149061da546Spatrick         llvm_unreachable("Unimplemented option");
1150061da546Spatrick       }
1151061da546Spatrick 
1152061da546Spatrick       return error;
1153061da546Spatrick     }
1154061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)1155061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
1156061da546Spatrick       m_level = lldb::eDescriptionLevelFull;
1157061da546Spatrick       m_internal = false;
1158061da546Spatrick       m_use_dummy = false;
1159061da546Spatrick     }
1160061da546Spatrick 
GetDefinitions()1161061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1162*f6aab3d8Srobert       return llvm::ArrayRef(g_breakpoint_list_options);
1163061da546Spatrick     }
1164061da546Spatrick 
1165061da546Spatrick     // Instance variables to hold the values for command options.
1166061da546Spatrick 
1167be691f3bSpatrick     lldb::DescriptionLevel m_level = lldb::eDescriptionLevelBrief;
1168061da546Spatrick 
1169061da546Spatrick     bool m_internal;
1170be691f3bSpatrick     bool m_use_dummy = false;
1171061da546Spatrick   };
1172061da546Spatrick 
1173061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1174061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1175061da546Spatrick     Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
1176061da546Spatrick 
1177061da546Spatrick     const BreakpointList &breakpoints =
1178061da546Spatrick         target.GetBreakpointList(m_options.m_internal);
1179061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
1180061da546Spatrick     target.GetBreakpointList(m_options.m_internal).GetListMutex(lock);
1181061da546Spatrick 
1182061da546Spatrick     size_t num_breakpoints = breakpoints.GetSize();
1183061da546Spatrick 
1184061da546Spatrick     if (num_breakpoints == 0) {
1185061da546Spatrick       result.AppendMessage("No breakpoints currently set.");
1186061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1187061da546Spatrick       return true;
1188061da546Spatrick     }
1189061da546Spatrick 
1190061da546Spatrick     Stream &output_stream = result.GetOutputStream();
1191061da546Spatrick 
1192061da546Spatrick     if (command.empty()) {
1193061da546Spatrick       // No breakpoint selected; show info about all currently set breakpoints.
1194061da546Spatrick       result.AppendMessage("Current breakpoints:");
1195061da546Spatrick       for (size_t i = 0; i < num_breakpoints; ++i) {
1196061da546Spatrick         Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get();
1197061da546Spatrick         if (breakpoint->AllowList())
1198061da546Spatrick           AddBreakpointDescription(&output_stream, breakpoint,
1199061da546Spatrick                                    m_options.m_level);
1200061da546Spatrick       }
1201061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1202061da546Spatrick     } else {
1203061da546Spatrick       // Particular breakpoints selected; show info about that breakpoint.
1204061da546Spatrick       BreakpointIDList valid_bp_ids;
1205061da546Spatrick       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1206061da546Spatrick           command, &target, result, &valid_bp_ids,
1207061da546Spatrick           BreakpointName::Permissions::PermissionKinds::listPerm);
1208061da546Spatrick 
1209061da546Spatrick       if (result.Succeeded()) {
1210061da546Spatrick         for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) {
1211061da546Spatrick           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1212061da546Spatrick           Breakpoint *breakpoint =
1213061da546Spatrick               target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1214061da546Spatrick           AddBreakpointDescription(&output_stream, breakpoint,
1215061da546Spatrick                                    m_options.m_level);
1216061da546Spatrick         }
1217061da546Spatrick         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1218061da546Spatrick       } else {
1219061da546Spatrick         result.AppendError("Invalid breakpoint ID.");
1220061da546Spatrick       }
1221061da546Spatrick     }
1222061da546Spatrick 
1223061da546Spatrick     return result.Succeeded();
1224061da546Spatrick   }
1225061da546Spatrick 
1226061da546Spatrick private:
1227061da546Spatrick   CommandOptions m_options;
1228061da546Spatrick };
1229061da546Spatrick 
1230061da546Spatrick // CommandObjectBreakpointClear
1231061da546Spatrick #pragma mark Clear::CommandOptions
1232061da546Spatrick 
1233061da546Spatrick #define LLDB_OPTIONS_breakpoint_clear
1234061da546Spatrick #include "CommandOptions.inc"
1235061da546Spatrick 
1236061da546Spatrick #pragma mark Clear
1237061da546Spatrick 
1238061da546Spatrick class CommandObjectBreakpointClear : public CommandObjectParsed {
1239061da546Spatrick public:
1240061da546Spatrick   enum BreakpointClearType { eClearTypeInvalid, eClearTypeFileAndLine };
1241061da546Spatrick 
CommandObjectBreakpointClear(CommandInterpreter & interpreter)1242061da546Spatrick   CommandObjectBreakpointClear(CommandInterpreter &interpreter)
1243061da546Spatrick       : CommandObjectParsed(interpreter, "breakpoint clear",
1244061da546Spatrick                             "Delete or disable breakpoints matching the "
1245061da546Spatrick                             "specified source file and line.",
1246*f6aab3d8Srobert                             "breakpoint clear <cmd-options>") {}
1247061da546Spatrick 
1248061da546Spatrick   ~CommandObjectBreakpointClear() override = default;
1249061da546Spatrick 
GetOptions()1250061da546Spatrick   Options *GetOptions() override { return &m_options; }
1251061da546Spatrick 
1252061da546Spatrick   class CommandOptions : public Options {
1253061da546Spatrick   public:
1254*f6aab3d8Srobert     CommandOptions() = default;
1255061da546Spatrick 
1256061da546Spatrick     ~CommandOptions() override = default;
1257061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1258061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1259061da546Spatrick                           ExecutionContext *execution_context) override {
1260061da546Spatrick       Status error;
1261061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
1262061da546Spatrick 
1263061da546Spatrick       switch (short_option) {
1264061da546Spatrick       case 'f':
1265dda28197Spatrick         m_filename.assign(std::string(option_arg));
1266061da546Spatrick         break;
1267061da546Spatrick 
1268061da546Spatrick       case 'l':
1269061da546Spatrick         option_arg.getAsInteger(0, m_line_num);
1270061da546Spatrick         break;
1271061da546Spatrick 
1272061da546Spatrick       default:
1273061da546Spatrick         llvm_unreachable("Unimplemented option");
1274061da546Spatrick       }
1275061da546Spatrick 
1276061da546Spatrick       return error;
1277061da546Spatrick     }
1278061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)1279061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
1280061da546Spatrick       m_filename.clear();
1281061da546Spatrick       m_line_num = 0;
1282061da546Spatrick     }
1283061da546Spatrick 
GetDefinitions()1284061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1285*f6aab3d8Srobert       return llvm::ArrayRef(g_breakpoint_clear_options);
1286061da546Spatrick     }
1287061da546Spatrick 
1288061da546Spatrick     // Instance variables to hold the values for command options.
1289061da546Spatrick 
1290061da546Spatrick     std::string m_filename;
1291be691f3bSpatrick     uint32_t m_line_num = 0;
1292061da546Spatrick   };
1293061da546Spatrick 
1294061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1295061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1296061da546Spatrick     Target &target = GetSelectedOrDummyTarget();
1297061da546Spatrick 
1298061da546Spatrick     // The following are the various types of breakpoints that could be
1299061da546Spatrick     // cleared:
1300061da546Spatrick     //   1). -f -l (clearing breakpoint by source location)
1301061da546Spatrick 
1302061da546Spatrick     BreakpointClearType break_type = eClearTypeInvalid;
1303061da546Spatrick 
1304061da546Spatrick     if (m_options.m_line_num != 0)
1305061da546Spatrick       break_type = eClearTypeFileAndLine;
1306061da546Spatrick 
1307061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
1308061da546Spatrick     target.GetBreakpointList().GetListMutex(lock);
1309061da546Spatrick 
1310061da546Spatrick     BreakpointList &breakpoints = target.GetBreakpointList();
1311061da546Spatrick     size_t num_breakpoints = breakpoints.GetSize();
1312061da546Spatrick 
1313061da546Spatrick     // Early return if there's no breakpoint at all.
1314061da546Spatrick     if (num_breakpoints == 0) {
1315061da546Spatrick       result.AppendError("Breakpoint clear: No breakpoint cleared.");
1316061da546Spatrick       return result.Succeeded();
1317061da546Spatrick     }
1318061da546Spatrick 
1319061da546Spatrick     // Find matching breakpoints and delete them.
1320061da546Spatrick 
1321061da546Spatrick     // First create a copy of all the IDs.
1322061da546Spatrick     std::vector<break_id_t> BreakIDs;
1323061da546Spatrick     for (size_t i = 0; i < num_breakpoints; ++i)
1324061da546Spatrick       BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID());
1325061da546Spatrick 
1326061da546Spatrick     int num_cleared = 0;
1327061da546Spatrick     StreamString ss;
1328061da546Spatrick     switch (break_type) {
1329061da546Spatrick     case eClearTypeFileAndLine: // Breakpoint by source position
1330061da546Spatrick     {
1331061da546Spatrick       const ConstString filename(m_options.m_filename.c_str());
1332061da546Spatrick       BreakpointLocationCollection loc_coll;
1333061da546Spatrick 
1334061da546Spatrick       for (size_t i = 0; i < num_breakpoints; ++i) {
1335061da546Spatrick         Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get();
1336061da546Spatrick 
1337061da546Spatrick         if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) {
1338061da546Spatrick           // If the collection size is 0, it's a full match and we can just
1339061da546Spatrick           // remove the breakpoint.
1340061da546Spatrick           if (loc_coll.GetSize() == 0) {
1341061da546Spatrick             bp->GetDescription(&ss, lldb::eDescriptionLevelBrief);
1342061da546Spatrick             ss.EOL();
1343061da546Spatrick             target.RemoveBreakpointByID(bp->GetID());
1344061da546Spatrick             ++num_cleared;
1345061da546Spatrick           }
1346061da546Spatrick         }
1347061da546Spatrick       }
1348061da546Spatrick     } break;
1349061da546Spatrick 
1350061da546Spatrick     default:
1351061da546Spatrick       break;
1352061da546Spatrick     }
1353061da546Spatrick 
1354061da546Spatrick     if (num_cleared > 0) {
1355061da546Spatrick       Stream &output_stream = result.GetOutputStream();
1356061da546Spatrick       output_stream.Printf("%d breakpoints cleared:\n", num_cleared);
1357061da546Spatrick       output_stream << ss.GetString();
1358061da546Spatrick       output_stream.EOL();
1359061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1360061da546Spatrick     } else {
1361061da546Spatrick       result.AppendError("Breakpoint clear: No breakpoint cleared.");
1362061da546Spatrick     }
1363061da546Spatrick 
1364061da546Spatrick     return result.Succeeded();
1365061da546Spatrick   }
1366061da546Spatrick 
1367061da546Spatrick private:
1368061da546Spatrick   CommandOptions m_options;
1369061da546Spatrick };
1370061da546Spatrick 
1371061da546Spatrick // CommandObjectBreakpointDelete
1372061da546Spatrick #define LLDB_OPTIONS_breakpoint_delete
1373061da546Spatrick #include "CommandOptions.inc"
1374061da546Spatrick 
1375061da546Spatrick #pragma mark Delete
1376061da546Spatrick 
1377061da546Spatrick class CommandObjectBreakpointDelete : public CommandObjectParsed {
1378061da546Spatrick public:
CommandObjectBreakpointDelete(CommandInterpreter & interpreter)1379061da546Spatrick   CommandObjectBreakpointDelete(CommandInterpreter &interpreter)
1380061da546Spatrick       : CommandObjectParsed(interpreter, "breakpoint delete",
1381061da546Spatrick                             "Delete the specified breakpoint(s).  If no "
1382061da546Spatrick                             "breakpoints are specified, delete them all.",
1383*f6aab3d8Srobert                             nullptr) {
1384061da546Spatrick     CommandArgumentEntry arg;
1385061da546Spatrick     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1386061da546Spatrick                                       eArgTypeBreakpointIDRange);
1387061da546Spatrick     // Add the entry for the first argument for this command to the object's
1388061da546Spatrick     // arguments vector.
1389061da546Spatrick     m_arguments.push_back(arg);
1390061da546Spatrick   }
1391061da546Spatrick 
1392061da546Spatrick   ~CommandObjectBreakpointDelete() override = default;
1393061da546Spatrick 
1394dda28197Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1395dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
1396dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
1397dda28197Spatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
1398dda28197Spatrick         GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
1399dda28197Spatrick         request, nullptr);
1400dda28197Spatrick   }
1401dda28197Spatrick 
GetOptions()1402061da546Spatrick   Options *GetOptions() override { return &m_options; }
1403061da546Spatrick 
1404061da546Spatrick   class CommandOptions : public Options {
1405061da546Spatrick   public:
1406*f6aab3d8Srobert     CommandOptions() = default;
1407061da546Spatrick 
1408061da546Spatrick     ~CommandOptions() override = default;
1409061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1410061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1411061da546Spatrick                           ExecutionContext *execution_context) override {
1412061da546Spatrick       Status error;
1413061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
1414061da546Spatrick 
1415061da546Spatrick       switch (short_option) {
1416061da546Spatrick       case 'f':
1417061da546Spatrick         m_force = true;
1418061da546Spatrick         break;
1419061da546Spatrick 
1420061da546Spatrick       case 'D':
1421061da546Spatrick         m_use_dummy = true;
1422061da546Spatrick         break;
1423061da546Spatrick 
1424be691f3bSpatrick       case 'd':
1425be691f3bSpatrick         m_delete_disabled = true;
1426be691f3bSpatrick         break;
1427be691f3bSpatrick 
1428061da546Spatrick       default:
1429061da546Spatrick         llvm_unreachable("Unimplemented option");
1430061da546Spatrick       }
1431061da546Spatrick 
1432061da546Spatrick       return error;
1433061da546Spatrick     }
1434061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)1435061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
1436061da546Spatrick       m_use_dummy = false;
1437061da546Spatrick       m_force = false;
1438be691f3bSpatrick       m_delete_disabled = false;
1439061da546Spatrick     }
1440061da546Spatrick 
GetDefinitions()1441061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1442*f6aab3d8Srobert       return llvm::ArrayRef(g_breakpoint_delete_options);
1443061da546Spatrick     }
1444061da546Spatrick 
1445061da546Spatrick     // Instance variables to hold the values for command options.
1446be691f3bSpatrick     bool m_use_dummy = false;
1447be691f3bSpatrick     bool m_force = false;
1448be691f3bSpatrick     bool m_delete_disabled = false;
1449061da546Spatrick   };
1450061da546Spatrick 
1451061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1452061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1453061da546Spatrick     Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
1454be691f3bSpatrick     result.Clear();
1455061da546Spatrick 
1456061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
1457061da546Spatrick     target.GetBreakpointList().GetListMutex(lock);
1458061da546Spatrick 
1459be691f3bSpatrick     BreakpointList &breakpoints = target.GetBreakpointList();
1460061da546Spatrick 
1461061da546Spatrick     size_t num_breakpoints = breakpoints.GetSize();
1462061da546Spatrick 
1463061da546Spatrick     if (num_breakpoints == 0) {
1464061da546Spatrick       result.AppendError("No breakpoints exist to be deleted.");
1465061da546Spatrick       return false;
1466061da546Spatrick     }
1467061da546Spatrick 
1468be691f3bSpatrick     // Handle the delete all breakpoints case:
1469be691f3bSpatrick     if (command.empty() && !m_options.m_delete_disabled) {
1470061da546Spatrick       if (!m_options.m_force &&
1471061da546Spatrick           !m_interpreter.Confirm(
1472061da546Spatrick               "About to delete all breakpoints, do you want to do that?",
1473061da546Spatrick               true)) {
1474061da546Spatrick         result.AppendMessage("Operation cancelled...");
1475061da546Spatrick       } else {
1476061da546Spatrick         target.RemoveAllowedBreakpoints();
1477061da546Spatrick         result.AppendMessageWithFormat(
1478061da546Spatrick             "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n",
1479061da546Spatrick             (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : "");
1480061da546Spatrick       }
1481061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1482be691f3bSpatrick       return result.Succeeded();
1483be691f3bSpatrick     }
1484be691f3bSpatrick 
1485be691f3bSpatrick     // Either we have some kind of breakpoint specification(s),
1486be691f3bSpatrick     // or we are handling "break disable --deleted".  Gather the list
1487be691f3bSpatrick     // of breakpoints to delete here, the we'll delete them below.
1488061da546Spatrick     BreakpointIDList valid_bp_ids;
1489be691f3bSpatrick 
1490be691f3bSpatrick     if (m_options.m_delete_disabled) {
1491be691f3bSpatrick       BreakpointIDList excluded_bp_ids;
1492be691f3bSpatrick 
1493be691f3bSpatrick       if (!command.empty()) {
1494be691f3bSpatrick         CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1495be691f3bSpatrick             command, &target, result, &excluded_bp_ids,
1496be691f3bSpatrick             BreakpointName::Permissions::PermissionKinds::deletePerm);
1497be691f3bSpatrick         if (!result.Succeeded())
1498be691f3bSpatrick           return false;
1499be691f3bSpatrick       }
1500be691f3bSpatrick 
1501be691f3bSpatrick       for (auto breakpoint_sp : breakpoints.Breakpoints()) {
1502be691f3bSpatrick         if (!breakpoint_sp->IsEnabled() && breakpoint_sp->AllowDelete()) {
1503be691f3bSpatrick           BreakpointID bp_id(breakpoint_sp->GetID());
1504be691f3bSpatrick           size_t pos = 0;
1505be691f3bSpatrick           if (!excluded_bp_ids.FindBreakpointID(bp_id, &pos))
1506be691f3bSpatrick             valid_bp_ids.AddBreakpointID(breakpoint_sp->GetID());
1507be691f3bSpatrick         }
1508be691f3bSpatrick       }
1509be691f3bSpatrick       if (valid_bp_ids.GetSize() == 0) {
1510be691f3bSpatrick         result.AppendError("No disabled breakpoints.");
1511be691f3bSpatrick         return false;
1512be691f3bSpatrick       }
1513be691f3bSpatrick     } else {
1514061da546Spatrick       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1515061da546Spatrick           command, &target, result, &valid_bp_ids,
1516061da546Spatrick           BreakpointName::Permissions::PermissionKinds::deletePerm);
1517be691f3bSpatrick       if (!result.Succeeded())
1518be691f3bSpatrick         return false;
1519be691f3bSpatrick     }
1520061da546Spatrick 
1521061da546Spatrick     int delete_count = 0;
1522061da546Spatrick     int disable_count = 0;
1523061da546Spatrick     const size_t count = valid_bp_ids.GetSize();
1524061da546Spatrick     for (size_t i = 0; i < count; ++i) {
1525061da546Spatrick       BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1526061da546Spatrick 
1527061da546Spatrick       if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1528061da546Spatrick         if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1529061da546Spatrick           Breakpoint *breakpoint =
1530061da546Spatrick               target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1531061da546Spatrick           BreakpointLocation *location =
1532061da546Spatrick               breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1533061da546Spatrick           // It makes no sense to try to delete individual locations, so we
1534061da546Spatrick           // disable them instead.
1535061da546Spatrick           if (location) {
1536061da546Spatrick             location->SetEnabled(false);
1537061da546Spatrick             ++disable_count;
1538061da546Spatrick           }
1539061da546Spatrick         } else {
1540061da546Spatrick           target.RemoveBreakpointByID(cur_bp_id.GetBreakpointID());
1541061da546Spatrick           ++delete_count;
1542061da546Spatrick         }
1543061da546Spatrick       }
1544061da546Spatrick     }
1545061da546Spatrick     result.AppendMessageWithFormat(
1546061da546Spatrick         "%d breakpoints deleted; %d breakpoint locations disabled.\n",
1547061da546Spatrick         delete_count, disable_count);
1548061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1549061da546Spatrick     return result.Succeeded();
1550061da546Spatrick   }
1551061da546Spatrick 
1552061da546Spatrick private:
1553061da546Spatrick   CommandOptions m_options;
1554061da546Spatrick };
1555061da546Spatrick 
1556061da546Spatrick // CommandObjectBreakpointName
1557061da546Spatrick #define LLDB_OPTIONS_breakpoint_name
1558061da546Spatrick #include "CommandOptions.inc"
1559061da546Spatrick 
1560061da546Spatrick class BreakpointNameOptionGroup : public OptionGroup {
1561061da546Spatrick public:
BreakpointNameOptionGroup()1562061da546Spatrick   BreakpointNameOptionGroup()
1563*f6aab3d8Srobert       : m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) {}
1564061da546Spatrick 
1565061da546Spatrick   ~BreakpointNameOptionGroup() override = default;
1566061da546Spatrick 
GetDefinitions()1567061da546Spatrick   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1568*f6aab3d8Srobert     return llvm::ArrayRef(g_breakpoint_name_options);
1569061da546Spatrick   }
1570061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1571061da546Spatrick   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1572061da546Spatrick                         ExecutionContext *execution_context) override {
1573061da546Spatrick     Status error;
1574061da546Spatrick     const int short_option = g_breakpoint_name_options[option_idx].short_option;
1575061da546Spatrick 
1576061da546Spatrick     switch (short_option) {
1577061da546Spatrick     case 'N':
1578061da546Spatrick       if (BreakpointID::StringIsBreakpointName(option_arg, error) &&
1579061da546Spatrick           error.Success())
1580061da546Spatrick         m_name.SetValueFromString(option_arg);
1581061da546Spatrick       break;
1582061da546Spatrick     case 'B':
1583061da546Spatrick       if (m_breakpoint.SetValueFromString(option_arg).Fail())
1584061da546Spatrick         error.SetErrorStringWithFormat(
1585061da546Spatrick             "unrecognized value \"%s\" for breakpoint",
1586061da546Spatrick             option_arg.str().c_str());
1587061da546Spatrick       break;
1588061da546Spatrick     case 'D':
1589061da546Spatrick       if (m_use_dummy.SetValueFromString(option_arg).Fail())
1590061da546Spatrick         error.SetErrorStringWithFormat(
1591061da546Spatrick             "unrecognized value \"%s\" for use-dummy",
1592061da546Spatrick             option_arg.str().c_str());
1593061da546Spatrick       break;
1594061da546Spatrick     case 'H':
1595061da546Spatrick       m_help_string.SetValueFromString(option_arg);
1596061da546Spatrick       break;
1597061da546Spatrick 
1598061da546Spatrick     default:
1599061da546Spatrick       llvm_unreachable("Unimplemented option");
1600061da546Spatrick     }
1601061da546Spatrick     return error;
1602061da546Spatrick   }
1603061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)1604061da546Spatrick   void OptionParsingStarting(ExecutionContext *execution_context) override {
1605061da546Spatrick     m_name.Clear();
1606061da546Spatrick     m_breakpoint.Clear();
1607061da546Spatrick     m_use_dummy.Clear();
1608061da546Spatrick     m_use_dummy.SetDefaultValue(false);
1609061da546Spatrick     m_help_string.Clear();
1610061da546Spatrick   }
1611061da546Spatrick 
1612061da546Spatrick   OptionValueString m_name;
1613061da546Spatrick   OptionValueUInt64 m_breakpoint;
1614061da546Spatrick   OptionValueBoolean m_use_dummy;
1615061da546Spatrick   OptionValueString m_help_string;
1616061da546Spatrick };
1617061da546Spatrick 
1618061da546Spatrick #define LLDB_OPTIONS_breakpoint_access
1619061da546Spatrick #include "CommandOptions.inc"
1620061da546Spatrick 
1621061da546Spatrick class BreakpointAccessOptionGroup : public OptionGroup {
1622061da546Spatrick public:
1623*f6aab3d8Srobert   BreakpointAccessOptionGroup() = default;
1624061da546Spatrick 
1625061da546Spatrick   ~BreakpointAccessOptionGroup() override = default;
1626061da546Spatrick 
GetDefinitions()1627061da546Spatrick   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1628*f6aab3d8Srobert     return llvm::ArrayRef(g_breakpoint_access_options);
1629061da546Spatrick   }
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1630061da546Spatrick   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1631061da546Spatrick                         ExecutionContext *execution_context) override {
1632061da546Spatrick     Status error;
1633061da546Spatrick     const int short_option =
1634061da546Spatrick         g_breakpoint_access_options[option_idx].short_option;
1635061da546Spatrick 
1636061da546Spatrick     switch (short_option) {
1637061da546Spatrick     case 'L': {
1638061da546Spatrick       bool value, success;
1639061da546Spatrick       value = OptionArgParser::ToBoolean(option_arg, false, &success);
1640061da546Spatrick       if (success) {
1641061da546Spatrick         m_permissions.SetAllowList(value);
1642061da546Spatrick       } else
1643061da546Spatrick         error.SetErrorStringWithFormat(
1644061da546Spatrick             "invalid boolean value '%s' passed for -L option",
1645061da546Spatrick             option_arg.str().c_str());
1646061da546Spatrick     } break;
1647061da546Spatrick     case 'A': {
1648061da546Spatrick       bool value, success;
1649061da546Spatrick       value = OptionArgParser::ToBoolean(option_arg, false, &success);
1650061da546Spatrick       if (success) {
1651061da546Spatrick         m_permissions.SetAllowDisable(value);
1652061da546Spatrick       } else
1653061da546Spatrick         error.SetErrorStringWithFormat(
1654061da546Spatrick             "invalid boolean value '%s' passed for -L option",
1655061da546Spatrick             option_arg.str().c_str());
1656061da546Spatrick     } break;
1657061da546Spatrick     case 'D': {
1658061da546Spatrick       bool value, success;
1659061da546Spatrick       value = OptionArgParser::ToBoolean(option_arg, false, &success);
1660061da546Spatrick       if (success) {
1661061da546Spatrick         m_permissions.SetAllowDelete(value);
1662061da546Spatrick       } else
1663061da546Spatrick         error.SetErrorStringWithFormat(
1664061da546Spatrick             "invalid boolean value '%s' passed for -L option",
1665061da546Spatrick             option_arg.str().c_str());
1666061da546Spatrick     } break;
1667061da546Spatrick     default:
1668061da546Spatrick       llvm_unreachable("Unimplemented option");
1669061da546Spatrick     }
1670061da546Spatrick 
1671061da546Spatrick     return error;
1672061da546Spatrick   }
1673061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)1674061da546Spatrick   void OptionParsingStarting(ExecutionContext *execution_context) override {}
1675061da546Spatrick 
GetPermissions() const1676061da546Spatrick   const BreakpointName::Permissions &GetPermissions() const {
1677061da546Spatrick     return m_permissions;
1678061da546Spatrick   }
1679061da546Spatrick   BreakpointName::Permissions m_permissions;
1680061da546Spatrick };
1681061da546Spatrick 
1682061da546Spatrick class CommandObjectBreakpointNameConfigure : public CommandObjectParsed {
1683061da546Spatrick public:
CommandObjectBreakpointNameConfigure(CommandInterpreter & interpreter)1684061da546Spatrick   CommandObjectBreakpointNameConfigure(CommandInterpreter &interpreter)
1685061da546Spatrick       : CommandObjectParsed(
1686061da546Spatrick             interpreter, "configure",
1687061da546Spatrick             "Configure the options for the breakpoint"
1688061da546Spatrick             " name provided.  "
1689061da546Spatrick             "If you provide a breakpoint id, the options will be copied from "
1690061da546Spatrick             "the breakpoint, otherwise only the options specified will be set "
1691061da546Spatrick             "on the name.",
1692061da546Spatrick             "breakpoint name configure <command-options> "
1693*f6aab3d8Srobert             "<breakpoint-name-list>") {
1694061da546Spatrick     // Create the first variant for the first (and only) argument for this
1695061da546Spatrick     // command.
1696061da546Spatrick     CommandArgumentEntry arg1;
1697061da546Spatrick     CommandArgumentData id_arg;
1698061da546Spatrick     id_arg.arg_type = eArgTypeBreakpointName;
1699061da546Spatrick     id_arg.arg_repetition = eArgRepeatOptional;
1700061da546Spatrick     arg1.push_back(id_arg);
1701061da546Spatrick     m_arguments.push_back(arg1);
1702061da546Spatrick 
1703061da546Spatrick     m_option_group.Append(&m_bp_opts, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
1704061da546Spatrick     m_option_group.Append(&m_access_options, LLDB_OPT_SET_ALL,
1705061da546Spatrick                           LLDB_OPT_SET_ALL);
1706061da546Spatrick     m_option_group.Append(&m_bp_id, LLDB_OPT_SET_2 | LLDB_OPT_SET_4,
1707061da546Spatrick                           LLDB_OPT_SET_ALL);
1708061da546Spatrick     m_option_group.Finalize();
1709061da546Spatrick   }
1710061da546Spatrick 
1711061da546Spatrick   ~CommandObjectBreakpointNameConfigure() override = default;
1712061da546Spatrick 
GetOptions()1713061da546Spatrick   Options *GetOptions() override { return &m_option_group; }
1714061da546Spatrick 
1715061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1716061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1717061da546Spatrick 
1718061da546Spatrick     const size_t argc = command.GetArgumentCount();
1719061da546Spatrick     if (argc == 0) {
1720061da546Spatrick       result.AppendError("No names provided.");
1721061da546Spatrick       return false;
1722061da546Spatrick     }
1723061da546Spatrick 
1724061da546Spatrick     Target &target = GetSelectedOrDummyTarget(false);
1725061da546Spatrick 
1726061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
1727061da546Spatrick     target.GetBreakpointList().GetListMutex(lock);
1728061da546Spatrick 
1729061da546Spatrick     // Make a pass through first to see that all the names are legal.
1730061da546Spatrick     for (auto &entry : command.entries()) {
1731061da546Spatrick       Status error;
1732061da546Spatrick       if (!BreakpointID::StringIsBreakpointName(entry.ref(), error)) {
1733061da546Spatrick         result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s",
1734061da546Spatrick                                      entry.c_str(), error.AsCString());
1735061da546Spatrick         return false;
1736061da546Spatrick       }
1737061da546Spatrick     }
1738061da546Spatrick     // Now configure them, we already pre-checked the names so we don't need to
1739061da546Spatrick     // check the error:
1740061da546Spatrick     BreakpointSP bp_sp;
1741061da546Spatrick     if (m_bp_id.m_breakpoint.OptionWasSet()) {
1742061da546Spatrick       lldb::break_id_t bp_id = m_bp_id.m_breakpoint.GetUInt64Value();
1743061da546Spatrick       bp_sp = target.GetBreakpointByID(bp_id);
1744061da546Spatrick       if (!bp_sp) {
1745061da546Spatrick         result.AppendErrorWithFormatv("Could not find specified breakpoint {0}",
1746061da546Spatrick                                       bp_id);
1747061da546Spatrick         return false;
1748061da546Spatrick       }
1749061da546Spatrick     }
1750061da546Spatrick 
1751061da546Spatrick     Status error;
1752061da546Spatrick     for (auto &entry : command.entries()) {
1753061da546Spatrick       ConstString name(entry.c_str());
1754061da546Spatrick       BreakpointName *bp_name = target.FindBreakpointName(name, true, error);
1755061da546Spatrick       if (!bp_name)
1756061da546Spatrick         continue;
1757061da546Spatrick       if (m_bp_id.m_help_string.OptionWasSet())
1758061da546Spatrick         bp_name->SetHelp(m_bp_id.m_help_string.GetStringValue().str().c_str());
1759061da546Spatrick 
1760061da546Spatrick       if (bp_sp)
1761be691f3bSpatrick         target.ConfigureBreakpointName(*bp_name, bp_sp->GetOptions(),
1762061da546Spatrick                                        m_access_options.GetPermissions());
1763061da546Spatrick       else
1764061da546Spatrick         target.ConfigureBreakpointName(*bp_name,
1765061da546Spatrick                                        m_bp_opts.GetBreakpointOptions(),
1766061da546Spatrick                                        m_access_options.GetPermissions());
1767061da546Spatrick     }
1768061da546Spatrick     return true;
1769061da546Spatrick   }
1770061da546Spatrick 
1771061da546Spatrick private:
1772061da546Spatrick   BreakpointNameOptionGroup m_bp_id; // Only using the id part of this.
1773061da546Spatrick   BreakpointOptionGroup m_bp_opts;
1774061da546Spatrick   BreakpointAccessOptionGroup m_access_options;
1775061da546Spatrick   OptionGroupOptions m_option_group;
1776061da546Spatrick };
1777061da546Spatrick 
1778061da546Spatrick class CommandObjectBreakpointNameAdd : public CommandObjectParsed {
1779061da546Spatrick public:
CommandObjectBreakpointNameAdd(CommandInterpreter & interpreter)1780061da546Spatrick   CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter)
1781061da546Spatrick       : CommandObjectParsed(
1782061da546Spatrick             interpreter, "add", "Add a name to the breakpoints provided.",
1783*f6aab3d8Srobert             "breakpoint name add <command-options> <breakpoint-id-list>") {
1784061da546Spatrick     // Create the first variant for the first (and only) argument for this
1785061da546Spatrick     // command.
1786061da546Spatrick     CommandArgumentEntry arg1;
1787061da546Spatrick     CommandArgumentData id_arg;
1788061da546Spatrick     id_arg.arg_type = eArgTypeBreakpointID;
1789061da546Spatrick     id_arg.arg_repetition = eArgRepeatOptional;
1790061da546Spatrick     arg1.push_back(id_arg);
1791061da546Spatrick     m_arguments.push_back(arg1);
1792061da546Spatrick 
1793061da546Spatrick     m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
1794061da546Spatrick     m_option_group.Finalize();
1795061da546Spatrick   }
1796061da546Spatrick 
1797061da546Spatrick   ~CommandObjectBreakpointNameAdd() override = default;
1798061da546Spatrick 
1799dda28197Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1800dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
1801dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
1802dda28197Spatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
1803dda28197Spatrick         GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
1804dda28197Spatrick         request, nullptr);
1805dda28197Spatrick   }
1806dda28197Spatrick 
GetOptions()1807061da546Spatrick   Options *GetOptions() override { return &m_option_group; }
1808061da546Spatrick 
1809061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1810061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1811061da546Spatrick     if (!m_name_options.m_name.OptionWasSet()) {
1812be691f3bSpatrick       result.AppendError("No name option provided.");
1813061da546Spatrick       return false;
1814061da546Spatrick     }
1815061da546Spatrick 
1816061da546Spatrick     Target &target =
1817061da546Spatrick         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1818061da546Spatrick 
1819061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
1820061da546Spatrick     target.GetBreakpointList().GetListMutex(lock);
1821061da546Spatrick 
1822061da546Spatrick     const BreakpointList &breakpoints = target.GetBreakpointList();
1823061da546Spatrick 
1824061da546Spatrick     size_t num_breakpoints = breakpoints.GetSize();
1825061da546Spatrick     if (num_breakpoints == 0) {
1826be691f3bSpatrick       result.AppendError("No breakpoints, cannot add names.");
1827061da546Spatrick       return false;
1828061da546Spatrick     }
1829061da546Spatrick 
1830061da546Spatrick     // Particular breakpoint selected; disable that breakpoint.
1831061da546Spatrick     BreakpointIDList valid_bp_ids;
1832061da546Spatrick     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
1833061da546Spatrick         command, &target, result, &valid_bp_ids,
1834061da546Spatrick         BreakpointName::Permissions::PermissionKinds::listPerm);
1835061da546Spatrick 
1836061da546Spatrick     if (result.Succeeded()) {
1837061da546Spatrick       if (valid_bp_ids.GetSize() == 0) {
1838be691f3bSpatrick         result.AppendError("No breakpoints specified, cannot add names.");
1839061da546Spatrick         return false;
1840061da546Spatrick       }
1841061da546Spatrick       size_t num_valid_ids = valid_bp_ids.GetSize();
1842061da546Spatrick       const char *bp_name = m_name_options.m_name.GetCurrentValue();
1843061da546Spatrick       Status error; // This error reports illegal names, but we've already
1844061da546Spatrick                     // checked that, so we don't need to check it again here.
1845061da546Spatrick       for (size_t index = 0; index < num_valid_ids; index++) {
1846061da546Spatrick         lldb::break_id_t bp_id =
1847061da546Spatrick             valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
1848061da546Spatrick         BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
1849061da546Spatrick         target.AddNameToBreakpoint(bp_sp, bp_name, error);
1850061da546Spatrick       }
1851061da546Spatrick     }
1852061da546Spatrick 
1853061da546Spatrick     return true;
1854061da546Spatrick   }
1855061da546Spatrick 
1856061da546Spatrick private:
1857061da546Spatrick   BreakpointNameOptionGroup m_name_options;
1858061da546Spatrick   OptionGroupOptions m_option_group;
1859061da546Spatrick };
1860061da546Spatrick 
1861061da546Spatrick class CommandObjectBreakpointNameDelete : public CommandObjectParsed {
1862061da546Spatrick public:
CommandObjectBreakpointNameDelete(CommandInterpreter & interpreter)1863061da546Spatrick   CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter)
1864061da546Spatrick       : CommandObjectParsed(
1865061da546Spatrick             interpreter, "delete",
1866061da546Spatrick             "Delete a name from the breakpoints provided.",
1867*f6aab3d8Srobert             "breakpoint name delete <command-options> <breakpoint-id-list>") {
1868061da546Spatrick     // Create the first variant for the first (and only) argument for this
1869061da546Spatrick     // command.
1870061da546Spatrick     CommandArgumentEntry arg1;
1871061da546Spatrick     CommandArgumentData id_arg;
1872061da546Spatrick     id_arg.arg_type = eArgTypeBreakpointID;
1873061da546Spatrick     id_arg.arg_repetition = eArgRepeatOptional;
1874061da546Spatrick     arg1.push_back(id_arg);
1875061da546Spatrick     m_arguments.push_back(arg1);
1876061da546Spatrick 
1877061da546Spatrick     m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
1878061da546Spatrick     m_option_group.Finalize();
1879061da546Spatrick   }
1880061da546Spatrick 
1881061da546Spatrick   ~CommandObjectBreakpointNameDelete() override = default;
1882061da546Spatrick 
1883dda28197Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1884dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
1885dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
1886dda28197Spatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
1887dda28197Spatrick         GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
1888dda28197Spatrick         request, nullptr);
1889dda28197Spatrick   }
1890dda28197Spatrick 
GetOptions()1891061da546Spatrick   Options *GetOptions() override { return &m_option_group; }
1892061da546Spatrick 
1893061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1894061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1895061da546Spatrick     if (!m_name_options.m_name.OptionWasSet()) {
1896be691f3bSpatrick       result.AppendError("No name option provided.");
1897061da546Spatrick       return false;
1898061da546Spatrick     }
1899061da546Spatrick 
1900061da546Spatrick     Target &target =
1901061da546Spatrick         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1902061da546Spatrick 
1903061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
1904061da546Spatrick     target.GetBreakpointList().GetListMutex(lock);
1905061da546Spatrick 
1906061da546Spatrick     const BreakpointList &breakpoints = target.GetBreakpointList();
1907061da546Spatrick 
1908061da546Spatrick     size_t num_breakpoints = breakpoints.GetSize();
1909061da546Spatrick     if (num_breakpoints == 0) {
1910be691f3bSpatrick       result.AppendError("No breakpoints, cannot delete names.");
1911061da546Spatrick       return false;
1912061da546Spatrick     }
1913061da546Spatrick 
1914061da546Spatrick     // Particular breakpoint selected; disable that breakpoint.
1915061da546Spatrick     BreakpointIDList valid_bp_ids;
1916061da546Spatrick     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
1917061da546Spatrick         command, &target, result, &valid_bp_ids,
1918061da546Spatrick         BreakpointName::Permissions::PermissionKinds::deletePerm);
1919061da546Spatrick 
1920061da546Spatrick     if (result.Succeeded()) {
1921061da546Spatrick       if (valid_bp_ids.GetSize() == 0) {
1922be691f3bSpatrick         result.AppendError("No breakpoints specified, cannot delete names.");
1923061da546Spatrick         return false;
1924061da546Spatrick       }
1925061da546Spatrick       ConstString bp_name(m_name_options.m_name.GetCurrentValue());
1926061da546Spatrick       size_t num_valid_ids = valid_bp_ids.GetSize();
1927061da546Spatrick       for (size_t index = 0; index < num_valid_ids; index++) {
1928061da546Spatrick         lldb::break_id_t bp_id =
1929061da546Spatrick             valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
1930061da546Spatrick         BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
1931061da546Spatrick         target.RemoveNameFromBreakpoint(bp_sp, bp_name);
1932061da546Spatrick       }
1933061da546Spatrick     }
1934061da546Spatrick 
1935061da546Spatrick     return true;
1936061da546Spatrick   }
1937061da546Spatrick 
1938061da546Spatrick private:
1939061da546Spatrick   BreakpointNameOptionGroup m_name_options;
1940061da546Spatrick   OptionGroupOptions m_option_group;
1941061da546Spatrick };
1942061da546Spatrick 
1943061da546Spatrick class CommandObjectBreakpointNameList : public CommandObjectParsed {
1944061da546Spatrick public:
CommandObjectBreakpointNameList(CommandInterpreter & interpreter)1945061da546Spatrick   CommandObjectBreakpointNameList(CommandInterpreter &interpreter)
1946061da546Spatrick       : CommandObjectParsed(interpreter, "list",
1947061da546Spatrick                             "List either the names for a breakpoint or info "
1948061da546Spatrick                             "about a given name.  With no arguments, lists all "
1949061da546Spatrick                             "names",
1950*f6aab3d8Srobert                             "breakpoint name list <command-options>") {
1951061da546Spatrick     m_option_group.Append(&m_name_options, LLDB_OPT_SET_3, LLDB_OPT_SET_ALL);
1952061da546Spatrick     m_option_group.Finalize();
1953061da546Spatrick   }
1954061da546Spatrick 
1955061da546Spatrick   ~CommandObjectBreakpointNameList() override = default;
1956061da546Spatrick 
GetOptions()1957061da546Spatrick   Options *GetOptions() override { return &m_option_group; }
1958061da546Spatrick 
1959061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1960061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
1961061da546Spatrick     Target &target =
1962061da546Spatrick         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1963061da546Spatrick 
1964061da546Spatrick     std::vector<std::string> name_list;
1965061da546Spatrick     if (command.empty()) {
1966061da546Spatrick       target.GetBreakpointNames(name_list);
1967061da546Spatrick     } else {
1968061da546Spatrick       for (const Args::ArgEntry &arg : command) {
1969061da546Spatrick         name_list.push_back(arg.c_str());
1970061da546Spatrick       }
1971061da546Spatrick     }
1972061da546Spatrick 
1973061da546Spatrick     if (name_list.empty()) {
1974061da546Spatrick       result.AppendMessage("No breakpoint names found.");
1975061da546Spatrick     } else {
1976061da546Spatrick       for (const std::string &name_str : name_list) {
1977061da546Spatrick         const char *name = name_str.c_str();
1978061da546Spatrick         // First print out the options for the name:
1979061da546Spatrick         Status error;
1980061da546Spatrick         BreakpointName *bp_name =
1981061da546Spatrick             target.FindBreakpointName(ConstString(name), false, error);
1982061da546Spatrick         if (bp_name) {
1983061da546Spatrick           StreamString s;
1984061da546Spatrick           result.AppendMessageWithFormat("Name: %s\n", name);
1985061da546Spatrick           if (bp_name->GetDescription(&s, eDescriptionLevelFull)) {
1986061da546Spatrick             result.AppendMessage(s.GetString());
1987061da546Spatrick           }
1988061da546Spatrick 
1989061da546Spatrick           std::unique_lock<std::recursive_mutex> lock;
1990061da546Spatrick           target.GetBreakpointList().GetListMutex(lock);
1991061da546Spatrick 
1992061da546Spatrick           BreakpointList &breakpoints = target.GetBreakpointList();
1993061da546Spatrick           bool any_set = false;
1994061da546Spatrick           for (BreakpointSP bp_sp : breakpoints.Breakpoints()) {
1995061da546Spatrick             if (bp_sp->MatchesName(name)) {
1996061da546Spatrick               StreamString s;
1997061da546Spatrick               any_set = true;
1998061da546Spatrick               bp_sp->GetDescription(&s, eDescriptionLevelBrief);
1999061da546Spatrick               s.EOL();
2000061da546Spatrick               result.AppendMessage(s.GetString());
2001061da546Spatrick             }
2002061da546Spatrick           }
2003061da546Spatrick           if (!any_set)
2004061da546Spatrick             result.AppendMessage("No breakpoints using this name.");
2005061da546Spatrick         } else {
2006061da546Spatrick           result.AppendMessageWithFormat("Name: %s not found.\n", name);
2007061da546Spatrick         }
2008061da546Spatrick       }
2009061da546Spatrick     }
2010061da546Spatrick     return true;
2011061da546Spatrick   }
2012061da546Spatrick 
2013061da546Spatrick private:
2014061da546Spatrick   BreakpointNameOptionGroup m_name_options;
2015061da546Spatrick   OptionGroupOptions m_option_group;
2016061da546Spatrick };
2017061da546Spatrick 
2018061da546Spatrick // CommandObjectBreakpointName
2019061da546Spatrick class CommandObjectBreakpointName : public CommandObjectMultiword {
2020061da546Spatrick public:
CommandObjectBreakpointName(CommandInterpreter & interpreter)2021061da546Spatrick   CommandObjectBreakpointName(CommandInterpreter &interpreter)
2022061da546Spatrick       : CommandObjectMultiword(
2023*f6aab3d8Srobert             interpreter, "name", "Commands to manage breakpoint names") {
2024*f6aab3d8Srobert 
2025*f6aab3d8Srobert 
2026*f6aab3d8Srobert     SetHelpLong(
2027*f6aab3d8Srobert             R"(
2028*f6aab3d8Srobert Breakpoint names provide a general tagging mechanism for breakpoints.  Each
2029*f6aab3d8Srobert breakpoint name can be added to any number of breakpoints, and each breakpoint
2030*f6aab3d8Srobert can have any number of breakpoint names attached to it. For instance:
2031*f6aab3d8Srobert 
2032*f6aab3d8Srobert     (lldb) break name add -N MyName 1-10
2033*f6aab3d8Srobert 
2034*f6aab3d8Srobert adds the name MyName to breakpoints 1-10, and:
2035*f6aab3d8Srobert 
2036*f6aab3d8Srobert     (lldb) break set -n myFunc -N Name1 -N Name2
2037*f6aab3d8Srobert 
2038*f6aab3d8Srobert adds two names to the breakpoint set at myFunc.
2039*f6aab3d8Srobert 
2040*f6aab3d8Srobert They have a number of interrelated uses:
2041*f6aab3d8Srobert 
2042*f6aab3d8Srobert 1) They provide a stable way to refer to a breakpoint (e.g. in another
2043*f6aab3d8Srobert breakpoint's action). Using the breakpoint ID for this purpose is fragile, since
2044*f6aab3d8Srobert it depends on the order of breakpoint creation.  Giving a name to the breakpoint
2045*f6aab3d8Srobert you want to act on, and then referring to it by name, is more robust:
2046*f6aab3d8Srobert 
2047*f6aab3d8Srobert     (lldb) break set -n myFunc -N BKPT1
2048*f6aab3d8Srobert     (lldb) break set -n myOtherFunc -C "break disable BKPT1"
2049*f6aab3d8Srobert 
2050*f6aab3d8Srobert 2) This is actually just a specific use of a more general feature of breakpoint
2051*f6aab3d8Srobert names.  The <breakpt-id-list> argument type used to specify one or more
2052*f6aab3d8Srobert breakpoints in most of the commands that deal with breakpoints also accepts
2053*f6aab3d8Srobert breakpoint names.  That allows you to refer to one breakpoint in a stable
2054*f6aab3d8Srobert manner, but also makes them a convenient grouping mechanism, allowing you to
2055*f6aab3d8Srobert easily act on a group of breakpoints by using their name, for instance disabling
2056*f6aab3d8Srobert them all in one action:
2057*f6aab3d8Srobert 
2058*f6aab3d8Srobert     (lldb) break set -n myFunc -N Group1
2059*f6aab3d8Srobert     (lldb) break set -n myOtherFunc -N Group1
2060*f6aab3d8Srobert     (lldb) break disable Group1
2061*f6aab3d8Srobert 
2062*f6aab3d8Srobert 3) But breakpoint names are also entities in their own right, and can be
2063*f6aab3d8Srobert configured with all the modifiable attributes of a breakpoint.  Then when you
2064*f6aab3d8Srobert add a breakpoint name to a breakpoint, the breakpoint will be configured to
2065*f6aab3d8Srobert match the state of the breakpoint name.  The link between the name and the
2066*f6aab3d8Srobert breakpoints sharing it remains live, so if you change the configuration on the
2067*f6aab3d8Srobert name, it will also change the configurations on the breakpoints:
2068*f6aab3d8Srobert 
2069*f6aab3d8Srobert     (lldb) break name configure -i 10 IgnoreSome
2070*f6aab3d8Srobert     (lldb) break set -n myFunc -N IgnoreSome
2071*f6aab3d8Srobert     (lldb) break list IgnoreSome
2072*f6aab3d8Srobert     2: name = 'myFunc', locations = 0 (pending) Options: ignore: 10 enabled
2073*f6aab3d8Srobert       Names:
2074*f6aab3d8Srobert         IgnoreSome
2075*f6aab3d8Srobert     (lldb) break name configure -i 5 IgnoreSome
2076*f6aab3d8Srobert     (lldb) break list IgnoreSome
2077*f6aab3d8Srobert     2: name = 'myFunc', locations = 0 (pending) Options: ignore: 5 enabled
2078*f6aab3d8Srobert       Names:
2079*f6aab3d8Srobert         IgnoreSome
2080*f6aab3d8Srobert 
2081*f6aab3d8Srobert Options that are not configured on a breakpoint name don't affect the value of
2082*f6aab3d8Srobert those options on the breakpoints they are added to.  So for instance, if Name1
2083*f6aab3d8Srobert has the -i option configured and Name2 the -c option, adding both names to a
2084*f6aab3d8Srobert breakpoint will set the -i option from Name1 and the -c option from Name2, and
2085*f6aab3d8Srobert the other options will be unaltered.
2086*f6aab3d8Srobert 
2087*f6aab3d8Srobert If you add multiple names to a breakpoint which have configured values for
2088*f6aab3d8Srobert the same option, the last name added's value wins.
2089*f6aab3d8Srobert 
2090*f6aab3d8Srobert The "liveness" of these settings is one way, from name to breakpoint.
2091*f6aab3d8Srobert If you use "break modify" to change an option that is also configured on a name
2092*f6aab3d8Srobert which that breakpoint has, the "break modify" command will override the setting
2093*f6aab3d8Srobert for that breakpoint, but won't change the value configured in the name or on the
2094*f6aab3d8Srobert other breakpoints sharing that name.
2095*f6aab3d8Srobert 
2096*f6aab3d8Srobert 4) Breakpoint names are also a convenient way to copy option sets from one
2097*f6aab3d8Srobert breakpoint to another.  Using the -B option to "breakpoint name configure" makes
2098*f6aab3d8Srobert a name configured with all the options of the original breakpoint.  Then
2099*f6aab3d8Srobert adding that name to another breakpoint copies over all the values from the
2100*f6aab3d8Srobert original breakpoint to the new one.
2101*f6aab3d8Srobert 
2102*f6aab3d8Srobert 5) You can also use breakpoint names to hide breakpoints from the breakpoint
2103*f6aab3d8Srobert operations that act on all breakpoints: "break delete", "break disable" and
2104*f6aab3d8Srobert "break list".  You do that by specifying a "false" value for the
2105*f6aab3d8Srobert --allow-{list,delete,disable} options to "breakpoint name configure" and then
2106*f6aab3d8Srobert adding that name to a breakpoint.
2107*f6aab3d8Srobert 
2108*f6aab3d8Srobert This won't keep the breakpoint from being deleted or disabled if you refer to it
2109*f6aab3d8Srobert specifically by ID. The point of the feature is to make sure users don't
2110*f6aab3d8Srobert inadvertently delete or disable useful breakpoints (e.g. ones an IDE is using
2111*f6aab3d8Srobert for its own purposes) as part of a "delete all" or "disable all" operation.  The
2112*f6aab3d8Srobert list hiding is because it's confusing for people to see breakpoints they
2113*f6aab3d8Srobert didn't set.
2114*f6aab3d8Srobert 
2115*f6aab3d8Srobert )");
2116061da546Spatrick     CommandObjectSP add_command_object(
2117061da546Spatrick         new CommandObjectBreakpointNameAdd(interpreter));
2118061da546Spatrick     CommandObjectSP delete_command_object(
2119061da546Spatrick         new CommandObjectBreakpointNameDelete(interpreter));
2120061da546Spatrick     CommandObjectSP list_command_object(
2121061da546Spatrick         new CommandObjectBreakpointNameList(interpreter));
2122061da546Spatrick     CommandObjectSP configure_command_object(
2123061da546Spatrick         new CommandObjectBreakpointNameConfigure(interpreter));
2124061da546Spatrick 
2125061da546Spatrick     LoadSubCommand("add", add_command_object);
2126061da546Spatrick     LoadSubCommand("delete", delete_command_object);
2127061da546Spatrick     LoadSubCommand("list", list_command_object);
2128061da546Spatrick     LoadSubCommand("configure", configure_command_object);
2129061da546Spatrick   }
2130061da546Spatrick 
2131061da546Spatrick   ~CommandObjectBreakpointName() override = default;
2132061da546Spatrick };
2133061da546Spatrick 
2134061da546Spatrick // CommandObjectBreakpointRead
2135061da546Spatrick #pragma mark Read::CommandOptions
2136061da546Spatrick #define LLDB_OPTIONS_breakpoint_read
2137061da546Spatrick #include "CommandOptions.inc"
2138061da546Spatrick 
2139061da546Spatrick #pragma mark Read
2140061da546Spatrick 
2141061da546Spatrick class CommandObjectBreakpointRead : public CommandObjectParsed {
2142061da546Spatrick public:
CommandObjectBreakpointRead(CommandInterpreter & interpreter)2143061da546Spatrick   CommandObjectBreakpointRead(CommandInterpreter &interpreter)
2144061da546Spatrick       : CommandObjectParsed(interpreter, "breakpoint read",
2145061da546Spatrick                             "Read and set the breakpoints previously saved to "
2146061da546Spatrick                             "a file with \"breakpoint write\".  ",
2147*f6aab3d8Srobert                             nullptr) {}
2148061da546Spatrick 
2149061da546Spatrick   ~CommandObjectBreakpointRead() override = default;
2150061da546Spatrick 
GetOptions()2151061da546Spatrick   Options *GetOptions() override { return &m_options; }
2152061da546Spatrick 
2153061da546Spatrick   class CommandOptions : public Options {
2154061da546Spatrick   public:
2155*f6aab3d8Srobert     CommandOptions() = default;
2156061da546Spatrick 
2157061da546Spatrick     ~CommandOptions() override = default;
2158061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2159061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2160061da546Spatrick                           ExecutionContext *execution_context) override {
2161061da546Spatrick       Status error;
2162061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
2163061da546Spatrick 
2164061da546Spatrick       switch (short_option) {
2165061da546Spatrick       case 'f':
2166dda28197Spatrick         m_filename.assign(std::string(option_arg));
2167061da546Spatrick         break;
2168061da546Spatrick       case 'N': {
2169061da546Spatrick         Status name_error;
2170061da546Spatrick         if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg),
2171061da546Spatrick                                                   name_error)) {
2172061da546Spatrick           error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
2173061da546Spatrick                                          name_error.AsCString());
2174061da546Spatrick         }
2175dda28197Spatrick         m_names.push_back(std::string(option_arg));
2176061da546Spatrick         break;
2177061da546Spatrick       }
2178061da546Spatrick       default:
2179061da546Spatrick         llvm_unreachable("Unimplemented option");
2180061da546Spatrick       }
2181061da546Spatrick 
2182061da546Spatrick       return error;
2183061da546Spatrick     }
2184061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)2185061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
2186061da546Spatrick       m_filename.clear();
2187061da546Spatrick       m_names.clear();
2188061da546Spatrick     }
2189061da546Spatrick 
GetDefinitions()2190061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2191*f6aab3d8Srobert       return llvm::ArrayRef(g_breakpoint_read_options);
2192061da546Spatrick     }
2193061da546Spatrick 
HandleOptionArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector,int opt_element_index,CommandInterpreter & interpreter)2194be691f3bSpatrick     void HandleOptionArgumentCompletion(
2195be691f3bSpatrick         CompletionRequest &request, OptionElementVector &opt_element_vector,
2196be691f3bSpatrick         int opt_element_index, CommandInterpreter &interpreter) override {
2197be691f3bSpatrick       int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
2198be691f3bSpatrick       int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
2199be691f3bSpatrick 
2200be691f3bSpatrick       switch (GetDefinitions()[opt_defs_index].short_option) {
2201be691f3bSpatrick       case 'f':
2202be691f3bSpatrick         CommandCompletions::InvokeCommonCompletionCallbacks(
2203be691f3bSpatrick             interpreter, CommandCompletions::eDiskFileCompletion, request,
2204be691f3bSpatrick             nullptr);
2205be691f3bSpatrick         break;
2206be691f3bSpatrick 
2207be691f3bSpatrick       case 'N':
2208*f6aab3d8Srobert         std::optional<FileSpec> file_spec;
2209be691f3bSpatrick         const llvm::StringRef dash_f("-f");
2210be691f3bSpatrick         for (int arg_idx = 0; arg_idx < opt_arg_pos; arg_idx++) {
2211be691f3bSpatrick           if (dash_f == request.GetParsedLine().GetArgumentAtIndex(arg_idx)) {
2212be691f3bSpatrick             file_spec.emplace(
2213be691f3bSpatrick                 request.GetParsedLine().GetArgumentAtIndex(arg_idx + 1));
2214be691f3bSpatrick             break;
2215be691f3bSpatrick           }
2216be691f3bSpatrick         }
2217be691f3bSpatrick         if (!file_spec)
2218be691f3bSpatrick           return;
2219be691f3bSpatrick 
2220be691f3bSpatrick         FileSystem::Instance().Resolve(*file_spec);
2221be691f3bSpatrick         Status error;
2222be691f3bSpatrick         StructuredData::ObjectSP input_data_sp =
2223be691f3bSpatrick             StructuredData::ParseJSONFromFile(*file_spec, error);
2224be691f3bSpatrick         if (!error.Success())
2225be691f3bSpatrick           return;
2226be691f3bSpatrick 
2227be691f3bSpatrick         StructuredData::Array *bkpt_array = input_data_sp->GetAsArray();
2228be691f3bSpatrick         if (!bkpt_array)
2229be691f3bSpatrick           return;
2230be691f3bSpatrick 
2231be691f3bSpatrick         const size_t num_bkpts = bkpt_array->GetSize();
2232be691f3bSpatrick         for (size_t i = 0; i < num_bkpts; i++) {
2233be691f3bSpatrick           StructuredData::ObjectSP bkpt_object_sp =
2234be691f3bSpatrick               bkpt_array->GetItemAtIndex(i);
2235be691f3bSpatrick           if (!bkpt_object_sp)
2236be691f3bSpatrick             return;
2237be691f3bSpatrick 
2238be691f3bSpatrick           StructuredData::Dictionary *bkpt_dict =
2239be691f3bSpatrick               bkpt_object_sp->GetAsDictionary();
2240be691f3bSpatrick           if (!bkpt_dict)
2241be691f3bSpatrick             return;
2242be691f3bSpatrick 
2243be691f3bSpatrick           StructuredData::ObjectSP bkpt_data_sp =
2244be691f3bSpatrick               bkpt_dict->GetValueForKey(Breakpoint::GetSerializationKey());
2245be691f3bSpatrick           if (!bkpt_data_sp)
2246be691f3bSpatrick             return;
2247be691f3bSpatrick 
2248be691f3bSpatrick           bkpt_dict = bkpt_data_sp->GetAsDictionary();
2249be691f3bSpatrick           if (!bkpt_dict)
2250be691f3bSpatrick             return;
2251be691f3bSpatrick 
2252be691f3bSpatrick           StructuredData::Array *names_array;
2253be691f3bSpatrick 
2254be691f3bSpatrick           if (!bkpt_dict->GetValueForKeyAsArray("Names", names_array))
2255be691f3bSpatrick             return;
2256be691f3bSpatrick 
2257be691f3bSpatrick           size_t num_names = names_array->GetSize();
2258be691f3bSpatrick 
2259be691f3bSpatrick           for (size_t i = 0; i < num_names; i++) {
2260be691f3bSpatrick             llvm::StringRef name;
2261be691f3bSpatrick             if (names_array->GetItemAtIndexAsString(i, name))
2262be691f3bSpatrick               request.TryCompleteCurrentArg(name);
2263be691f3bSpatrick           }
2264be691f3bSpatrick         }
2265be691f3bSpatrick       }
2266be691f3bSpatrick     }
2267061da546Spatrick 
2268061da546Spatrick     std::string m_filename;
2269061da546Spatrick     std::vector<std::string> m_names;
2270061da546Spatrick   };
2271061da546Spatrick 
2272061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)2273061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
2274061da546Spatrick     Target &target = GetSelectedOrDummyTarget();
2275061da546Spatrick 
2276061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
2277061da546Spatrick     target.GetBreakpointList().GetListMutex(lock);
2278061da546Spatrick 
2279061da546Spatrick     FileSpec input_spec(m_options.m_filename);
2280061da546Spatrick     FileSystem::Instance().Resolve(input_spec);
2281061da546Spatrick     BreakpointIDList new_bps;
2282061da546Spatrick     Status error = target.CreateBreakpointsFromFile(input_spec,
2283061da546Spatrick                                                     m_options.m_names, new_bps);
2284061da546Spatrick 
2285061da546Spatrick     if (!error.Success()) {
2286061da546Spatrick       result.AppendError(error.AsCString());
2287061da546Spatrick       return false;
2288061da546Spatrick     }
2289061da546Spatrick 
2290061da546Spatrick     Stream &output_stream = result.GetOutputStream();
2291061da546Spatrick 
2292061da546Spatrick     size_t num_breakpoints = new_bps.GetSize();
2293061da546Spatrick     if (num_breakpoints == 0) {
2294061da546Spatrick       result.AppendMessage("No breakpoints added.");
2295061da546Spatrick     } else {
2296061da546Spatrick       // No breakpoint selected; show info about all currently set breakpoints.
2297061da546Spatrick       result.AppendMessage("New breakpoints:");
2298061da546Spatrick       for (size_t i = 0; i < num_breakpoints; ++i) {
2299061da546Spatrick         BreakpointID bp_id = new_bps.GetBreakpointIDAtIndex(i);
2300061da546Spatrick         Breakpoint *bp = target.GetBreakpointList()
2301061da546Spatrick                              .FindBreakpointByID(bp_id.GetBreakpointID())
2302061da546Spatrick                              .get();
2303061da546Spatrick         if (bp)
2304061da546Spatrick           bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
2305061da546Spatrick                              false);
2306061da546Spatrick       }
2307061da546Spatrick     }
2308061da546Spatrick     return result.Succeeded();
2309061da546Spatrick   }
2310061da546Spatrick 
2311061da546Spatrick private:
2312061da546Spatrick   CommandOptions m_options;
2313061da546Spatrick };
2314061da546Spatrick 
2315061da546Spatrick // CommandObjectBreakpointWrite
2316061da546Spatrick #pragma mark Write::CommandOptions
2317061da546Spatrick #define LLDB_OPTIONS_breakpoint_write
2318061da546Spatrick #include "CommandOptions.inc"
2319061da546Spatrick 
2320061da546Spatrick #pragma mark Write
2321061da546Spatrick class CommandObjectBreakpointWrite : public CommandObjectParsed {
2322061da546Spatrick public:
CommandObjectBreakpointWrite(CommandInterpreter & interpreter)2323061da546Spatrick   CommandObjectBreakpointWrite(CommandInterpreter &interpreter)
2324061da546Spatrick       : CommandObjectParsed(interpreter, "breakpoint write",
2325061da546Spatrick                             "Write the breakpoints listed to a file that can "
2326061da546Spatrick                             "be read in with \"breakpoint read\".  "
2327061da546Spatrick                             "If given no arguments, writes all breakpoints.",
2328*f6aab3d8Srobert                             nullptr) {
2329061da546Spatrick     CommandArgumentEntry arg;
2330061da546Spatrick     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
2331061da546Spatrick                                       eArgTypeBreakpointIDRange);
2332061da546Spatrick     // Add the entry for the first argument for this command to the object's
2333061da546Spatrick     // arguments vector.
2334061da546Spatrick     m_arguments.push_back(arg);
2335061da546Spatrick   }
2336061da546Spatrick 
2337061da546Spatrick   ~CommandObjectBreakpointWrite() override = default;
2338061da546Spatrick 
2339dda28197Spatrick   void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2340dda28197Spatrick   HandleArgumentCompletion(CompletionRequest &request,
2341dda28197Spatrick                            OptionElementVector &opt_element_vector) override {
2342dda28197Spatrick     CommandCompletions::InvokeCommonCompletionCallbacks(
2343dda28197Spatrick         GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
2344dda28197Spatrick         request, nullptr);
2345dda28197Spatrick   }
2346dda28197Spatrick 
GetOptions()2347061da546Spatrick   Options *GetOptions() override { return &m_options; }
2348061da546Spatrick 
2349061da546Spatrick   class CommandOptions : public Options {
2350061da546Spatrick   public:
2351*f6aab3d8Srobert     CommandOptions() = default;
2352061da546Spatrick 
2353061da546Spatrick     ~CommandOptions() override = default;
2354061da546Spatrick 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2355061da546Spatrick     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2356061da546Spatrick                           ExecutionContext *execution_context) override {
2357061da546Spatrick       Status error;
2358061da546Spatrick       const int short_option = m_getopt_table[option_idx].val;
2359061da546Spatrick 
2360061da546Spatrick       switch (short_option) {
2361061da546Spatrick       case 'f':
2362dda28197Spatrick         m_filename.assign(std::string(option_arg));
2363061da546Spatrick         break;
2364061da546Spatrick       case 'a':
2365061da546Spatrick         m_append = true;
2366061da546Spatrick         break;
2367061da546Spatrick       default:
2368061da546Spatrick         llvm_unreachable("Unimplemented option");
2369061da546Spatrick       }
2370061da546Spatrick 
2371061da546Spatrick       return error;
2372061da546Spatrick     }
2373061da546Spatrick 
OptionParsingStarting(ExecutionContext * execution_context)2374061da546Spatrick     void OptionParsingStarting(ExecutionContext *execution_context) override {
2375061da546Spatrick       m_filename.clear();
2376061da546Spatrick       m_append = false;
2377061da546Spatrick     }
2378061da546Spatrick 
GetDefinitions()2379061da546Spatrick     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2380*f6aab3d8Srobert       return llvm::ArrayRef(g_breakpoint_write_options);
2381061da546Spatrick     }
2382061da546Spatrick 
2383061da546Spatrick     // Instance variables to hold the values for command options.
2384061da546Spatrick 
2385061da546Spatrick     std::string m_filename;
2386061da546Spatrick     bool m_append = false;
2387061da546Spatrick   };
2388061da546Spatrick 
2389061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)2390061da546Spatrick   bool DoExecute(Args &command, CommandReturnObject &result) override {
2391061da546Spatrick     Target &target = GetSelectedOrDummyTarget();
2392061da546Spatrick 
2393061da546Spatrick     std::unique_lock<std::recursive_mutex> lock;
2394061da546Spatrick     target.GetBreakpointList().GetListMutex(lock);
2395061da546Spatrick 
2396061da546Spatrick     BreakpointIDList valid_bp_ids;
2397061da546Spatrick     if (!command.empty()) {
2398061da546Spatrick       CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
2399061da546Spatrick           command, &target, result, &valid_bp_ids,
2400061da546Spatrick           BreakpointName::Permissions::PermissionKinds::listPerm);
2401061da546Spatrick 
2402061da546Spatrick       if (!result.Succeeded()) {
2403061da546Spatrick         result.SetStatus(eReturnStatusFailed);
2404061da546Spatrick         return false;
2405061da546Spatrick       }
2406061da546Spatrick     }
2407061da546Spatrick     FileSpec file_spec(m_options.m_filename);
2408061da546Spatrick     FileSystem::Instance().Resolve(file_spec);
2409061da546Spatrick     Status error = target.SerializeBreakpointsToFile(file_spec, valid_bp_ids,
2410061da546Spatrick                                                      m_options.m_append);
2411061da546Spatrick     if (!error.Success()) {
2412061da546Spatrick       result.AppendErrorWithFormat("error serializing breakpoints: %s.",
2413061da546Spatrick                                    error.AsCString());
2414061da546Spatrick     }
2415061da546Spatrick     return result.Succeeded();
2416061da546Spatrick   }
2417061da546Spatrick 
2418061da546Spatrick private:
2419061da546Spatrick   CommandOptions m_options;
2420061da546Spatrick };
2421061da546Spatrick 
2422061da546Spatrick // CommandObjectMultiwordBreakpoint
2423061da546Spatrick #pragma mark MultiwordBreakpoint
2424061da546Spatrick 
CommandObjectMultiwordBreakpoint(CommandInterpreter & interpreter)2425061da546Spatrick CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
2426061da546Spatrick     CommandInterpreter &interpreter)
2427061da546Spatrick     : CommandObjectMultiword(
2428061da546Spatrick           interpreter, "breakpoint",
2429061da546Spatrick           "Commands for operating on breakpoints (see 'help b' for shorthand.)",
2430061da546Spatrick           "breakpoint <subcommand> [<command-options>]") {
2431061da546Spatrick   CommandObjectSP list_command_object(
2432061da546Spatrick       new CommandObjectBreakpointList(interpreter));
2433061da546Spatrick   CommandObjectSP enable_command_object(
2434061da546Spatrick       new CommandObjectBreakpointEnable(interpreter));
2435061da546Spatrick   CommandObjectSP disable_command_object(
2436061da546Spatrick       new CommandObjectBreakpointDisable(interpreter));
2437061da546Spatrick   CommandObjectSP clear_command_object(
2438061da546Spatrick       new CommandObjectBreakpointClear(interpreter));
2439061da546Spatrick   CommandObjectSP delete_command_object(
2440061da546Spatrick       new CommandObjectBreakpointDelete(interpreter));
2441061da546Spatrick   CommandObjectSP set_command_object(
2442061da546Spatrick       new CommandObjectBreakpointSet(interpreter));
2443061da546Spatrick   CommandObjectSP command_command_object(
2444061da546Spatrick       new CommandObjectBreakpointCommand(interpreter));
2445061da546Spatrick   CommandObjectSP modify_command_object(
2446061da546Spatrick       new CommandObjectBreakpointModify(interpreter));
2447061da546Spatrick   CommandObjectSP name_command_object(
2448061da546Spatrick       new CommandObjectBreakpointName(interpreter));
2449061da546Spatrick   CommandObjectSP write_command_object(
2450061da546Spatrick       new CommandObjectBreakpointWrite(interpreter));
2451061da546Spatrick   CommandObjectSP read_command_object(
2452061da546Spatrick       new CommandObjectBreakpointRead(interpreter));
2453061da546Spatrick 
2454061da546Spatrick   list_command_object->SetCommandName("breakpoint list");
2455061da546Spatrick   enable_command_object->SetCommandName("breakpoint enable");
2456061da546Spatrick   disable_command_object->SetCommandName("breakpoint disable");
2457061da546Spatrick   clear_command_object->SetCommandName("breakpoint clear");
2458061da546Spatrick   delete_command_object->SetCommandName("breakpoint delete");
2459061da546Spatrick   set_command_object->SetCommandName("breakpoint set");
2460061da546Spatrick   command_command_object->SetCommandName("breakpoint command");
2461061da546Spatrick   modify_command_object->SetCommandName("breakpoint modify");
2462061da546Spatrick   name_command_object->SetCommandName("breakpoint name");
2463061da546Spatrick   write_command_object->SetCommandName("breakpoint write");
2464061da546Spatrick   read_command_object->SetCommandName("breakpoint read");
2465061da546Spatrick 
2466061da546Spatrick   LoadSubCommand("list", list_command_object);
2467061da546Spatrick   LoadSubCommand("enable", enable_command_object);
2468061da546Spatrick   LoadSubCommand("disable", disable_command_object);
2469061da546Spatrick   LoadSubCommand("clear", clear_command_object);
2470061da546Spatrick   LoadSubCommand("delete", delete_command_object);
2471061da546Spatrick   LoadSubCommand("set", set_command_object);
2472061da546Spatrick   LoadSubCommand("command", command_command_object);
2473061da546Spatrick   LoadSubCommand("modify", modify_command_object);
2474061da546Spatrick   LoadSubCommand("name", name_command_object);
2475061da546Spatrick   LoadSubCommand("write", write_command_object);
2476061da546Spatrick   LoadSubCommand("read", read_command_object);
2477061da546Spatrick }
2478061da546Spatrick 
2479061da546Spatrick CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default;
2480061da546Spatrick 
VerifyIDs(Args & args,Target * target,bool allow_locations,CommandReturnObject & result,BreakpointIDList * valid_ids,BreakpointName::Permissions::PermissionKinds purpose)2481061da546Spatrick void CommandObjectMultiwordBreakpoint::VerifyIDs(
2482061da546Spatrick     Args &args, Target *target, bool allow_locations,
2483061da546Spatrick     CommandReturnObject &result, BreakpointIDList *valid_ids,
2484061da546Spatrick     BreakpointName::Permissions ::PermissionKinds purpose) {
2485061da546Spatrick   // args can be strings representing 1). integers (for breakpoint ids)
2486061da546Spatrick   //                                  2). the full breakpoint & location
2487061da546Spatrick   //                                  canonical representation
2488061da546Spatrick   //                                  3). the word "to" or a hyphen,
2489061da546Spatrick   //                                  representing a range (in which case there
2490061da546Spatrick   //                                      had *better* be an entry both before &
2491061da546Spatrick   //                                      after of one of the first two types.
2492061da546Spatrick   //                                  4). A breakpoint name
2493061da546Spatrick   // If args is empty, we will use the last created breakpoint (if there is
2494061da546Spatrick   // one.)
2495061da546Spatrick 
2496061da546Spatrick   Args temp_args;
2497061da546Spatrick 
2498061da546Spatrick   if (args.empty()) {
2499061da546Spatrick     if (target->GetLastCreatedBreakpoint()) {
2500061da546Spatrick       valid_ids->AddBreakpointID(BreakpointID(
2501061da546Spatrick           target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID));
2502061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2503061da546Spatrick     } else {
2504061da546Spatrick       result.AppendError(
2505061da546Spatrick           "No breakpoint specified and no last created breakpoint.");
2506061da546Spatrick     }
2507061da546Spatrick     return;
2508061da546Spatrick   }
2509061da546Spatrick 
2510061da546Spatrick   // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff
2511061da546Spatrick   // directly from the old ARGS to the new TEMP_ARGS.  Do not copy breakpoint
2512061da546Spatrick   // id range strings over; instead generate a list of strings for all the
2513061da546Spatrick   // breakpoint ids in the range, and shove all of those breakpoint id strings
2514061da546Spatrick   // into TEMP_ARGS.
2515061da546Spatrick 
2516061da546Spatrick   BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations,
2517061da546Spatrick                                            purpose, result, temp_args);
2518061da546Spatrick 
2519061da546Spatrick   // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual
2520061da546Spatrick   // BreakpointIDList:
2521061da546Spatrick 
2522061da546Spatrick   valid_ids->InsertStringArray(temp_args.GetArgumentArrayRef(), result);
2523061da546Spatrick 
2524061da546Spatrick   // At this point,  all of the breakpoint ids that the user passed in have
2525061da546Spatrick   // been converted to breakpoint IDs and put into valid_ids.
2526061da546Spatrick 
2527061da546Spatrick   if (result.Succeeded()) {
2528061da546Spatrick     // Now that we've converted everything from args into a list of breakpoint
2529061da546Spatrick     // ids, go through our tentative list of breakpoint id's and verify that
2530061da546Spatrick     // they correspond to valid/currently set breakpoints.
2531061da546Spatrick 
2532061da546Spatrick     const size_t count = valid_ids->GetSize();
2533061da546Spatrick     for (size_t i = 0; i < count; ++i) {
2534061da546Spatrick       BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex(i);
2535061da546Spatrick       Breakpoint *breakpoint =
2536061da546Spatrick           target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
2537061da546Spatrick       if (breakpoint != nullptr) {
2538061da546Spatrick         const size_t num_locations = breakpoint->GetNumLocations();
2539061da546Spatrick         if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) {
2540061da546Spatrick           StreamString id_str;
2541061da546Spatrick           BreakpointID::GetCanonicalReference(
2542061da546Spatrick               &id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
2543061da546Spatrick           i = valid_ids->GetSize() + 1;
2544061da546Spatrick           result.AppendErrorWithFormat(
2545061da546Spatrick               "'%s' is not a currently valid breakpoint/location id.\n",
2546061da546Spatrick               id_str.GetData());
2547061da546Spatrick         }
2548061da546Spatrick       } else {
2549061da546Spatrick         i = valid_ids->GetSize() + 1;
2550061da546Spatrick         result.AppendErrorWithFormat(
2551061da546Spatrick             "'%d' is not a currently valid breakpoint ID.\n",
2552061da546Spatrick             cur_bp_id.GetBreakpointID());
2553061da546Spatrick       }
2554061da546Spatrick     }
2555061da546Spatrick   }
2556061da546Spatrick }
2557