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