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