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