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

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

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