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