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