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