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

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