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

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