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

source code of lldb/source/Commands/CommandObjectBreakpoint.cpp