[PowerPC] Collect some CallLowering arguments into a struct. [NFC]
[llvm-project.git] / lldb / source / Commands / CommandObjectBreakpoint.cpp
blob7c4c50ecf3f920b2acce2b84cfb4185d80d04096
1 //===-- CommandObjectBreakpoint.cpp -----------------------------*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
9 #include "CommandObjectBreakpoint.h"
10 #include "CommandObjectBreakpointCommand.h"
11 #include "lldb/Breakpoint/Breakpoint.h"
12 #include "lldb/Breakpoint/BreakpointIDList.h"
13 #include "lldb/Breakpoint/BreakpointLocation.h"
14 #include "lldb/Host/OptionParser.h"
15 #include "lldb/Interpreter/CommandInterpreter.h"
16 #include "lldb/Interpreter/CommandReturnObject.h"
17 #include "lldb/Interpreter/OptionArgParser.h"
18 #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
19 #include "lldb/Interpreter/OptionValueBoolean.h"
20 #include "lldb/Interpreter/OptionValueString.h"
21 #include "lldb/Interpreter/OptionValueUInt64.h"
22 #include "lldb/Interpreter/Options.h"
23 #include "lldb/Target/Language.h"
24 #include "lldb/Target/StackFrame.h"
25 #include "lldb/Target/Target.h"
26 #include "lldb/Target/ThreadSpec.h"
27 #include "lldb/Utility/RegularExpression.h"
28 #include "lldb/Utility/StreamString.h"
30 #include <memory>
31 #include <vector>
33 using namespace lldb;
34 using namespace lldb_private;
36 static void AddBreakpointDescription(Stream *s, Breakpoint *bp,
37 lldb::DescriptionLevel level) {
38 s->IndentMore();
39 bp->GetDescription(s, level, true);
40 s->IndentLess();
41 s->EOL();
44 // Modifiable Breakpoint Options
45 #pragma mark Modify::CommandOptions
46 #define LLDB_OPTIONS_breakpoint_modify
47 #include "CommandOptions.inc"
49 class lldb_private::BreakpointOptionGroup : public OptionGroup {
50 public:
51 BreakpointOptionGroup() : OptionGroup(), m_bp_opts(false) {}
53 ~BreakpointOptionGroup() override = default;
55 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
56 return llvm::makeArrayRef(g_breakpoint_modify_options);
59 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
60 ExecutionContext *execution_context) override {
61 Status error;
62 const int short_option =
63 g_breakpoint_modify_options[option_idx].short_option;
65 switch (short_option) {
66 case 'c':
67 // Normally an empty breakpoint condition marks is as unset. But we need
68 // to say it was passed in.
69 m_bp_opts.SetCondition(option_arg.str().c_str());
70 m_bp_opts.m_set_flags.Set(BreakpointOptions::eCondition);
71 break;
72 case 'C':
73 m_commands.push_back(option_arg);
74 break;
75 case 'd':
76 m_bp_opts.SetEnabled(false);
77 break;
78 case 'e':
79 m_bp_opts.SetEnabled(true);
80 break;
81 case 'G': {
82 bool value, success;
83 value = OptionArgParser::ToBoolean(option_arg, false, &success);
84 if (success) {
85 m_bp_opts.SetAutoContinue(value);
86 } else
87 error.SetErrorStringWithFormat(
88 "invalid boolean value '%s' passed for -G option",
89 option_arg.str().c_str());
90 } break;
91 case 'i': {
92 uint32_t ignore_count;
93 if (option_arg.getAsInteger(0, ignore_count))
94 error.SetErrorStringWithFormat("invalid ignore count '%s'",
95 option_arg.str().c_str());
96 else
97 m_bp_opts.SetIgnoreCount(ignore_count);
98 } break;
99 case 'o': {
100 bool value, success;
101 value = OptionArgParser::ToBoolean(option_arg, false, &success);
102 if (success) {
103 m_bp_opts.SetOneShot(value);
104 } else
105 error.SetErrorStringWithFormat(
106 "invalid boolean value '%s' passed for -o option",
107 option_arg.str().c_str());
108 } break;
109 case 't': {
110 lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID;
111 if (option_arg[0] != '\0') {
112 if (option_arg.getAsInteger(0, thread_id))
113 error.SetErrorStringWithFormat("invalid thread id string '%s'",
114 option_arg.str().c_str());
116 m_bp_opts.SetThreadID(thread_id);
117 } break;
118 case 'T':
119 m_bp_opts.GetThreadSpec()->SetName(option_arg.str().c_str());
120 break;
121 case 'q':
122 m_bp_opts.GetThreadSpec()->SetQueueName(option_arg.str().c_str());
123 break;
124 case 'x': {
125 uint32_t thread_index = UINT32_MAX;
126 if (option_arg[0] != '\n') {
127 if (option_arg.getAsInteger(0, thread_index))
128 error.SetErrorStringWithFormat("invalid thread index string '%s'",
129 option_arg.str().c_str());
131 m_bp_opts.GetThreadSpec()->SetIndex(thread_index);
132 } break;
133 default:
134 llvm_unreachable("Unimplemented option");
137 return error;
140 void OptionParsingStarting(ExecutionContext *execution_context) override {
141 m_bp_opts.Clear();
142 m_commands.clear();
145 Status OptionParsingFinished(ExecutionContext *execution_context) override {
146 if (!m_commands.empty()) {
147 auto cmd_data = std::make_unique<BreakpointOptions::CommandData>();
149 for (std::string &str : m_commands)
150 cmd_data->user_source.AppendString(str);
152 cmd_data->stop_on_error = true;
153 m_bp_opts.SetCommandDataCallback(cmd_data);
155 return Status();
158 const BreakpointOptions &GetBreakpointOptions() { return m_bp_opts; }
160 std::vector<std::string> m_commands;
161 BreakpointOptions m_bp_opts;
164 #define LLDB_OPTIONS_breakpoint_dummy
165 #include "CommandOptions.inc"
167 class BreakpointDummyOptionGroup : public OptionGroup {
168 public:
169 BreakpointDummyOptionGroup() : OptionGroup() {}
171 ~BreakpointDummyOptionGroup() override = default;
173 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
174 return llvm::makeArrayRef(g_breakpoint_dummy_options);
177 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
178 ExecutionContext *execution_context) override {
179 Status error;
180 const int short_option =
181 g_breakpoint_dummy_options[option_idx].short_option;
183 switch (short_option) {
184 case 'D':
185 m_use_dummy = true;
186 break;
187 default:
188 llvm_unreachable("Unimplemented option");
191 return error;
194 void OptionParsingStarting(ExecutionContext *execution_context) override {
195 m_use_dummy = false;
198 bool m_use_dummy;
201 #define LLDB_OPTIONS_breakpoint_set
202 #include "CommandOptions.inc"
204 // CommandObjectBreakpointSet
206 class CommandObjectBreakpointSet : public CommandObjectParsed {
207 public:
208 enum BreakpointSetType {
209 eSetTypeInvalid,
210 eSetTypeFileAndLine,
211 eSetTypeAddress,
212 eSetTypeFunctionName,
213 eSetTypeFunctionRegexp,
214 eSetTypeSourceRegexp,
215 eSetTypeException,
216 eSetTypeScripted,
219 CommandObjectBreakpointSet(CommandInterpreter &interpreter)
220 : CommandObjectParsed(
221 interpreter, "breakpoint set",
222 "Sets a breakpoint or set of breakpoints in the executable.",
223 "breakpoint set <cmd-options>"),
224 m_bp_opts(), m_python_class_options("scripted breakpoint", true, 'P'),
225 m_options() {
226 // We're picking up all the normal options, commands and disable.
227 m_all_options.Append(&m_python_class_options,
228 LLDB_OPT_SET_1 | LLDB_OPT_SET_2, LLDB_OPT_SET_11);
229 m_all_options.Append(&m_bp_opts,
230 LLDB_OPT_SET_1 | LLDB_OPT_SET_3 | LLDB_OPT_SET_4,
231 LLDB_OPT_SET_ALL);
232 m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
233 m_all_options.Append(&m_options);
234 m_all_options.Finalize();
237 ~CommandObjectBreakpointSet() override = default;
239 Options *GetOptions() override { return &m_all_options; }
241 class CommandOptions : public OptionGroup {
242 public:
243 CommandOptions()
244 : OptionGroup(), m_condition(), m_filenames(), m_line_num(0),
245 m_column(0), m_func_names(),
246 m_func_name_type_mask(eFunctionNameTypeNone), m_func_regexp(),
247 m_source_text_regexp(), m_modules(), m_load_addr(), m_catch_bp(false),
248 m_throw_bp(true), m_hardware(false),
249 m_exception_language(eLanguageTypeUnknown),
250 m_language(lldb::eLanguageTypeUnknown),
251 m_skip_prologue(eLazyBoolCalculate), m_all_files(false),
252 m_move_to_nearest_code(eLazyBoolCalculate) {}
254 ~CommandOptions() override = default;
256 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
257 ExecutionContext *execution_context) override {
258 Status error;
259 const int short_option =
260 g_breakpoint_set_options[option_idx].short_option;
262 switch (short_option) {
263 case 'a': {
264 m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg,
265 LLDB_INVALID_ADDRESS, &error);
266 } break;
268 case 'A':
269 m_all_files = true;
270 break;
272 case 'b':
273 m_func_names.push_back(option_arg);
274 m_func_name_type_mask |= eFunctionNameTypeBase;
275 break;
277 case 'C':
278 if (option_arg.getAsInteger(0, m_column))
279 error.SetErrorStringWithFormat("invalid column number: %s",
280 option_arg.str().c_str());
281 break;
283 case 'E': {
284 LanguageType language = Language::GetLanguageTypeFromString(option_arg);
286 switch (language) {
287 case eLanguageTypeC89:
288 case eLanguageTypeC:
289 case eLanguageTypeC99:
290 case eLanguageTypeC11:
291 m_exception_language = eLanguageTypeC;
292 break;
293 case eLanguageTypeC_plus_plus:
294 case eLanguageTypeC_plus_plus_03:
295 case eLanguageTypeC_plus_plus_11:
296 case eLanguageTypeC_plus_plus_14:
297 m_exception_language = eLanguageTypeC_plus_plus;
298 break;
299 case eLanguageTypeObjC:
300 m_exception_language = eLanguageTypeObjC;
301 break;
302 case eLanguageTypeObjC_plus_plus:
303 error.SetErrorStringWithFormat(
304 "Set exception breakpoints separately for c++ and objective-c");
305 break;
306 case eLanguageTypeUnknown:
307 error.SetErrorStringWithFormat(
308 "Unknown language type: '%s' for exception breakpoint",
309 option_arg.str().c_str());
310 break;
311 default:
312 error.SetErrorStringWithFormat(
313 "Unsupported language type: '%s' for exception breakpoint",
314 option_arg.str().c_str());
316 } break;
318 case 'f':
319 m_filenames.AppendIfUnique(FileSpec(option_arg));
320 break;
322 case 'F':
323 m_func_names.push_back(option_arg);
324 m_func_name_type_mask |= eFunctionNameTypeFull;
325 break;
327 case 'h': {
328 bool success;
329 m_catch_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
330 if (!success)
331 error.SetErrorStringWithFormat(
332 "Invalid boolean value for on-catch option: '%s'",
333 option_arg.str().c_str());
334 } break;
336 case 'H':
337 m_hardware = true;
338 break;
340 case 'K': {
341 bool success;
342 bool value;
343 value = OptionArgParser::ToBoolean(option_arg, true, &success);
344 if (value)
345 m_skip_prologue = eLazyBoolYes;
346 else
347 m_skip_prologue = eLazyBoolNo;
349 if (!success)
350 error.SetErrorStringWithFormat(
351 "Invalid boolean value for skip prologue option: '%s'",
352 option_arg.str().c_str());
353 } break;
355 case 'l':
356 if (option_arg.getAsInteger(0, m_line_num))
357 error.SetErrorStringWithFormat("invalid line number: %s.",
358 option_arg.str().c_str());
359 break;
361 case 'L':
362 m_language = Language::GetLanguageTypeFromString(option_arg);
363 if (m_language == eLanguageTypeUnknown)
364 error.SetErrorStringWithFormat(
365 "Unknown language type: '%s' for breakpoint",
366 option_arg.str().c_str());
367 break;
369 case 'm': {
370 bool success;
371 bool value;
372 value = OptionArgParser::ToBoolean(option_arg, true, &success);
373 if (value)
374 m_move_to_nearest_code = eLazyBoolYes;
375 else
376 m_move_to_nearest_code = eLazyBoolNo;
378 if (!success)
379 error.SetErrorStringWithFormat(
380 "Invalid boolean value for move-to-nearest-code option: '%s'",
381 option_arg.str().c_str());
382 break;
385 case 'M':
386 m_func_names.push_back(option_arg);
387 m_func_name_type_mask |= eFunctionNameTypeMethod;
388 break;
390 case 'n':
391 m_func_names.push_back(option_arg);
392 m_func_name_type_mask |= eFunctionNameTypeAuto;
393 break;
395 case 'N': {
396 if (BreakpointID::StringIsBreakpointName(option_arg, error))
397 m_breakpoint_names.push_back(option_arg);
398 else
399 error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
400 option_arg.str().c_str());
401 break;
404 case 'R': {
405 lldb::addr_t tmp_offset_addr;
406 tmp_offset_addr = OptionArgParser::ToAddress(execution_context,
407 option_arg, 0, &error);
408 if (error.Success())
409 m_offset_addr = tmp_offset_addr;
410 } break;
412 case 'O':
413 m_exception_extra_args.AppendArgument("-O");
414 m_exception_extra_args.AppendArgument(option_arg);
415 break;
417 case 'p':
418 m_source_text_regexp.assign(option_arg);
419 break;
421 case 'r':
422 m_func_regexp.assign(option_arg);
423 break;
425 case 's':
426 m_modules.AppendIfUnique(FileSpec(option_arg));
427 break;
429 case 'S':
430 m_func_names.push_back(option_arg);
431 m_func_name_type_mask |= eFunctionNameTypeSelector;
432 break;
434 case 'w': {
435 bool success;
436 m_throw_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
437 if (!success)
438 error.SetErrorStringWithFormat(
439 "Invalid boolean value for on-throw option: '%s'",
440 option_arg.str().c_str());
441 } break;
443 case 'X':
444 m_source_regex_func_names.insert(option_arg);
445 break;
447 default:
448 llvm_unreachable("Unimplemented option");
451 return error;
454 void OptionParsingStarting(ExecutionContext *execution_context) override {
455 m_filenames.Clear();
456 m_line_num = 0;
457 m_column = 0;
458 m_func_names.clear();
459 m_func_name_type_mask = eFunctionNameTypeNone;
460 m_func_regexp.clear();
461 m_source_text_regexp.clear();
462 m_modules.Clear();
463 m_load_addr = LLDB_INVALID_ADDRESS;
464 m_offset_addr = 0;
465 m_catch_bp = false;
466 m_throw_bp = true;
467 m_hardware = false;
468 m_exception_language = eLanguageTypeUnknown;
469 m_language = lldb::eLanguageTypeUnknown;
470 m_skip_prologue = eLazyBoolCalculate;
471 m_breakpoint_names.clear();
472 m_all_files = false;
473 m_exception_extra_args.Clear();
474 m_move_to_nearest_code = eLazyBoolCalculate;
475 m_source_regex_func_names.clear();
476 m_current_key.clear();
479 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
480 return llvm::makeArrayRef(g_breakpoint_set_options);
483 // Instance variables to hold the values for command options.
485 std::string m_condition;
486 FileSpecList m_filenames;
487 uint32_t m_line_num;
488 uint32_t m_column;
489 std::vector<std::string> m_func_names;
490 std::vector<std::string> m_breakpoint_names;
491 lldb::FunctionNameType m_func_name_type_mask;
492 std::string m_func_regexp;
493 std::string m_source_text_regexp;
494 FileSpecList m_modules;
495 lldb::addr_t m_load_addr;
496 lldb::addr_t m_offset_addr;
497 bool m_catch_bp;
498 bool m_throw_bp;
499 bool m_hardware; // Request to use hardware breakpoints
500 lldb::LanguageType m_exception_language;
501 lldb::LanguageType m_language;
502 LazyBool m_skip_prologue;
503 bool m_all_files;
504 Args m_exception_extra_args;
505 LazyBool m_move_to_nearest_code;
506 std::unordered_set<std::string> m_source_regex_func_names;
507 std::string m_current_key;
510 protected:
511 bool DoExecute(Args &command, CommandReturnObject &result) override {
512 Target &target = GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy);
514 // The following are the various types of breakpoints that could be set:
515 // 1). -f -l -p [-s -g] (setting breakpoint by source location)
516 // 2). -a [-s -g] (setting breakpoint by address)
517 // 3). -n [-s -g] (setting breakpoint by function name)
518 // 4). -r [-s -g] (setting breakpoint by function name regular
519 // expression)
520 // 5). -p -f (setting a breakpoint by comparing a reg-exp
521 // to source text)
522 // 6). -E [-w -h] (setting a breakpoint for exceptions for a
523 // given language.)
525 BreakpointSetType break_type = eSetTypeInvalid;
527 if (!m_python_class_options.GetName().empty())
528 break_type = eSetTypeScripted;
529 else if (m_options.m_line_num != 0)
530 break_type = eSetTypeFileAndLine;
531 else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
532 break_type = eSetTypeAddress;
533 else if (!m_options.m_func_names.empty())
534 break_type = eSetTypeFunctionName;
535 else if (!m_options.m_func_regexp.empty())
536 break_type = eSetTypeFunctionRegexp;
537 else if (!m_options.m_source_text_regexp.empty())
538 break_type = eSetTypeSourceRegexp;
539 else if (m_options.m_exception_language != eLanguageTypeUnknown)
540 break_type = eSetTypeException;
542 BreakpointSP bp_sp = nullptr;
543 FileSpec module_spec;
544 const bool internal = false;
546 // If the user didn't specify skip-prologue, having an offset should turn
547 // that off.
548 if (m_options.m_offset_addr != 0 &&
549 m_options.m_skip_prologue == eLazyBoolCalculate)
550 m_options.m_skip_prologue = eLazyBoolNo;
552 switch (break_type) {
553 case eSetTypeFileAndLine: // Breakpoint by source position
555 FileSpec file;
556 const size_t num_files = m_options.m_filenames.GetSize();
557 if (num_files == 0) {
558 if (!GetDefaultFile(target, file, result)) {
559 result.AppendError("No file supplied and no default file available.");
560 result.SetStatus(eReturnStatusFailed);
561 return false;
563 } else if (num_files > 1) {
564 result.AppendError("Only one file at a time is allowed for file and "
565 "line breakpoints.");
566 result.SetStatus(eReturnStatusFailed);
567 return false;
568 } else
569 file = m_options.m_filenames.GetFileSpecAtIndex(0);
571 // Only check for inline functions if
572 LazyBool check_inlines = eLazyBoolCalculate;
574 bp_sp = target.CreateBreakpoint(
575 &(m_options.m_modules), file, m_options.m_line_num,
576 m_options.m_column, m_options.m_offset_addr, check_inlines,
577 m_options.m_skip_prologue, internal, m_options.m_hardware,
578 m_options.m_move_to_nearest_code);
579 } break;
581 case eSetTypeAddress: // Breakpoint by address
583 // If a shared library has been specified, make an lldb_private::Address
584 // with the library, and use that. That way the address breakpoint
585 // will track the load location of the library.
586 size_t num_modules_specified = m_options.m_modules.GetSize();
587 if (num_modules_specified == 1) {
588 const FileSpec *file_spec =
589 m_options.m_modules.GetFileSpecPointerAtIndex(0);
590 bp_sp = target.CreateAddressInModuleBreakpoint(
591 m_options.m_load_addr, internal, file_spec, m_options.m_hardware);
592 } else if (num_modules_specified == 0) {
593 bp_sp = target.CreateBreakpoint(m_options.m_load_addr, internal,
594 m_options.m_hardware);
595 } else {
596 result.AppendError("Only one shared library can be specified for "
597 "address breakpoints.");
598 result.SetStatus(eReturnStatusFailed);
599 return false;
601 break;
603 case eSetTypeFunctionName: // Breakpoint by function name
605 FunctionNameType name_type_mask = m_options.m_func_name_type_mask;
607 if (name_type_mask == 0)
608 name_type_mask = eFunctionNameTypeAuto;
610 bp_sp = target.CreateBreakpoint(
611 &(m_options.m_modules), &(m_options.m_filenames),
612 m_options.m_func_names, name_type_mask, m_options.m_language,
613 m_options.m_offset_addr, m_options.m_skip_prologue, internal,
614 m_options.m_hardware);
615 } break;
617 case eSetTypeFunctionRegexp: // Breakpoint by regular expression function
618 // name
620 RegularExpression regexp(m_options.m_func_regexp);
621 if (llvm::Error err = regexp.GetError()) {
622 result.AppendErrorWithFormat(
623 "Function name regular expression could not be compiled: \"%s\"",
624 llvm::toString(std::move(err)).c_str());
625 result.SetStatus(eReturnStatusFailed);
626 return false;
629 bp_sp = target.CreateFuncRegexBreakpoint(
630 &(m_options.m_modules), &(m_options.m_filenames), std::move(regexp),
631 m_options.m_language, m_options.m_skip_prologue, internal,
632 m_options.m_hardware);
633 } break;
634 case eSetTypeSourceRegexp: // Breakpoint by regexp on source text.
636 const size_t num_files = m_options.m_filenames.GetSize();
638 if (num_files == 0 && !m_options.m_all_files) {
639 FileSpec file;
640 if (!GetDefaultFile(target, file, result)) {
641 result.AppendError(
642 "No files provided and could not find default file.");
643 result.SetStatus(eReturnStatusFailed);
644 return false;
645 } else {
646 m_options.m_filenames.Append(file);
650 RegularExpression regexp(m_options.m_source_text_regexp);
651 if (llvm::Error err = regexp.GetError()) {
652 result.AppendErrorWithFormat(
653 "Source text regular expression could not be compiled: \"%s\"",
654 llvm::toString(std::move(err)).c_str());
655 result.SetStatus(eReturnStatusFailed);
656 return false;
658 bp_sp = target.CreateSourceRegexBreakpoint(
659 &(m_options.m_modules), &(m_options.m_filenames),
660 m_options.m_source_regex_func_names, std::move(regexp), internal,
661 m_options.m_hardware, m_options.m_move_to_nearest_code);
662 } break;
663 case eSetTypeException: {
664 Status precond_error;
665 bp_sp = target.CreateExceptionBreakpoint(
666 m_options.m_exception_language, m_options.m_catch_bp,
667 m_options.m_throw_bp, internal, &m_options.m_exception_extra_args,
668 &precond_error);
669 if (precond_error.Fail()) {
670 result.AppendErrorWithFormat(
671 "Error setting extra exception arguments: %s",
672 precond_error.AsCString());
673 target.RemoveBreakpointByID(bp_sp->GetID());
674 result.SetStatus(eReturnStatusFailed);
675 return false;
677 } break;
678 case eSetTypeScripted: {
680 Status error;
681 bp_sp = target.CreateScriptedBreakpoint(
682 m_python_class_options.GetName().c_str(), &(m_options.m_modules),
683 &(m_options.m_filenames), false, m_options.m_hardware,
684 m_python_class_options.GetStructuredData(), &error);
685 if (error.Fail()) {
686 result.AppendErrorWithFormat(
687 "Error setting extra exception arguments: %s", error.AsCString());
688 target.RemoveBreakpointByID(bp_sp->GetID());
689 result.SetStatus(eReturnStatusFailed);
690 return false;
692 } break;
693 default:
694 break;
697 // Now set the various options that were passed in:
698 if (bp_sp) {
699 bp_sp->GetOptions()->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
701 if (!m_options.m_breakpoint_names.empty()) {
702 Status name_error;
703 for (auto name : m_options.m_breakpoint_names) {
704 target.AddNameToBreakpoint(bp_sp, name.c_str(), name_error);
705 if (name_error.Fail()) {
706 result.AppendErrorWithFormat("Invalid breakpoint name: %s",
707 name.c_str());
708 target.RemoveBreakpointByID(bp_sp->GetID());
709 result.SetStatus(eReturnStatusFailed);
710 return false;
716 if (bp_sp) {
717 Stream &output_stream = result.GetOutputStream();
718 const bool show_locations = false;
719 bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
720 show_locations);
721 if (&target == &GetDummyTarget())
722 output_stream.Printf("Breakpoint set in dummy target, will get copied "
723 "into future targets.\n");
724 else {
725 // Don't print out this warning for exception breakpoints. They can
726 // get set before the target is set, but we won't know how to actually
727 // set the breakpoint till we run.
728 if (bp_sp->GetNumLocations() == 0 && break_type != eSetTypeException) {
729 output_stream.Printf("WARNING: Unable to resolve breakpoint to any "
730 "actual locations.\n");
733 result.SetStatus(eReturnStatusSuccessFinishResult);
734 } else if (!bp_sp) {
735 result.AppendError("Breakpoint creation failed: No breakpoint created.");
736 result.SetStatus(eReturnStatusFailed);
739 return result.Succeeded();
742 private:
743 bool GetDefaultFile(Target &target, FileSpec &file,
744 CommandReturnObject &result) {
745 uint32_t default_line;
746 // First use the Source Manager's default file. Then use the current stack
747 // frame's file.
748 if (!target.GetSourceManager().GetDefaultFileAndLine(file, default_line)) {
749 StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
750 if (cur_frame == nullptr) {
751 result.AppendError(
752 "No selected frame to use to find the default file.");
753 result.SetStatus(eReturnStatusFailed);
754 return false;
755 } else if (!cur_frame->HasDebugInformation()) {
756 result.AppendError("Cannot use the selected frame to find the default "
757 "file, it has no debug info.");
758 result.SetStatus(eReturnStatusFailed);
759 return false;
760 } else {
761 const SymbolContext &sc =
762 cur_frame->GetSymbolContext(eSymbolContextLineEntry);
763 if (sc.line_entry.file) {
764 file = sc.line_entry.file;
765 } else {
766 result.AppendError("Can't find the file for the selected frame to "
767 "use as the default file.");
768 result.SetStatus(eReturnStatusFailed);
769 return false;
773 return true;
776 BreakpointOptionGroup m_bp_opts;
777 BreakpointDummyOptionGroup m_dummy_options;
778 OptionGroupPythonClassWithDict m_python_class_options;
779 CommandOptions m_options;
780 OptionGroupOptions m_all_options;
783 // CommandObjectBreakpointModify
784 #pragma mark Modify
786 class CommandObjectBreakpointModify : public CommandObjectParsed {
787 public:
788 CommandObjectBreakpointModify(CommandInterpreter &interpreter)
789 : CommandObjectParsed(interpreter, "breakpoint modify",
790 "Modify the options on a breakpoint or set of "
791 "breakpoints in the executable. "
792 "If no breakpoint is specified, acts on the last "
793 "created breakpoint. "
794 "With the exception of -e, -d and -i, passing an "
795 "empty argument clears the modification.",
796 nullptr),
797 m_options() {
798 CommandArgumentEntry arg;
799 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
800 eArgTypeBreakpointIDRange);
801 // Add the entry for the first argument for this command to the object's
802 // arguments vector.
803 m_arguments.push_back(arg);
805 m_options.Append(&m_bp_opts,
806 LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3,
807 LLDB_OPT_SET_ALL);
808 m_options.Append(&m_dummy_opts, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
809 m_options.Finalize();
812 ~CommandObjectBreakpointModify() override = default;
814 Options *GetOptions() override { return &m_options; }
816 protected:
817 bool DoExecute(Args &command, CommandReturnObject &result) override {
818 Target &target = GetSelectedOrDummyTarget(m_dummy_opts.m_use_dummy);
820 std::unique_lock<std::recursive_mutex> lock;
821 target.GetBreakpointList().GetListMutex(lock);
823 BreakpointIDList valid_bp_ids;
825 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
826 command, &target, result, &valid_bp_ids,
827 BreakpointName::Permissions::PermissionKinds::disablePerm);
829 if (result.Succeeded()) {
830 const size_t count = valid_bp_ids.GetSize();
831 for (size_t i = 0; i < count; ++i) {
832 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
834 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
835 Breakpoint *bp =
836 target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
837 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
838 BreakpointLocation *location =
839 bp->FindLocationByID(cur_bp_id.GetLocationID()).get();
840 if (location)
841 location->GetLocationOptions()->CopyOverSetOptions(
842 m_bp_opts.GetBreakpointOptions());
843 } else {
844 bp->GetOptions()->CopyOverSetOptions(
845 m_bp_opts.GetBreakpointOptions());
851 return result.Succeeded();
854 private:
855 BreakpointOptionGroup m_bp_opts;
856 BreakpointDummyOptionGroup m_dummy_opts;
857 OptionGroupOptions m_options;
860 // CommandObjectBreakpointEnable
861 #pragma mark Enable
863 class CommandObjectBreakpointEnable : public CommandObjectParsed {
864 public:
865 CommandObjectBreakpointEnable(CommandInterpreter &interpreter)
866 : CommandObjectParsed(interpreter, "enable",
867 "Enable the specified disabled breakpoint(s). If "
868 "no breakpoints are specified, enable all of them.",
869 nullptr) {
870 CommandArgumentEntry arg;
871 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
872 eArgTypeBreakpointIDRange);
873 // Add the entry for the first argument for this command to the object's
874 // arguments vector.
875 m_arguments.push_back(arg);
878 ~CommandObjectBreakpointEnable() override = default;
880 protected:
881 bool DoExecute(Args &command, CommandReturnObject &result) override {
882 Target &target = GetSelectedOrDummyTarget();
884 std::unique_lock<std::recursive_mutex> lock;
885 target.GetBreakpointList().GetListMutex(lock);
887 const BreakpointList &breakpoints = target.GetBreakpointList();
889 size_t num_breakpoints = breakpoints.GetSize();
891 if (num_breakpoints == 0) {
892 result.AppendError("No breakpoints exist to be enabled.");
893 result.SetStatus(eReturnStatusFailed);
894 return false;
897 if (command.empty()) {
898 // No breakpoint selected; enable all currently set breakpoints.
899 target.EnableAllowedBreakpoints();
900 result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64
901 " breakpoints)\n",
902 (uint64_t)num_breakpoints);
903 result.SetStatus(eReturnStatusSuccessFinishNoResult);
904 } else {
905 // Particular breakpoint selected; enable that breakpoint.
906 BreakpointIDList valid_bp_ids;
907 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
908 command, &target, result, &valid_bp_ids,
909 BreakpointName::Permissions::PermissionKinds::disablePerm);
911 if (result.Succeeded()) {
912 int enable_count = 0;
913 int loc_count = 0;
914 const size_t count = valid_bp_ids.GetSize();
915 for (size_t i = 0; i < count; ++i) {
916 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
918 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
919 Breakpoint *breakpoint =
920 target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
921 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
922 BreakpointLocation *location =
923 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
924 if (location) {
925 location->SetEnabled(true);
926 ++loc_count;
928 } else {
929 breakpoint->SetEnabled(true);
930 ++enable_count;
934 result.AppendMessageWithFormat("%d breakpoints enabled.\n",
935 enable_count + loc_count);
936 result.SetStatus(eReturnStatusSuccessFinishNoResult);
940 return result.Succeeded();
944 // CommandObjectBreakpointDisable
945 #pragma mark Disable
947 class CommandObjectBreakpointDisable : public CommandObjectParsed {
948 public:
949 CommandObjectBreakpointDisable(CommandInterpreter &interpreter)
950 : CommandObjectParsed(
951 interpreter, "breakpoint disable",
952 "Disable the specified breakpoint(s) without deleting "
953 "them. If none are specified, disable all "
954 "breakpoints.",
955 nullptr) {
956 SetHelpLong(
957 "Disable the specified breakpoint(s) without deleting them. \
958 If none are specified, disable all breakpoints."
962 "Note: disabling a breakpoint will cause none of its locations to be hit \
963 regardless of whether individual locations are enabled or disabled. After the sequence:"
966 (lldb) break disable 1
967 (lldb) break enable 1.1
969 execution will NOT stop at location 1.1. To achieve that, type:
971 (lldb) break disable 1.*
972 (lldb) break enable 1.1
975 "The first command disables all locations for breakpoint 1, \
976 the second re-enables the first location.");
978 CommandArgumentEntry arg;
979 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
980 eArgTypeBreakpointIDRange);
981 // Add the entry for the first argument for this command to the object's
982 // arguments vector.
983 m_arguments.push_back(arg);
986 ~CommandObjectBreakpointDisable() override = default;
988 protected:
989 bool DoExecute(Args &command, CommandReturnObject &result) override {
990 Target &target = GetSelectedOrDummyTarget();
991 std::unique_lock<std::recursive_mutex> lock;
992 target.GetBreakpointList().GetListMutex(lock);
994 const BreakpointList &breakpoints = target.GetBreakpointList();
995 size_t num_breakpoints = breakpoints.GetSize();
997 if (num_breakpoints == 0) {
998 result.AppendError("No breakpoints exist to be disabled.");
999 result.SetStatus(eReturnStatusFailed);
1000 return false;
1003 if (command.empty()) {
1004 // No breakpoint selected; disable all currently set breakpoints.
1005 target.DisableAllowedBreakpoints();
1006 result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu64
1007 " breakpoints)\n",
1008 (uint64_t)num_breakpoints);
1009 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1010 } else {
1011 // Particular breakpoint selected; disable that breakpoint.
1012 BreakpointIDList valid_bp_ids;
1014 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1015 command, &target, result, &valid_bp_ids,
1016 BreakpointName::Permissions::PermissionKinds::disablePerm);
1018 if (result.Succeeded()) {
1019 int disable_count = 0;
1020 int loc_count = 0;
1021 const size_t count = valid_bp_ids.GetSize();
1022 for (size_t i = 0; i < count; ++i) {
1023 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1025 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1026 Breakpoint *breakpoint =
1027 target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1028 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1029 BreakpointLocation *location =
1030 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1031 if (location) {
1032 location->SetEnabled(false);
1033 ++loc_count;
1035 } else {
1036 breakpoint->SetEnabled(false);
1037 ++disable_count;
1041 result.AppendMessageWithFormat("%d breakpoints disabled.\n",
1042 disable_count + loc_count);
1043 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1047 return result.Succeeded();
1051 // CommandObjectBreakpointList
1053 #pragma mark List::CommandOptions
1054 #define LLDB_OPTIONS_breakpoint_list
1055 #include "CommandOptions.inc"
1057 #pragma mark List
1059 class CommandObjectBreakpointList : public CommandObjectParsed {
1060 public:
1061 CommandObjectBreakpointList(CommandInterpreter &interpreter)
1062 : CommandObjectParsed(
1063 interpreter, "breakpoint list",
1064 "List some or all breakpoints at configurable levels of detail.",
1065 nullptr),
1066 m_options() {
1067 CommandArgumentEntry arg;
1068 CommandArgumentData bp_id_arg;
1070 // Define the first (and only) variant of this arg.
1071 bp_id_arg.arg_type = eArgTypeBreakpointID;
1072 bp_id_arg.arg_repetition = eArgRepeatOptional;
1074 // There is only one variant this argument could be; put it into the
1075 // argument entry.
1076 arg.push_back(bp_id_arg);
1078 // Push the data for the first argument into the m_arguments vector.
1079 m_arguments.push_back(arg);
1082 ~CommandObjectBreakpointList() override = default;
1084 Options *GetOptions() override { return &m_options; }
1086 class CommandOptions : public Options {
1087 public:
1088 CommandOptions()
1089 : Options(), m_level(lldb::eDescriptionLevelBrief), m_use_dummy(false) {
1092 ~CommandOptions() override = default;
1094 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1095 ExecutionContext *execution_context) override {
1096 Status error;
1097 const int short_option = m_getopt_table[option_idx].val;
1099 switch (short_option) {
1100 case 'b':
1101 m_level = lldb::eDescriptionLevelBrief;
1102 break;
1103 case 'D':
1104 m_use_dummy = true;
1105 break;
1106 case 'f':
1107 m_level = lldb::eDescriptionLevelFull;
1108 break;
1109 case 'v':
1110 m_level = lldb::eDescriptionLevelVerbose;
1111 break;
1112 case 'i':
1113 m_internal = true;
1114 break;
1115 default:
1116 llvm_unreachable("Unimplemented option");
1119 return error;
1122 void OptionParsingStarting(ExecutionContext *execution_context) override {
1123 m_level = lldb::eDescriptionLevelFull;
1124 m_internal = false;
1125 m_use_dummy = false;
1128 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1129 return llvm::makeArrayRef(g_breakpoint_list_options);
1132 // Instance variables to hold the values for command options.
1134 lldb::DescriptionLevel m_level;
1136 bool m_internal;
1137 bool m_use_dummy;
1140 protected:
1141 bool DoExecute(Args &command, CommandReturnObject &result) override {
1142 Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
1144 const BreakpointList &breakpoints =
1145 target.GetBreakpointList(m_options.m_internal);
1146 std::unique_lock<std::recursive_mutex> lock;
1147 target.GetBreakpointList(m_options.m_internal).GetListMutex(lock);
1149 size_t num_breakpoints = breakpoints.GetSize();
1151 if (num_breakpoints == 0) {
1152 result.AppendMessage("No breakpoints currently set.");
1153 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1154 return true;
1157 Stream &output_stream = result.GetOutputStream();
1159 if (command.empty()) {
1160 // No breakpoint selected; show info about all currently set breakpoints.
1161 result.AppendMessage("Current breakpoints:");
1162 for (size_t i = 0; i < num_breakpoints; ++i) {
1163 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get();
1164 if (breakpoint->AllowList())
1165 AddBreakpointDescription(&output_stream, breakpoint,
1166 m_options.m_level);
1168 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1169 } else {
1170 // Particular breakpoints selected; show info about that breakpoint.
1171 BreakpointIDList valid_bp_ids;
1172 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1173 command, &target, result, &valid_bp_ids,
1174 BreakpointName::Permissions::PermissionKinds::listPerm);
1176 if (result.Succeeded()) {
1177 for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) {
1178 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1179 Breakpoint *breakpoint =
1180 target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1181 AddBreakpointDescription(&output_stream, breakpoint,
1182 m_options.m_level);
1184 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1185 } else {
1186 result.AppendError("Invalid breakpoint ID.");
1187 result.SetStatus(eReturnStatusFailed);
1191 return result.Succeeded();
1194 private:
1195 CommandOptions m_options;
1198 // CommandObjectBreakpointClear
1199 #pragma mark Clear::CommandOptions
1201 #define LLDB_OPTIONS_breakpoint_clear
1202 #include "CommandOptions.inc"
1204 #pragma mark Clear
1206 class CommandObjectBreakpointClear : public CommandObjectParsed {
1207 public:
1208 enum BreakpointClearType { eClearTypeInvalid, eClearTypeFileAndLine };
1210 CommandObjectBreakpointClear(CommandInterpreter &interpreter)
1211 : CommandObjectParsed(interpreter, "breakpoint clear",
1212 "Delete or disable breakpoints matching the "
1213 "specified source file and line.",
1214 "breakpoint clear <cmd-options>"),
1215 m_options() {}
1217 ~CommandObjectBreakpointClear() override = default;
1219 Options *GetOptions() override { return &m_options; }
1221 class CommandOptions : public Options {
1222 public:
1223 CommandOptions() : Options(), m_filename(), m_line_num(0) {}
1225 ~CommandOptions() override = default;
1227 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1228 ExecutionContext *execution_context) override {
1229 Status error;
1230 const int short_option = m_getopt_table[option_idx].val;
1232 switch (short_option) {
1233 case 'f':
1234 m_filename.assign(option_arg);
1235 break;
1237 case 'l':
1238 option_arg.getAsInteger(0, m_line_num);
1239 break;
1241 default:
1242 llvm_unreachable("Unimplemented option");
1245 return error;
1248 void OptionParsingStarting(ExecutionContext *execution_context) override {
1249 m_filename.clear();
1250 m_line_num = 0;
1253 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1254 return llvm::makeArrayRef(g_breakpoint_clear_options);
1257 // Instance variables to hold the values for command options.
1259 std::string m_filename;
1260 uint32_t m_line_num;
1263 protected:
1264 bool DoExecute(Args &command, CommandReturnObject &result) override {
1265 Target &target = GetSelectedOrDummyTarget();
1267 // The following are the various types of breakpoints that could be
1268 // cleared:
1269 // 1). -f -l (clearing breakpoint by source location)
1271 BreakpointClearType break_type = eClearTypeInvalid;
1273 if (m_options.m_line_num != 0)
1274 break_type = eClearTypeFileAndLine;
1276 std::unique_lock<std::recursive_mutex> lock;
1277 target.GetBreakpointList().GetListMutex(lock);
1279 BreakpointList &breakpoints = target.GetBreakpointList();
1280 size_t num_breakpoints = breakpoints.GetSize();
1282 // Early return if there's no breakpoint at all.
1283 if (num_breakpoints == 0) {
1284 result.AppendError("Breakpoint clear: No breakpoint cleared.");
1285 result.SetStatus(eReturnStatusFailed);
1286 return result.Succeeded();
1289 // Find matching breakpoints and delete them.
1291 // First create a copy of all the IDs.
1292 std::vector<break_id_t> BreakIDs;
1293 for (size_t i = 0; i < num_breakpoints; ++i)
1294 BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID());
1296 int num_cleared = 0;
1297 StreamString ss;
1298 switch (break_type) {
1299 case eClearTypeFileAndLine: // Breakpoint by source position
1301 const ConstString filename(m_options.m_filename.c_str());
1302 BreakpointLocationCollection loc_coll;
1304 for (size_t i = 0; i < num_breakpoints; ++i) {
1305 Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get();
1307 if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) {
1308 // If the collection size is 0, it's a full match and we can just
1309 // remove the breakpoint.
1310 if (loc_coll.GetSize() == 0) {
1311 bp->GetDescription(&ss, lldb::eDescriptionLevelBrief);
1312 ss.EOL();
1313 target.RemoveBreakpointByID(bp->GetID());
1314 ++num_cleared;
1318 } break;
1320 default:
1321 break;
1324 if (num_cleared > 0) {
1325 Stream &output_stream = result.GetOutputStream();
1326 output_stream.Printf("%d breakpoints cleared:\n", num_cleared);
1327 output_stream << ss.GetString();
1328 output_stream.EOL();
1329 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1330 } else {
1331 result.AppendError("Breakpoint clear: No breakpoint cleared.");
1332 result.SetStatus(eReturnStatusFailed);
1335 return result.Succeeded();
1338 private:
1339 CommandOptions m_options;
1342 // CommandObjectBreakpointDelete
1343 #define LLDB_OPTIONS_breakpoint_delete
1344 #include "CommandOptions.inc"
1346 #pragma mark Delete
1348 class CommandObjectBreakpointDelete : public CommandObjectParsed {
1349 public:
1350 CommandObjectBreakpointDelete(CommandInterpreter &interpreter)
1351 : CommandObjectParsed(interpreter, "breakpoint delete",
1352 "Delete the specified breakpoint(s). If no "
1353 "breakpoints are specified, delete them all.",
1354 nullptr),
1355 m_options() {
1356 CommandArgumentEntry arg;
1357 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1358 eArgTypeBreakpointIDRange);
1359 // Add the entry for the first argument for this command to the object's
1360 // arguments vector.
1361 m_arguments.push_back(arg);
1364 ~CommandObjectBreakpointDelete() override = default;
1366 Options *GetOptions() override { return &m_options; }
1368 class CommandOptions : public Options {
1369 public:
1370 CommandOptions() : Options(), m_use_dummy(false), m_force(false) {}
1372 ~CommandOptions() override = default;
1374 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1375 ExecutionContext *execution_context) override {
1376 Status error;
1377 const int short_option = m_getopt_table[option_idx].val;
1379 switch (short_option) {
1380 case 'f':
1381 m_force = true;
1382 break;
1384 case 'D':
1385 m_use_dummy = true;
1386 break;
1388 default:
1389 llvm_unreachable("Unimplemented option");
1392 return error;
1395 void OptionParsingStarting(ExecutionContext *execution_context) override {
1396 m_use_dummy = false;
1397 m_force = false;
1400 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1401 return llvm::makeArrayRef(g_breakpoint_delete_options);
1404 // Instance variables to hold the values for command options.
1405 bool m_use_dummy;
1406 bool m_force;
1409 protected:
1410 bool DoExecute(Args &command, CommandReturnObject &result) override {
1411 Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
1413 std::unique_lock<std::recursive_mutex> lock;
1414 target.GetBreakpointList().GetListMutex(lock);
1416 const BreakpointList &breakpoints = target.GetBreakpointList();
1418 size_t num_breakpoints = breakpoints.GetSize();
1420 if (num_breakpoints == 0) {
1421 result.AppendError("No breakpoints exist to be deleted.");
1422 result.SetStatus(eReturnStatusFailed);
1423 return false;
1426 if (command.empty()) {
1427 if (!m_options.m_force &&
1428 !m_interpreter.Confirm(
1429 "About to delete all breakpoints, do you want to do that?",
1430 true)) {
1431 result.AppendMessage("Operation cancelled...");
1432 } else {
1433 target.RemoveAllowedBreakpoints();
1434 result.AppendMessageWithFormat(
1435 "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n",
1436 (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : "");
1438 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1439 } else {
1440 // Particular breakpoint selected; disable that breakpoint.
1441 BreakpointIDList valid_bp_ids;
1442 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1443 command, &target, result, &valid_bp_ids,
1444 BreakpointName::Permissions::PermissionKinds::deletePerm);
1446 if (result.Succeeded()) {
1447 int delete_count = 0;
1448 int disable_count = 0;
1449 const size_t count = valid_bp_ids.GetSize();
1450 for (size_t i = 0; i < count; ++i) {
1451 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1453 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1454 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1455 Breakpoint *breakpoint =
1456 target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1457 BreakpointLocation *location =
1458 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1459 // It makes no sense to try to delete individual locations, so we
1460 // disable them instead.
1461 if (location) {
1462 location->SetEnabled(false);
1463 ++disable_count;
1465 } else {
1466 target.RemoveBreakpointByID(cur_bp_id.GetBreakpointID());
1467 ++delete_count;
1471 result.AppendMessageWithFormat(
1472 "%d breakpoints deleted; %d breakpoint locations disabled.\n",
1473 delete_count, disable_count);
1474 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1477 return result.Succeeded();
1480 private:
1481 CommandOptions m_options;
1484 // CommandObjectBreakpointName
1485 #define LLDB_OPTIONS_breakpoint_name
1486 #include "CommandOptions.inc"
1488 class BreakpointNameOptionGroup : public OptionGroup {
1489 public:
1490 BreakpointNameOptionGroup()
1491 : OptionGroup(), m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) {
1494 ~BreakpointNameOptionGroup() override = default;
1496 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1497 return llvm::makeArrayRef(g_breakpoint_name_options);
1500 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1501 ExecutionContext *execution_context) override {
1502 Status error;
1503 const int short_option = g_breakpoint_name_options[option_idx].short_option;
1505 switch (short_option) {
1506 case 'N':
1507 if (BreakpointID::StringIsBreakpointName(option_arg, error) &&
1508 error.Success())
1509 m_name.SetValueFromString(option_arg);
1510 break;
1511 case 'B':
1512 if (m_breakpoint.SetValueFromString(option_arg).Fail())
1513 error.SetErrorStringWithFormat(
1514 "unrecognized value \"%s\" for breakpoint",
1515 option_arg.str().c_str());
1516 break;
1517 case 'D':
1518 if (m_use_dummy.SetValueFromString(option_arg).Fail())
1519 error.SetErrorStringWithFormat(
1520 "unrecognized value \"%s\" for use-dummy",
1521 option_arg.str().c_str());
1522 break;
1523 case 'H':
1524 m_help_string.SetValueFromString(option_arg);
1525 break;
1527 default:
1528 llvm_unreachable("Unimplemented option");
1530 return error;
1533 void OptionParsingStarting(ExecutionContext *execution_context) override {
1534 m_name.Clear();
1535 m_breakpoint.Clear();
1536 m_use_dummy.Clear();
1537 m_use_dummy.SetDefaultValue(false);
1538 m_help_string.Clear();
1541 OptionValueString m_name;
1542 OptionValueUInt64 m_breakpoint;
1543 OptionValueBoolean m_use_dummy;
1544 OptionValueString m_help_string;
1547 #define LLDB_OPTIONS_breakpoint_access
1548 #include "CommandOptions.inc"
1550 class BreakpointAccessOptionGroup : public OptionGroup {
1551 public:
1552 BreakpointAccessOptionGroup() : OptionGroup() {}
1554 ~BreakpointAccessOptionGroup() override = default;
1556 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1557 return llvm::makeArrayRef(g_breakpoint_access_options);
1559 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1560 ExecutionContext *execution_context) override {
1561 Status error;
1562 const int short_option =
1563 g_breakpoint_access_options[option_idx].short_option;
1565 switch (short_option) {
1566 case 'L': {
1567 bool value, success;
1568 value = OptionArgParser::ToBoolean(option_arg, false, &success);
1569 if (success) {
1570 m_permissions.SetAllowList(value);
1571 } else
1572 error.SetErrorStringWithFormat(
1573 "invalid boolean value '%s' passed for -L option",
1574 option_arg.str().c_str());
1575 } break;
1576 case 'A': {
1577 bool value, success;
1578 value = OptionArgParser::ToBoolean(option_arg, false, &success);
1579 if (success) {
1580 m_permissions.SetAllowDisable(value);
1581 } else
1582 error.SetErrorStringWithFormat(
1583 "invalid boolean value '%s' passed for -L option",
1584 option_arg.str().c_str());
1585 } break;
1586 case 'D': {
1587 bool value, success;
1588 value = OptionArgParser::ToBoolean(option_arg, false, &success);
1589 if (success) {
1590 m_permissions.SetAllowDelete(value);
1591 } else
1592 error.SetErrorStringWithFormat(
1593 "invalid boolean value '%s' passed for -L option",
1594 option_arg.str().c_str());
1595 } break;
1596 default:
1597 llvm_unreachable("Unimplemented option");
1600 return error;
1603 void OptionParsingStarting(ExecutionContext *execution_context) override {}
1605 const BreakpointName::Permissions &GetPermissions() const {
1606 return m_permissions;
1608 BreakpointName::Permissions m_permissions;
1611 class CommandObjectBreakpointNameConfigure : public CommandObjectParsed {
1612 public:
1613 CommandObjectBreakpointNameConfigure(CommandInterpreter &interpreter)
1614 : CommandObjectParsed(
1615 interpreter, "configure",
1616 "Configure the options for the breakpoint"
1617 " name provided. "
1618 "If you provide a breakpoint id, the options will be copied from "
1619 "the breakpoint, otherwise only the options specified will be set "
1620 "on the name.",
1621 "breakpoint name configure <command-options> "
1622 "<breakpoint-name-list>"),
1623 m_bp_opts(), m_option_group() {
1624 // Create the first variant for the first (and only) argument for this
1625 // command.
1626 CommandArgumentEntry arg1;
1627 CommandArgumentData id_arg;
1628 id_arg.arg_type = eArgTypeBreakpointName;
1629 id_arg.arg_repetition = eArgRepeatOptional;
1630 arg1.push_back(id_arg);
1631 m_arguments.push_back(arg1);
1633 m_option_group.Append(&m_bp_opts, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
1634 m_option_group.Append(&m_access_options, LLDB_OPT_SET_ALL,
1635 LLDB_OPT_SET_ALL);
1636 m_option_group.Append(&m_bp_id, LLDB_OPT_SET_2 | LLDB_OPT_SET_4,
1637 LLDB_OPT_SET_ALL);
1638 m_option_group.Finalize();
1641 ~CommandObjectBreakpointNameConfigure() override = default;
1643 Options *GetOptions() override { return &m_option_group; }
1645 protected:
1646 bool DoExecute(Args &command, CommandReturnObject &result) override {
1648 const size_t argc = command.GetArgumentCount();
1649 if (argc == 0) {
1650 result.AppendError("No names provided.");
1651 result.SetStatus(eReturnStatusFailed);
1652 return false;
1655 Target &target = GetSelectedOrDummyTarget(false);
1657 std::unique_lock<std::recursive_mutex> lock;
1658 target.GetBreakpointList().GetListMutex(lock);
1660 // Make a pass through first to see that all the names are legal.
1661 for (auto &entry : command.entries()) {
1662 Status error;
1663 if (!BreakpointID::StringIsBreakpointName(entry.ref(), error)) {
1664 result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s",
1665 entry.c_str(), error.AsCString());
1666 result.SetStatus(eReturnStatusFailed);
1667 return false;
1670 // Now configure them, we already pre-checked the names so we don't need to
1671 // check the error:
1672 BreakpointSP bp_sp;
1673 if (m_bp_id.m_breakpoint.OptionWasSet()) {
1674 lldb::break_id_t bp_id = m_bp_id.m_breakpoint.GetUInt64Value();
1675 bp_sp = target.GetBreakpointByID(bp_id);
1676 if (!bp_sp) {
1677 result.AppendErrorWithFormatv("Could not find specified breakpoint {0}",
1678 bp_id);
1679 result.SetStatus(eReturnStatusFailed);
1680 return false;
1684 Status error;
1685 for (auto &entry : command.entries()) {
1686 ConstString name(entry.c_str());
1687 BreakpointName *bp_name = target.FindBreakpointName(name, true, error);
1688 if (!bp_name)
1689 continue;
1690 if (m_bp_id.m_help_string.OptionWasSet())
1691 bp_name->SetHelp(m_bp_id.m_help_string.GetStringValue().str().c_str());
1693 if (bp_sp)
1694 target.ConfigureBreakpointName(*bp_name, *bp_sp->GetOptions(),
1695 m_access_options.GetPermissions());
1696 else
1697 target.ConfigureBreakpointName(*bp_name,
1698 m_bp_opts.GetBreakpointOptions(),
1699 m_access_options.GetPermissions());
1701 return true;
1704 private:
1705 BreakpointNameOptionGroup m_bp_id; // Only using the id part of this.
1706 BreakpointOptionGroup m_bp_opts;
1707 BreakpointAccessOptionGroup m_access_options;
1708 OptionGroupOptions m_option_group;
1711 class CommandObjectBreakpointNameAdd : public CommandObjectParsed {
1712 public:
1713 CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter)
1714 : CommandObjectParsed(
1715 interpreter, "add", "Add a name to the breakpoints provided.",
1716 "breakpoint name add <command-options> <breakpoint-id-list>"),
1717 m_name_options(), m_option_group() {
1718 // Create the first variant for the first (and only) argument for this
1719 // command.
1720 CommandArgumentEntry arg1;
1721 CommandArgumentData id_arg;
1722 id_arg.arg_type = eArgTypeBreakpointID;
1723 id_arg.arg_repetition = eArgRepeatOptional;
1724 arg1.push_back(id_arg);
1725 m_arguments.push_back(arg1);
1727 m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
1728 m_option_group.Finalize();
1731 ~CommandObjectBreakpointNameAdd() override = default;
1733 Options *GetOptions() override { return &m_option_group; }
1735 protected:
1736 bool DoExecute(Args &command, CommandReturnObject &result) override {
1737 if (!m_name_options.m_name.OptionWasSet()) {
1738 result.SetError("No name option provided.");
1739 return false;
1742 Target &target =
1743 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1745 std::unique_lock<std::recursive_mutex> lock;
1746 target.GetBreakpointList().GetListMutex(lock);
1748 const BreakpointList &breakpoints = target.GetBreakpointList();
1750 size_t num_breakpoints = breakpoints.GetSize();
1751 if (num_breakpoints == 0) {
1752 result.SetError("No breakpoints, cannot add names.");
1753 result.SetStatus(eReturnStatusFailed);
1754 return false;
1757 // Particular breakpoint selected; disable that breakpoint.
1758 BreakpointIDList valid_bp_ids;
1759 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
1760 command, &target, result, &valid_bp_ids,
1761 BreakpointName::Permissions::PermissionKinds::listPerm);
1763 if (result.Succeeded()) {
1764 if (valid_bp_ids.GetSize() == 0) {
1765 result.SetError("No breakpoints specified, cannot add names.");
1766 result.SetStatus(eReturnStatusFailed);
1767 return false;
1769 size_t num_valid_ids = valid_bp_ids.GetSize();
1770 const char *bp_name = m_name_options.m_name.GetCurrentValue();
1771 Status error; // This error reports illegal names, but we've already
1772 // checked that, so we don't need to check it again here.
1773 for (size_t index = 0; index < num_valid_ids; index++) {
1774 lldb::break_id_t bp_id =
1775 valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
1776 BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
1777 target.AddNameToBreakpoint(bp_sp, bp_name, error);
1781 return true;
1784 private:
1785 BreakpointNameOptionGroup m_name_options;
1786 OptionGroupOptions m_option_group;
1789 class CommandObjectBreakpointNameDelete : public CommandObjectParsed {
1790 public:
1791 CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter)
1792 : CommandObjectParsed(
1793 interpreter, "delete",
1794 "Delete a name from the breakpoints provided.",
1795 "breakpoint name delete <command-options> <breakpoint-id-list>"),
1796 m_name_options(), m_option_group() {
1797 // Create the first variant for the first (and only) argument for this
1798 // command.
1799 CommandArgumentEntry arg1;
1800 CommandArgumentData id_arg;
1801 id_arg.arg_type = eArgTypeBreakpointID;
1802 id_arg.arg_repetition = eArgRepeatOptional;
1803 arg1.push_back(id_arg);
1804 m_arguments.push_back(arg1);
1806 m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
1807 m_option_group.Finalize();
1810 ~CommandObjectBreakpointNameDelete() override = default;
1812 Options *GetOptions() override { return &m_option_group; }
1814 protected:
1815 bool DoExecute(Args &command, CommandReturnObject &result) override {
1816 if (!m_name_options.m_name.OptionWasSet()) {
1817 result.SetError("No name option provided.");
1818 return false;
1821 Target &target =
1822 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1824 std::unique_lock<std::recursive_mutex> lock;
1825 target.GetBreakpointList().GetListMutex(lock);
1827 const BreakpointList &breakpoints = target.GetBreakpointList();
1829 size_t num_breakpoints = breakpoints.GetSize();
1830 if (num_breakpoints == 0) {
1831 result.SetError("No breakpoints, cannot delete names.");
1832 result.SetStatus(eReturnStatusFailed);
1833 return false;
1836 // Particular breakpoint selected; disable that breakpoint.
1837 BreakpointIDList valid_bp_ids;
1838 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
1839 command, &target, result, &valid_bp_ids,
1840 BreakpointName::Permissions::PermissionKinds::deletePerm);
1842 if (result.Succeeded()) {
1843 if (valid_bp_ids.GetSize() == 0) {
1844 result.SetError("No breakpoints specified, cannot delete names.");
1845 result.SetStatus(eReturnStatusFailed);
1846 return false;
1848 ConstString bp_name(m_name_options.m_name.GetCurrentValue());
1849 size_t num_valid_ids = valid_bp_ids.GetSize();
1850 for (size_t index = 0; index < num_valid_ids; index++) {
1851 lldb::break_id_t bp_id =
1852 valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
1853 BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
1854 target.RemoveNameFromBreakpoint(bp_sp, bp_name);
1858 return true;
1861 private:
1862 BreakpointNameOptionGroup m_name_options;
1863 OptionGroupOptions m_option_group;
1866 class CommandObjectBreakpointNameList : public CommandObjectParsed {
1867 public:
1868 CommandObjectBreakpointNameList(CommandInterpreter &interpreter)
1869 : CommandObjectParsed(interpreter, "list",
1870 "List either the names for a breakpoint or info "
1871 "about a given name. With no arguments, lists all "
1872 "names",
1873 "breakpoint name list <command-options>"),
1874 m_name_options(), m_option_group() {
1875 m_option_group.Append(&m_name_options, LLDB_OPT_SET_3, LLDB_OPT_SET_ALL);
1876 m_option_group.Finalize();
1879 ~CommandObjectBreakpointNameList() override = default;
1881 Options *GetOptions() override { return &m_option_group; }
1883 protected:
1884 bool DoExecute(Args &command, CommandReturnObject &result) override {
1885 Target &target =
1886 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1888 std::vector<std::string> name_list;
1889 if (command.empty()) {
1890 target.GetBreakpointNames(name_list);
1891 } else {
1892 for (const Args::ArgEntry &arg : command) {
1893 name_list.push_back(arg.c_str());
1897 if (name_list.empty()) {
1898 result.AppendMessage("No breakpoint names found.");
1899 } else {
1900 for (const std::string &name_str : name_list) {
1901 const char *name = name_str.c_str();
1902 // First print out the options for the name:
1903 Status error;
1904 BreakpointName *bp_name =
1905 target.FindBreakpointName(ConstString(name), false, error);
1906 if (bp_name) {
1907 StreamString s;
1908 result.AppendMessageWithFormat("Name: %s\n", name);
1909 if (bp_name->GetDescription(&s, eDescriptionLevelFull)) {
1910 result.AppendMessage(s.GetString());
1913 std::unique_lock<std::recursive_mutex> lock;
1914 target.GetBreakpointList().GetListMutex(lock);
1916 BreakpointList &breakpoints = target.GetBreakpointList();
1917 bool any_set = false;
1918 for (BreakpointSP bp_sp : breakpoints.Breakpoints()) {
1919 if (bp_sp->MatchesName(name)) {
1920 StreamString s;
1921 any_set = true;
1922 bp_sp->GetDescription(&s, eDescriptionLevelBrief);
1923 s.EOL();
1924 result.AppendMessage(s.GetString());
1927 if (!any_set)
1928 result.AppendMessage("No breakpoints using this name.");
1929 } else {
1930 result.AppendMessageWithFormat("Name: %s not found.\n", name);
1934 return true;
1937 private:
1938 BreakpointNameOptionGroup m_name_options;
1939 OptionGroupOptions m_option_group;
1942 // CommandObjectBreakpointName
1943 class CommandObjectBreakpointName : public CommandObjectMultiword {
1944 public:
1945 CommandObjectBreakpointName(CommandInterpreter &interpreter)
1946 : CommandObjectMultiword(
1947 interpreter, "name", "Commands to manage name tags for breakpoints",
1948 "breakpoint name <subcommand> [<command-options>]") {
1949 CommandObjectSP add_command_object(
1950 new CommandObjectBreakpointNameAdd(interpreter));
1951 CommandObjectSP delete_command_object(
1952 new CommandObjectBreakpointNameDelete(interpreter));
1953 CommandObjectSP list_command_object(
1954 new CommandObjectBreakpointNameList(interpreter));
1955 CommandObjectSP configure_command_object(
1956 new CommandObjectBreakpointNameConfigure(interpreter));
1958 LoadSubCommand("add", add_command_object);
1959 LoadSubCommand("delete", delete_command_object);
1960 LoadSubCommand("list", list_command_object);
1961 LoadSubCommand("configure", configure_command_object);
1964 ~CommandObjectBreakpointName() override = default;
1967 // CommandObjectBreakpointRead
1968 #pragma mark Read::CommandOptions
1969 #define LLDB_OPTIONS_breakpoint_read
1970 #include "CommandOptions.inc"
1972 #pragma mark Read
1974 class CommandObjectBreakpointRead : public CommandObjectParsed {
1975 public:
1976 CommandObjectBreakpointRead(CommandInterpreter &interpreter)
1977 : CommandObjectParsed(interpreter, "breakpoint read",
1978 "Read and set the breakpoints previously saved to "
1979 "a file with \"breakpoint write\". ",
1980 nullptr),
1981 m_options() {
1982 CommandArgumentEntry arg;
1983 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1984 eArgTypeBreakpointIDRange);
1985 // Add the entry for the first argument for this command to the object's
1986 // arguments vector.
1987 m_arguments.push_back(arg);
1990 ~CommandObjectBreakpointRead() override = default;
1992 Options *GetOptions() override { return &m_options; }
1994 class CommandOptions : public Options {
1995 public:
1996 CommandOptions() : Options() {}
1998 ~CommandOptions() override = default;
2000 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2001 ExecutionContext *execution_context) override {
2002 Status error;
2003 const int short_option = m_getopt_table[option_idx].val;
2005 switch (short_option) {
2006 case 'f':
2007 m_filename.assign(option_arg);
2008 break;
2009 case 'N': {
2010 Status name_error;
2011 if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg),
2012 name_error)) {
2013 error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
2014 name_error.AsCString());
2016 m_names.push_back(option_arg);
2017 break;
2019 default:
2020 llvm_unreachable("Unimplemented option");
2023 return error;
2026 void OptionParsingStarting(ExecutionContext *execution_context) override {
2027 m_filename.clear();
2028 m_names.clear();
2031 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2032 return llvm::makeArrayRef(g_breakpoint_read_options);
2035 // Instance variables to hold the values for command options.
2037 std::string m_filename;
2038 std::vector<std::string> m_names;
2041 protected:
2042 bool DoExecute(Args &command, CommandReturnObject &result) override {
2043 Target &target = GetSelectedOrDummyTarget();
2045 std::unique_lock<std::recursive_mutex> lock;
2046 target.GetBreakpointList().GetListMutex(lock);
2048 FileSpec input_spec(m_options.m_filename);
2049 FileSystem::Instance().Resolve(input_spec);
2050 BreakpointIDList new_bps;
2051 Status error = target.CreateBreakpointsFromFile(input_spec,
2052 m_options.m_names, new_bps);
2054 if (!error.Success()) {
2055 result.AppendError(error.AsCString());
2056 result.SetStatus(eReturnStatusFailed);
2057 return false;
2060 Stream &output_stream = result.GetOutputStream();
2062 size_t num_breakpoints = new_bps.GetSize();
2063 if (num_breakpoints == 0) {
2064 result.AppendMessage("No breakpoints added.");
2065 } else {
2066 // No breakpoint selected; show info about all currently set breakpoints.
2067 result.AppendMessage("New breakpoints:");
2068 for (size_t i = 0; i < num_breakpoints; ++i) {
2069 BreakpointID bp_id = new_bps.GetBreakpointIDAtIndex(i);
2070 Breakpoint *bp = target.GetBreakpointList()
2071 .FindBreakpointByID(bp_id.GetBreakpointID())
2072 .get();
2073 if (bp)
2074 bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
2075 false);
2078 return result.Succeeded();
2081 private:
2082 CommandOptions m_options;
2085 // CommandObjectBreakpointWrite
2086 #pragma mark Write::CommandOptions
2087 #define LLDB_OPTIONS_breakpoint_write
2088 #include "CommandOptions.inc"
2090 #pragma mark Write
2091 class CommandObjectBreakpointWrite : public CommandObjectParsed {
2092 public:
2093 CommandObjectBreakpointWrite(CommandInterpreter &interpreter)
2094 : CommandObjectParsed(interpreter, "breakpoint write",
2095 "Write the breakpoints listed to a file that can "
2096 "be read in with \"breakpoint read\". "
2097 "If given no arguments, writes all breakpoints.",
2098 nullptr),
2099 m_options() {
2100 CommandArgumentEntry arg;
2101 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
2102 eArgTypeBreakpointIDRange);
2103 // Add the entry for the first argument for this command to the object's
2104 // arguments vector.
2105 m_arguments.push_back(arg);
2108 ~CommandObjectBreakpointWrite() override = default;
2110 Options *GetOptions() override { return &m_options; }
2112 class CommandOptions : public Options {
2113 public:
2114 CommandOptions() : Options() {}
2116 ~CommandOptions() override = default;
2118 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2119 ExecutionContext *execution_context) override {
2120 Status error;
2121 const int short_option = m_getopt_table[option_idx].val;
2123 switch (short_option) {
2124 case 'f':
2125 m_filename.assign(option_arg);
2126 break;
2127 case 'a':
2128 m_append = true;
2129 break;
2130 default:
2131 llvm_unreachable("Unimplemented option");
2134 return error;
2137 void OptionParsingStarting(ExecutionContext *execution_context) override {
2138 m_filename.clear();
2139 m_append = false;
2142 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2143 return llvm::makeArrayRef(g_breakpoint_write_options);
2146 // Instance variables to hold the values for command options.
2148 std::string m_filename;
2149 bool m_append = false;
2152 protected:
2153 bool DoExecute(Args &command, CommandReturnObject &result) override {
2154 Target &target = GetSelectedOrDummyTarget();
2156 std::unique_lock<std::recursive_mutex> lock;
2157 target.GetBreakpointList().GetListMutex(lock);
2159 BreakpointIDList valid_bp_ids;
2160 if (!command.empty()) {
2161 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
2162 command, &target, result, &valid_bp_ids,
2163 BreakpointName::Permissions::PermissionKinds::listPerm);
2165 if (!result.Succeeded()) {
2166 result.SetStatus(eReturnStatusFailed);
2167 return false;
2170 FileSpec file_spec(m_options.m_filename);
2171 FileSystem::Instance().Resolve(file_spec);
2172 Status error = target.SerializeBreakpointsToFile(file_spec, valid_bp_ids,
2173 m_options.m_append);
2174 if (!error.Success()) {
2175 result.AppendErrorWithFormat("error serializing breakpoints: %s.",
2176 error.AsCString());
2177 result.SetStatus(eReturnStatusFailed);
2179 return result.Succeeded();
2182 private:
2183 CommandOptions m_options;
2186 // CommandObjectMultiwordBreakpoint
2187 #pragma mark MultiwordBreakpoint
2189 CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
2190 CommandInterpreter &interpreter)
2191 : CommandObjectMultiword(
2192 interpreter, "breakpoint",
2193 "Commands for operating on breakpoints (see 'help b' for shorthand.)",
2194 "breakpoint <subcommand> [<command-options>]") {
2195 CommandObjectSP list_command_object(
2196 new CommandObjectBreakpointList(interpreter));
2197 CommandObjectSP enable_command_object(
2198 new CommandObjectBreakpointEnable(interpreter));
2199 CommandObjectSP disable_command_object(
2200 new CommandObjectBreakpointDisable(interpreter));
2201 CommandObjectSP clear_command_object(
2202 new CommandObjectBreakpointClear(interpreter));
2203 CommandObjectSP delete_command_object(
2204 new CommandObjectBreakpointDelete(interpreter));
2205 CommandObjectSP set_command_object(
2206 new CommandObjectBreakpointSet(interpreter));
2207 CommandObjectSP command_command_object(
2208 new CommandObjectBreakpointCommand(interpreter));
2209 CommandObjectSP modify_command_object(
2210 new CommandObjectBreakpointModify(interpreter));
2211 CommandObjectSP name_command_object(
2212 new CommandObjectBreakpointName(interpreter));
2213 CommandObjectSP write_command_object(
2214 new CommandObjectBreakpointWrite(interpreter));
2215 CommandObjectSP read_command_object(
2216 new CommandObjectBreakpointRead(interpreter));
2218 list_command_object->SetCommandName("breakpoint list");
2219 enable_command_object->SetCommandName("breakpoint enable");
2220 disable_command_object->SetCommandName("breakpoint disable");
2221 clear_command_object->SetCommandName("breakpoint clear");
2222 delete_command_object->SetCommandName("breakpoint delete");
2223 set_command_object->SetCommandName("breakpoint set");
2224 command_command_object->SetCommandName("breakpoint command");
2225 modify_command_object->SetCommandName("breakpoint modify");
2226 name_command_object->SetCommandName("breakpoint name");
2227 write_command_object->SetCommandName("breakpoint write");
2228 read_command_object->SetCommandName("breakpoint read");
2230 LoadSubCommand("list", list_command_object);
2231 LoadSubCommand("enable", enable_command_object);
2232 LoadSubCommand("disable", disable_command_object);
2233 LoadSubCommand("clear", clear_command_object);
2234 LoadSubCommand("delete", delete_command_object);
2235 LoadSubCommand("set", set_command_object);
2236 LoadSubCommand("command", command_command_object);
2237 LoadSubCommand("modify", modify_command_object);
2238 LoadSubCommand("name", name_command_object);
2239 LoadSubCommand("write", write_command_object);
2240 LoadSubCommand("read", read_command_object);
2243 CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default;
2245 void CommandObjectMultiwordBreakpoint::VerifyIDs(
2246 Args &args, Target *target, bool allow_locations,
2247 CommandReturnObject &result, BreakpointIDList *valid_ids,
2248 BreakpointName::Permissions ::PermissionKinds purpose) {
2249 // args can be strings representing 1). integers (for breakpoint ids)
2250 // 2). the full breakpoint & location
2251 // canonical representation
2252 // 3). the word "to" or a hyphen,
2253 // representing a range (in which case there
2254 // had *better* be an entry both before &
2255 // after of one of the first two types.
2256 // 4). A breakpoint name
2257 // If args is empty, we will use the last created breakpoint (if there is
2258 // one.)
2260 Args temp_args;
2262 if (args.empty()) {
2263 if (target->GetLastCreatedBreakpoint()) {
2264 valid_ids->AddBreakpointID(BreakpointID(
2265 target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID));
2266 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2267 } else {
2268 result.AppendError(
2269 "No breakpoint specified and no last created breakpoint.");
2270 result.SetStatus(eReturnStatusFailed);
2272 return;
2275 // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff
2276 // directly from the old ARGS to the new TEMP_ARGS. Do not copy breakpoint
2277 // id range strings over; instead generate a list of strings for all the
2278 // breakpoint ids in the range, and shove all of those breakpoint id strings
2279 // into TEMP_ARGS.
2281 BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations,
2282 purpose, result, temp_args);
2284 // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual
2285 // BreakpointIDList:
2287 valid_ids->InsertStringArray(temp_args.GetArgumentArrayRef(), result);
2289 // At this point, all of the breakpoint ids that the user passed in have
2290 // been converted to breakpoint IDs and put into valid_ids.
2292 if (result.Succeeded()) {
2293 // Now that we've converted everything from args into a list of breakpoint
2294 // ids, go through our tentative list of breakpoint id's and verify that
2295 // they correspond to valid/currently set breakpoints.
2297 const size_t count = valid_ids->GetSize();
2298 for (size_t i = 0; i < count; ++i) {
2299 BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex(i);
2300 Breakpoint *breakpoint =
2301 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
2302 if (breakpoint != nullptr) {
2303 const size_t num_locations = breakpoint->GetNumLocations();
2304 if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) {
2305 StreamString id_str;
2306 BreakpointID::GetCanonicalReference(
2307 &id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
2308 i = valid_ids->GetSize() + 1;
2309 result.AppendErrorWithFormat(
2310 "'%s' is not a currently valid breakpoint/location id.\n",
2311 id_str.GetData());
2312 result.SetStatus(eReturnStatusFailed);
2314 } else {
2315 i = valid_ids->GetSize() + 1;
2316 result.AppendErrorWithFormat(
2317 "'%d' is not a currently valid breakpoint ID.\n",
2318 cur_bp_id.GetBreakpointID());
2319 result.SetStatus(eReturnStatusFailed);