Path: blob/main/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpoint.cpp
39587 views
//===-- CommandObjectBreakpoint.cpp ---------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "CommandObjectBreakpoint.h"9#include "CommandObjectBreakpointCommand.h"10#include "lldb/Breakpoint/Breakpoint.h"11#include "lldb/Breakpoint/BreakpointIDList.h"12#include "lldb/Breakpoint/BreakpointLocation.h"13#include "lldb/Host/OptionParser.h"14#include "lldb/Interpreter/CommandInterpreter.h"15#include "lldb/Interpreter/CommandOptionArgumentTable.h"16#include "lldb/Interpreter/CommandReturnObject.h"17#include "lldb/Interpreter/OptionArgParser.h"18#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"19#include "lldb/Interpreter/OptionValueBoolean.h"20#include "lldb/Interpreter/OptionValueFileColonLine.h"21#include "lldb/Interpreter/OptionValueString.h"22#include "lldb/Interpreter/OptionValueUInt64.h"23#include "lldb/Interpreter/Options.h"24#include "lldb/Target/Language.h"25#include "lldb/Target/StackFrame.h"26#include "lldb/Target/Target.h"27#include "lldb/Target/ThreadSpec.h"28#include "lldb/Utility/RegularExpression.h"29#include "lldb/Utility/StreamString.h"3031#include <memory>32#include <optional>33#include <vector>3435using namespace lldb;36using namespace lldb_private;3738static void AddBreakpointDescription(Stream *s, Breakpoint *bp,39lldb::DescriptionLevel level) {40s->IndentMore();41bp->GetDescription(s, level, true);42s->IndentLess();43s->EOL();44}4546// Modifiable Breakpoint Options47#pragma mark Modify::CommandOptions48#define LLDB_OPTIONS_breakpoint_modify49#include "CommandOptions.inc"5051class lldb_private::BreakpointOptionGroup : public OptionGroup {52public:53BreakpointOptionGroup() : m_bp_opts(false) {}5455~BreakpointOptionGroup() override = default;5657llvm::ArrayRef<OptionDefinition> GetDefinitions() override {58return llvm::ArrayRef(g_breakpoint_modify_options);59}6061Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,62ExecutionContext *execution_context) override {63Status error;64const int short_option =65g_breakpoint_modify_options[option_idx].short_option;66const char *long_option =67g_breakpoint_modify_options[option_idx].long_option;6869switch (short_option) {70case 'c':71// Normally an empty breakpoint condition marks is as unset. But we need72// to say it was passed in.73m_bp_opts.SetCondition(option_arg.str().c_str());74m_bp_opts.m_set_flags.Set(BreakpointOptions::eCondition);75break;76case 'C':77m_commands.push_back(std::string(option_arg));78break;79case 'd':80m_bp_opts.SetEnabled(false);81break;82case 'e':83m_bp_opts.SetEnabled(true);84break;85case 'G': {86bool value, success;87value = OptionArgParser::ToBoolean(option_arg, false, &success);88if (success)89m_bp_opts.SetAutoContinue(value);90else91error = CreateOptionParsingError(option_arg, short_option, long_option,92g_bool_parsing_error_message);93} break;94case 'i': {95uint32_t ignore_count;96if (option_arg.getAsInteger(0, ignore_count))97error = CreateOptionParsingError(option_arg, short_option, long_option,98g_int_parsing_error_message);99else100m_bp_opts.SetIgnoreCount(ignore_count);101} break;102case 'o': {103bool value, success;104value = OptionArgParser::ToBoolean(option_arg, false, &success);105if (success) {106m_bp_opts.SetOneShot(value);107} else108error = CreateOptionParsingError(option_arg, short_option, long_option,109g_bool_parsing_error_message);110} break;111case 't': {112lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID;113if (option_arg == "current") {114if (!execution_context) {115error = CreateOptionParsingError(116option_arg, short_option, long_option,117"No context to determine current thread");118} else {119ThreadSP ctx_thread_sp = execution_context->GetThreadSP();120if (!ctx_thread_sp || !ctx_thread_sp->IsValid()) {121error =122CreateOptionParsingError(option_arg, short_option, long_option,123"No currently selected thread");124} else {125thread_id = ctx_thread_sp->GetID();126}127}128} else if (option_arg.getAsInteger(0, thread_id)) {129error = CreateOptionParsingError(option_arg, short_option, long_option,130g_int_parsing_error_message);131}132if (thread_id != LLDB_INVALID_THREAD_ID)133m_bp_opts.SetThreadID(thread_id);134} break;135case 'T':136m_bp_opts.GetThreadSpec()->SetName(option_arg.str().c_str());137break;138case 'q':139m_bp_opts.GetThreadSpec()->SetQueueName(option_arg.str().c_str());140break;141case 'x': {142uint32_t thread_index = UINT32_MAX;143if (option_arg.getAsInteger(0, thread_index)) {144error = CreateOptionParsingError(option_arg, short_option, long_option,145g_int_parsing_error_message);146} else {147m_bp_opts.GetThreadSpec()->SetIndex(thread_index);148}149} break;150default:151llvm_unreachable("Unimplemented option");152}153154return error;155}156157void OptionParsingStarting(ExecutionContext *execution_context) override {158m_bp_opts.Clear();159m_commands.clear();160}161162Status OptionParsingFinished(ExecutionContext *execution_context) override {163if (!m_commands.empty()) {164auto cmd_data = std::make_unique<BreakpointOptions::CommandData>();165166for (std::string &str : m_commands)167cmd_data->user_source.AppendString(str);168169cmd_data->stop_on_error = true;170m_bp_opts.SetCommandDataCallback(cmd_data);171}172return Status();173}174175const BreakpointOptions &GetBreakpointOptions() { return m_bp_opts; }176177std::vector<std::string> m_commands;178BreakpointOptions m_bp_opts;179};180181#define LLDB_OPTIONS_breakpoint_dummy182#include "CommandOptions.inc"183184class BreakpointDummyOptionGroup : public OptionGroup {185public:186BreakpointDummyOptionGroup() = default;187188~BreakpointDummyOptionGroup() override = default;189190llvm::ArrayRef<OptionDefinition> GetDefinitions() override {191return llvm::ArrayRef(g_breakpoint_dummy_options);192}193194Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,195ExecutionContext *execution_context) override {196Status error;197const int short_option =198g_breakpoint_dummy_options[option_idx].short_option;199200switch (short_option) {201case 'D':202m_use_dummy = true;203break;204default:205llvm_unreachable("Unimplemented option");206}207208return error;209}210211void OptionParsingStarting(ExecutionContext *execution_context) override {212m_use_dummy = false;213}214215bool m_use_dummy;216};217218#define LLDB_OPTIONS_breakpoint_set219#include "CommandOptions.inc"220221// CommandObjectBreakpointSet222223class CommandObjectBreakpointSet : public CommandObjectParsed {224public:225enum BreakpointSetType {226eSetTypeInvalid,227eSetTypeFileAndLine,228eSetTypeAddress,229eSetTypeFunctionName,230eSetTypeFunctionRegexp,231eSetTypeSourceRegexp,232eSetTypeException,233eSetTypeScripted,234};235236CommandObjectBreakpointSet(CommandInterpreter &interpreter)237: CommandObjectParsed(238interpreter, "breakpoint set",239"Sets a breakpoint or set of breakpoints in the executable.",240"breakpoint set <cmd-options>"),241m_python_class_options("scripted breakpoint", true, 'P') {242// We're picking up all the normal options, commands and disable.243m_all_options.Append(&m_python_class_options,244LLDB_OPT_SET_1 | LLDB_OPT_SET_2, LLDB_OPT_SET_11);245m_all_options.Append(&m_bp_opts,246LLDB_OPT_SET_1 | LLDB_OPT_SET_3 | LLDB_OPT_SET_4,247LLDB_OPT_SET_ALL);248m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);249m_all_options.Append(&m_options);250m_all_options.Finalize();251}252253~CommandObjectBreakpointSet() override = default;254255Options *GetOptions() override { return &m_all_options; }256257class CommandOptions : public OptionGroup {258public:259CommandOptions() = default;260261~CommandOptions() override = default;262263Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,264ExecutionContext *execution_context) override {265Status error;266const int short_option =267g_breakpoint_set_options[option_idx].short_option;268const char *long_option =269g_breakpoint_set_options[option_idx].long_option;270271switch (short_option) {272case 'a': {273m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg,274LLDB_INVALID_ADDRESS, &error);275} break;276277case 'A':278m_all_files = true;279break;280281case 'b':282m_func_names.push_back(std::string(option_arg));283m_func_name_type_mask |= eFunctionNameTypeBase;284break;285286case 'u':287if (option_arg.getAsInteger(0, m_column))288error =289CreateOptionParsingError(option_arg, short_option, long_option,290g_int_parsing_error_message);291break;292293case 'E': {294LanguageType language = Language::GetLanguageTypeFromString(option_arg);295296llvm::StringRef error_context;297switch (language) {298case eLanguageTypeC89:299case eLanguageTypeC:300case eLanguageTypeC99:301case eLanguageTypeC11:302m_exception_language = eLanguageTypeC;303break;304case eLanguageTypeC_plus_plus:305case eLanguageTypeC_plus_plus_03:306case eLanguageTypeC_plus_plus_11:307case eLanguageTypeC_plus_plus_14:308m_exception_language = eLanguageTypeC_plus_plus;309break;310case eLanguageTypeObjC_plus_plus:311error_context =312"Set exception breakpoints separately for c++ and objective-c";313break;314case eLanguageTypeUnknown:315error_context = "Unknown language type for exception breakpoint";316break;317default:318if (Language *languagePlugin = Language::FindPlugin(language)) {319if (languagePlugin->SupportsExceptionBreakpointsOnThrow() ||320languagePlugin->SupportsExceptionBreakpointsOnCatch()) {321m_exception_language = language;322break;323}324}325error_context = "Unsupported language type for exception breakpoint";326}327if (!error_context.empty())328error = CreateOptionParsingError(option_arg, short_option,329long_option, error_context);330} break;331332case 'f':333m_filenames.AppendIfUnique(FileSpec(option_arg));334break;335336case 'F':337m_func_names.push_back(std::string(option_arg));338m_func_name_type_mask |= eFunctionNameTypeFull;339break;340341case 'h': {342bool success;343m_catch_bp = OptionArgParser::ToBoolean(option_arg, true, &success);344if (!success)345error =346CreateOptionParsingError(option_arg, short_option, long_option,347g_bool_parsing_error_message);348} break;349350case 'H':351m_hardware = true;352break;353354case 'K': {355bool success;356bool value;357value = OptionArgParser::ToBoolean(option_arg, true, &success);358if (value)359m_skip_prologue = eLazyBoolYes;360else361m_skip_prologue = eLazyBoolNo;362363if (!success)364error =365CreateOptionParsingError(option_arg, short_option, long_option,366g_bool_parsing_error_message);367} break;368369case 'l':370if (option_arg.getAsInteger(0, m_line_num))371error =372CreateOptionParsingError(option_arg, short_option, long_option,373g_int_parsing_error_message);374break;375376case 'L':377m_language = Language::GetLanguageTypeFromString(option_arg);378if (m_language == eLanguageTypeUnknown)379error =380CreateOptionParsingError(option_arg, short_option, long_option,381g_language_parsing_error_message);382break;383384case 'm': {385bool success;386bool value;387value = OptionArgParser::ToBoolean(option_arg, true, &success);388if (value)389m_move_to_nearest_code = eLazyBoolYes;390else391m_move_to_nearest_code = eLazyBoolNo;392393if (!success)394error =395CreateOptionParsingError(option_arg, short_option, long_option,396g_bool_parsing_error_message);397break;398}399400case 'M':401m_func_names.push_back(std::string(option_arg));402m_func_name_type_mask |= eFunctionNameTypeMethod;403break;404405case 'n':406m_func_names.push_back(std::string(option_arg));407m_func_name_type_mask |= eFunctionNameTypeAuto;408break;409410case 'N': {411if (BreakpointID::StringIsBreakpointName(option_arg, error))412m_breakpoint_names.push_back(std::string(option_arg));413else414error = CreateOptionParsingError(415option_arg, short_option, long_option, "Invalid breakpoint name");416break;417}418419case 'R': {420lldb::addr_t tmp_offset_addr;421tmp_offset_addr = OptionArgParser::ToAddress(execution_context,422option_arg, 0, &error);423if (error.Success())424m_offset_addr = tmp_offset_addr;425} break;426427case 'O':428m_exception_extra_args.AppendArgument("-O");429m_exception_extra_args.AppendArgument(option_arg);430break;431432case 'p':433m_source_text_regexp.assign(std::string(option_arg));434break;435436case 'r':437m_func_regexp.assign(std::string(option_arg));438break;439440case 's':441m_modules.AppendIfUnique(FileSpec(option_arg));442break;443444case 'S':445m_func_names.push_back(std::string(option_arg));446m_func_name_type_mask |= eFunctionNameTypeSelector;447break;448449case 'w': {450bool success;451m_throw_bp = OptionArgParser::ToBoolean(option_arg, true, &success);452if (!success)453error =454CreateOptionParsingError(option_arg, short_option, long_option,455g_bool_parsing_error_message);456} break;457458case 'X':459m_source_regex_func_names.insert(std::string(option_arg));460break;461462case 'y':463{464OptionValueFileColonLine value;465Status fcl_err = value.SetValueFromString(option_arg);466if (!fcl_err.Success()) {467error = CreateOptionParsingError(option_arg, short_option,468long_option, fcl_err.AsCString());469} else {470m_filenames.AppendIfUnique(value.GetFileSpec());471m_line_num = value.GetLineNumber();472m_column = value.GetColumnNumber();473}474} break;475476default:477llvm_unreachable("Unimplemented option");478}479480return error;481}482483void OptionParsingStarting(ExecutionContext *execution_context) override {484m_filenames.Clear();485m_line_num = 0;486m_column = 0;487m_func_names.clear();488m_func_name_type_mask = eFunctionNameTypeNone;489m_func_regexp.clear();490m_source_text_regexp.clear();491m_modules.Clear();492m_load_addr = LLDB_INVALID_ADDRESS;493m_offset_addr = 0;494m_catch_bp = false;495m_throw_bp = true;496m_hardware = false;497m_exception_language = eLanguageTypeUnknown;498m_language = lldb::eLanguageTypeUnknown;499m_skip_prologue = eLazyBoolCalculate;500m_breakpoint_names.clear();501m_all_files = false;502m_exception_extra_args.Clear();503m_move_to_nearest_code = eLazyBoolCalculate;504m_source_regex_func_names.clear();505m_current_key.clear();506}507508llvm::ArrayRef<OptionDefinition> GetDefinitions() override {509return llvm::ArrayRef(g_breakpoint_set_options);510}511512// Instance variables to hold the values for command options.513514std::string m_condition;515FileSpecList m_filenames;516uint32_t m_line_num = 0;517uint32_t m_column = 0;518std::vector<std::string> m_func_names;519std::vector<std::string> m_breakpoint_names;520lldb::FunctionNameType m_func_name_type_mask = eFunctionNameTypeNone;521std::string m_func_regexp;522std::string m_source_text_regexp;523FileSpecList m_modules;524lldb::addr_t m_load_addr = 0;525lldb::addr_t m_offset_addr;526bool m_catch_bp = false;527bool m_throw_bp = true;528bool m_hardware = false; // Request to use hardware breakpoints529lldb::LanguageType m_exception_language = eLanguageTypeUnknown;530lldb::LanguageType m_language = lldb::eLanguageTypeUnknown;531LazyBool m_skip_prologue = eLazyBoolCalculate;532bool m_all_files = false;533Args m_exception_extra_args;534LazyBool m_move_to_nearest_code = eLazyBoolCalculate;535std::unordered_set<std::string> m_source_regex_func_names;536std::string m_current_key;537};538539protected:540void DoExecute(Args &command, CommandReturnObject &result) override {541Target &target = GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy);542543// The following are the various types of breakpoints that could be set:544// 1). -f -l -p [-s -g] (setting breakpoint by source location)545// 2). -a [-s -g] (setting breakpoint by address)546// 3). -n [-s -g] (setting breakpoint by function name)547// 4). -r [-s -g] (setting breakpoint by function name regular548// expression)549// 5). -p -f (setting a breakpoint by comparing a reg-exp550// to source text)551// 6). -E [-w -h] (setting a breakpoint for exceptions for a552// given language.)553554BreakpointSetType break_type = eSetTypeInvalid;555556if (!m_python_class_options.GetName().empty())557break_type = eSetTypeScripted;558else if (m_options.m_line_num != 0)559break_type = eSetTypeFileAndLine;560else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)561break_type = eSetTypeAddress;562else if (!m_options.m_func_names.empty())563break_type = eSetTypeFunctionName;564else if (!m_options.m_func_regexp.empty())565break_type = eSetTypeFunctionRegexp;566else if (!m_options.m_source_text_regexp.empty())567break_type = eSetTypeSourceRegexp;568else if (m_options.m_exception_language != eLanguageTypeUnknown)569break_type = eSetTypeException;570571BreakpointSP bp_sp = nullptr;572FileSpec module_spec;573const bool internal = false;574575// If the user didn't specify skip-prologue, having an offset should turn576// that off.577if (m_options.m_offset_addr != 0 &&578m_options.m_skip_prologue == eLazyBoolCalculate)579m_options.m_skip_prologue = eLazyBoolNo;580581switch (break_type) {582case eSetTypeFileAndLine: // Breakpoint by source position583{584FileSpec file;585const size_t num_files = m_options.m_filenames.GetSize();586if (num_files == 0) {587if (!GetDefaultFile(target, file, result)) {588result.AppendError("No file supplied and no default file available.");589return;590}591} else if (num_files > 1) {592result.AppendError("Only one file at a time is allowed for file and "593"line breakpoints.");594return;595} else596file = m_options.m_filenames.GetFileSpecAtIndex(0);597598// Only check for inline functions if599LazyBool check_inlines = eLazyBoolCalculate;600601bp_sp = target.CreateBreakpoint(602&(m_options.m_modules), file, m_options.m_line_num,603m_options.m_column, m_options.m_offset_addr, check_inlines,604m_options.m_skip_prologue, internal, m_options.m_hardware,605m_options.m_move_to_nearest_code);606} break;607608case eSetTypeAddress: // Breakpoint by address609{610// If a shared library has been specified, make an lldb_private::Address611// with the library, and use that. That way the address breakpoint612// will track the load location of the library.613size_t num_modules_specified = m_options.m_modules.GetSize();614if (num_modules_specified == 1) {615const FileSpec &file_spec =616m_options.m_modules.GetFileSpecAtIndex(0);617bp_sp = target.CreateAddressInModuleBreakpoint(618m_options.m_load_addr, internal, file_spec, m_options.m_hardware);619} else if (num_modules_specified == 0) {620bp_sp = target.CreateBreakpoint(m_options.m_load_addr, internal,621m_options.m_hardware);622} else {623result.AppendError("Only one shared library can be specified for "624"address breakpoints.");625return;626}627break;628}629case eSetTypeFunctionName: // Breakpoint by function name630{631FunctionNameType name_type_mask = m_options.m_func_name_type_mask;632633if (name_type_mask == 0)634name_type_mask = eFunctionNameTypeAuto;635636bp_sp = target.CreateBreakpoint(637&(m_options.m_modules), &(m_options.m_filenames),638m_options.m_func_names, name_type_mask, m_options.m_language,639m_options.m_offset_addr, m_options.m_skip_prologue, internal,640m_options.m_hardware);641} break;642643case eSetTypeFunctionRegexp: // Breakpoint by regular expression function644// name645{646RegularExpression regexp(m_options.m_func_regexp);647if (llvm::Error err = regexp.GetError()) {648result.AppendErrorWithFormat(649"Function name regular expression could not be compiled: %s",650llvm::toString(std::move(err)).c_str());651// Check if the incorrect regex looks like a globbing expression and652// warn the user about it.653if (!m_options.m_func_regexp.empty()) {654if (m_options.m_func_regexp[0] == '*' ||655m_options.m_func_regexp[0] == '?')656result.AppendWarning(657"Function name regex does not accept glob patterns.");658}659return;660}661662bp_sp = target.CreateFuncRegexBreakpoint(663&(m_options.m_modules), &(m_options.m_filenames), std::move(regexp),664m_options.m_language, m_options.m_skip_prologue, internal,665m_options.m_hardware);666} break;667case eSetTypeSourceRegexp: // Breakpoint by regexp on source text.668{669const size_t num_files = m_options.m_filenames.GetSize();670671if (num_files == 0 && !m_options.m_all_files) {672FileSpec file;673if (!GetDefaultFile(target, file, result)) {674result.AppendError(675"No files provided and could not find default file.");676return;677} else {678m_options.m_filenames.Append(file);679}680}681682RegularExpression regexp(m_options.m_source_text_regexp);683if (llvm::Error err = regexp.GetError()) {684result.AppendErrorWithFormat(685"Source text regular expression could not be compiled: \"%s\"",686llvm::toString(std::move(err)).c_str());687return;688}689bp_sp = target.CreateSourceRegexBreakpoint(690&(m_options.m_modules), &(m_options.m_filenames),691m_options.m_source_regex_func_names, std::move(regexp), internal,692m_options.m_hardware, m_options.m_move_to_nearest_code);693} break;694case eSetTypeException: {695Status precond_error;696bp_sp = target.CreateExceptionBreakpoint(697m_options.m_exception_language, m_options.m_catch_bp,698m_options.m_throw_bp, internal, &m_options.m_exception_extra_args,699&precond_error);700if (precond_error.Fail()) {701result.AppendErrorWithFormat(702"Error setting extra exception arguments: %s",703precond_error.AsCString());704target.RemoveBreakpointByID(bp_sp->GetID());705return;706}707} break;708case eSetTypeScripted: {709710Status error;711bp_sp = target.CreateScriptedBreakpoint(712m_python_class_options.GetName().c_str(), &(m_options.m_modules),713&(m_options.m_filenames), false, m_options.m_hardware,714m_python_class_options.GetStructuredData(), &error);715if (error.Fail()) {716result.AppendErrorWithFormat(717"Error setting extra exception arguments: %s", error.AsCString());718target.RemoveBreakpointByID(bp_sp->GetID());719return;720}721} break;722default:723break;724}725726// Now set the various options that were passed in:727if (bp_sp) {728bp_sp->GetOptions().CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());729730if (!m_options.m_breakpoint_names.empty()) {731Status name_error;732for (auto name : m_options.m_breakpoint_names) {733target.AddNameToBreakpoint(bp_sp, name.c_str(), name_error);734if (name_error.Fail()) {735result.AppendErrorWithFormat("Invalid breakpoint name: %s",736name.c_str());737target.RemoveBreakpointByID(bp_sp->GetID());738return;739}740}741}742}743744if (bp_sp) {745Stream &output_stream = result.GetOutputStream();746const bool show_locations = false;747bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,748show_locations);749if (&target == &GetDummyTarget())750output_stream.Printf("Breakpoint set in dummy target, will get copied "751"into future targets.\n");752else {753// Don't print out this warning for exception breakpoints. They can754// get set before the target is set, but we won't know how to actually755// set the breakpoint till we run.756if (bp_sp->GetNumLocations() == 0 && break_type != eSetTypeException) {757output_stream.Printf("WARNING: Unable to resolve breakpoint to any "758"actual locations.\n");759}760}761result.SetStatus(eReturnStatusSuccessFinishResult);762} else if (!bp_sp) {763result.AppendError("Breakpoint creation failed: No breakpoint created.");764}765}766767private:768bool GetDefaultFile(Target &target, FileSpec &file,769CommandReturnObject &result) {770uint32_t default_line;771// First use the Source Manager's default file. Then use the current stack772// frame's file.773if (!target.GetSourceManager().GetDefaultFileAndLine(file, default_line)) {774StackFrame *cur_frame = m_exe_ctx.GetFramePtr();775if (cur_frame == nullptr) {776result.AppendError(777"No selected frame to use to find the default file.");778return false;779} else if (!cur_frame->HasDebugInformation()) {780result.AppendError("Cannot use the selected frame to find the default "781"file, it has no debug info.");782return false;783} else {784const SymbolContext &sc =785cur_frame->GetSymbolContext(eSymbolContextLineEntry);786if (sc.line_entry.GetFile()) {787file = sc.line_entry.GetFile();788} else {789result.AppendError("Can't find the file for the selected frame to "790"use as the default file.");791return false;792}793}794}795return true;796}797798BreakpointOptionGroup m_bp_opts;799BreakpointDummyOptionGroup m_dummy_options;800OptionGroupPythonClassWithDict m_python_class_options;801CommandOptions m_options;802OptionGroupOptions m_all_options;803};804805// CommandObjectBreakpointModify806#pragma mark Modify807808class CommandObjectBreakpointModify : public CommandObjectParsed {809public:810CommandObjectBreakpointModify(CommandInterpreter &interpreter)811: CommandObjectParsed(interpreter, "breakpoint modify",812"Modify the options on a breakpoint or set of "813"breakpoints in the executable. "814"If no breakpoint is specified, acts on the last "815"created breakpoint. "816"With the exception of -e, -d and -i, passing an "817"empty argument clears the modification.",818nullptr) {819CommandObject::AddIDsArgumentData(eBreakpointArgs);820821m_options.Append(&m_bp_opts,822LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3,823LLDB_OPT_SET_ALL);824m_options.Append(&m_dummy_opts, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);825m_options.Finalize();826}827828~CommandObjectBreakpointModify() override = default;829830void831HandleArgumentCompletion(CompletionRequest &request,832OptionElementVector &opt_element_vector) override {833lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(834GetCommandInterpreter(), lldb::eBreakpointCompletion, request, nullptr);835}836837Options *GetOptions() override { return &m_options; }838839protected:840void DoExecute(Args &command, CommandReturnObject &result) override {841Target &target = GetSelectedOrDummyTarget(m_dummy_opts.m_use_dummy);842843std::unique_lock<std::recursive_mutex> lock;844target.GetBreakpointList().GetListMutex(lock);845846BreakpointIDList valid_bp_ids;847848CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(849command, &target, result, &valid_bp_ids,850BreakpointName::Permissions::PermissionKinds::disablePerm);851852if (result.Succeeded()) {853const size_t count = valid_bp_ids.GetSize();854for (size_t i = 0; i < count; ++i) {855BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);856857if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {858Breakpoint *bp =859target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();860if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {861BreakpointLocation *location =862bp->FindLocationByID(cur_bp_id.GetLocationID()).get();863if (location)864location->GetLocationOptions().CopyOverSetOptions(865m_bp_opts.GetBreakpointOptions());866} else {867bp->GetOptions().CopyOverSetOptions(868m_bp_opts.GetBreakpointOptions());869}870}871}872}873}874875private:876BreakpointOptionGroup m_bp_opts;877BreakpointDummyOptionGroup m_dummy_opts;878OptionGroupOptions m_options;879};880881// CommandObjectBreakpointEnable882#pragma mark Enable883884class CommandObjectBreakpointEnable : public CommandObjectParsed {885public:886CommandObjectBreakpointEnable(CommandInterpreter &interpreter)887: CommandObjectParsed(interpreter, "enable",888"Enable the specified disabled breakpoint(s). If "889"no breakpoints are specified, enable all of them.",890nullptr) {891CommandObject::AddIDsArgumentData(eBreakpointArgs);892}893894~CommandObjectBreakpointEnable() override = default;895896void897HandleArgumentCompletion(CompletionRequest &request,898OptionElementVector &opt_element_vector) override {899lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(900GetCommandInterpreter(), lldb::eBreakpointCompletion, request, nullptr);901}902903protected:904void DoExecute(Args &command, CommandReturnObject &result) override {905Target &target = GetSelectedOrDummyTarget();906907std::unique_lock<std::recursive_mutex> lock;908target.GetBreakpointList().GetListMutex(lock);909910const BreakpointList &breakpoints = target.GetBreakpointList();911912size_t num_breakpoints = breakpoints.GetSize();913914if (num_breakpoints == 0) {915result.AppendError("No breakpoints exist to be enabled.");916return;917}918919if (command.empty()) {920// No breakpoint selected; enable all currently set breakpoints.921target.EnableAllowedBreakpoints();922result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64923" breakpoints)\n",924(uint64_t)num_breakpoints);925result.SetStatus(eReturnStatusSuccessFinishNoResult);926} else {927// Particular breakpoint selected; enable that breakpoint.928BreakpointIDList valid_bp_ids;929CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(930command, &target, result, &valid_bp_ids,931BreakpointName::Permissions::PermissionKinds::disablePerm);932933if (result.Succeeded()) {934int enable_count = 0;935int loc_count = 0;936const size_t count = valid_bp_ids.GetSize();937for (size_t i = 0; i < count; ++i) {938BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);939940if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {941Breakpoint *breakpoint =942target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();943if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {944BreakpointLocation *location =945breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();946if (location) {947location->SetEnabled(true);948++loc_count;949}950} else {951breakpoint->SetEnabled(true);952++enable_count;953}954}955}956result.AppendMessageWithFormat("%d breakpoints enabled.\n",957enable_count + loc_count);958result.SetStatus(eReturnStatusSuccessFinishNoResult);959}960}961}962};963964// CommandObjectBreakpointDisable965#pragma mark Disable966967class CommandObjectBreakpointDisable : public CommandObjectParsed {968public:969CommandObjectBreakpointDisable(CommandInterpreter &interpreter)970: CommandObjectParsed(971interpreter, "breakpoint disable",972"Disable the specified breakpoint(s) without deleting "973"them. If none are specified, disable all "974"breakpoints.",975nullptr) {976SetHelpLong(977"Disable the specified breakpoint(s) without deleting them. \978If none are specified, disable all breakpoints."979R"(980981)"982"Note: disabling a breakpoint will cause none of its locations to be hit \983regardless of whether individual locations are enabled or disabled. After the sequence:"984R"(985986(lldb) break disable 1987(lldb) break enable 1.1988989execution will NOT stop at location 1.1. To achieve that, type:990991(lldb) break disable 1.*992(lldb) break enable 1.1993994)"995"The first command disables all locations for breakpoint 1, \996the second re-enables the first location.");997998CommandObject::AddIDsArgumentData(eBreakpointArgs);999}10001001~CommandObjectBreakpointDisable() override = default;10021003void1004HandleArgumentCompletion(CompletionRequest &request,1005OptionElementVector &opt_element_vector) override {1006lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1007GetCommandInterpreter(), lldb::eBreakpointCompletion, request, nullptr);1008}10091010protected:1011void DoExecute(Args &command, CommandReturnObject &result) override {1012Target &target = GetSelectedOrDummyTarget();1013std::unique_lock<std::recursive_mutex> lock;1014target.GetBreakpointList().GetListMutex(lock);10151016const BreakpointList &breakpoints = target.GetBreakpointList();1017size_t num_breakpoints = breakpoints.GetSize();10181019if (num_breakpoints == 0) {1020result.AppendError("No breakpoints exist to be disabled.");1021return;1022}10231024if (command.empty()) {1025// No breakpoint selected; disable all currently set breakpoints.1026target.DisableAllowedBreakpoints();1027result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu641028" breakpoints)\n",1029(uint64_t)num_breakpoints);1030result.SetStatus(eReturnStatusSuccessFinishNoResult);1031} else {1032// Particular breakpoint selected; disable that breakpoint.1033BreakpointIDList valid_bp_ids;10341035CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(1036command, &target, result, &valid_bp_ids,1037BreakpointName::Permissions::PermissionKinds::disablePerm);10381039if (result.Succeeded()) {1040int disable_count = 0;1041int loc_count = 0;1042const size_t count = valid_bp_ids.GetSize();1043for (size_t i = 0; i < count; ++i) {1044BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);10451046if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {1047Breakpoint *breakpoint =1048target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();1049if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {1050BreakpointLocation *location =1051breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();1052if (location) {1053location->SetEnabled(false);1054++loc_count;1055}1056} else {1057breakpoint->SetEnabled(false);1058++disable_count;1059}1060}1061}1062result.AppendMessageWithFormat("%d breakpoints disabled.\n",1063disable_count + loc_count);1064result.SetStatus(eReturnStatusSuccessFinishNoResult);1065}1066}1067}1068};10691070// CommandObjectBreakpointList10711072#pragma mark List::CommandOptions1073#define LLDB_OPTIONS_breakpoint_list1074#include "CommandOptions.inc"10751076#pragma mark List10771078class CommandObjectBreakpointList : public CommandObjectParsed {1079public:1080CommandObjectBreakpointList(CommandInterpreter &interpreter)1081: CommandObjectParsed(1082interpreter, "breakpoint list",1083"List some or all breakpoints at configurable levels of detail.",1084nullptr) {1085CommandArgumentEntry arg;1086CommandArgumentData bp_id_arg;10871088// Define the first (and only) variant of this arg.1089AddSimpleArgumentList(eArgTypeBreakpointID, eArgRepeatOptional);1090}10911092~CommandObjectBreakpointList() override = default;10931094Options *GetOptions() override { return &m_options; }10951096class CommandOptions : public Options {1097public:1098CommandOptions() = default;10991100~CommandOptions() override = default;11011102Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1103ExecutionContext *execution_context) override {1104Status error;1105const int short_option = m_getopt_table[option_idx].val;11061107switch (short_option) {1108case 'b':1109m_level = lldb::eDescriptionLevelBrief;1110break;1111case 'D':1112m_use_dummy = true;1113break;1114case 'f':1115m_level = lldb::eDescriptionLevelFull;1116break;1117case 'v':1118m_level = lldb::eDescriptionLevelVerbose;1119break;1120case 'i':1121m_internal = true;1122break;1123default:1124llvm_unreachable("Unimplemented option");1125}11261127return error;1128}11291130void OptionParsingStarting(ExecutionContext *execution_context) override {1131m_level = lldb::eDescriptionLevelFull;1132m_internal = false;1133m_use_dummy = false;1134}11351136llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1137return llvm::ArrayRef(g_breakpoint_list_options);1138}11391140// Instance variables to hold the values for command options.11411142lldb::DescriptionLevel m_level = lldb::eDescriptionLevelBrief;11431144bool m_internal;1145bool m_use_dummy = false;1146};11471148protected:1149void DoExecute(Args &command, CommandReturnObject &result) override {1150Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy);11511152const BreakpointList &breakpoints =1153target.GetBreakpointList(m_options.m_internal);1154std::unique_lock<std::recursive_mutex> lock;1155target.GetBreakpointList(m_options.m_internal).GetListMutex(lock);11561157size_t num_breakpoints = breakpoints.GetSize();11581159if (num_breakpoints == 0) {1160result.AppendMessage("No breakpoints currently set.");1161result.SetStatus(eReturnStatusSuccessFinishNoResult);1162return;1163}11641165Stream &output_stream = result.GetOutputStream();11661167if (command.empty()) {1168// No breakpoint selected; show info about all currently set breakpoints.1169result.AppendMessage("Current breakpoints:");1170for (size_t i = 0; i < num_breakpoints; ++i) {1171Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get();1172if (breakpoint->AllowList())1173AddBreakpointDescription(&output_stream, breakpoint,1174m_options.m_level);1175}1176result.SetStatus(eReturnStatusSuccessFinishNoResult);1177} else {1178// Particular breakpoints selected; show info about that breakpoint.1179BreakpointIDList valid_bp_ids;1180CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(1181command, &target, result, &valid_bp_ids,1182BreakpointName::Permissions::PermissionKinds::listPerm);11831184if (result.Succeeded()) {1185for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) {1186BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);1187Breakpoint *breakpoint =1188target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();1189AddBreakpointDescription(&output_stream, breakpoint,1190m_options.m_level);1191}1192result.SetStatus(eReturnStatusSuccessFinishNoResult);1193} else {1194result.AppendError("Invalid breakpoint ID.");1195}1196}1197}11981199private:1200CommandOptions m_options;1201};12021203// CommandObjectBreakpointClear1204#pragma mark Clear::CommandOptions12051206#define LLDB_OPTIONS_breakpoint_clear1207#include "CommandOptions.inc"12081209#pragma mark Clear12101211class CommandObjectBreakpointClear : public CommandObjectParsed {1212public:1213enum BreakpointClearType { eClearTypeInvalid, eClearTypeFileAndLine };12141215CommandObjectBreakpointClear(CommandInterpreter &interpreter)1216: CommandObjectParsed(interpreter, "breakpoint clear",1217"Delete or disable breakpoints matching the "1218"specified source file and line.",1219"breakpoint clear <cmd-options>") {}12201221~CommandObjectBreakpointClear() override = default;12221223Options *GetOptions() override { return &m_options; }12241225class CommandOptions : public Options {1226public:1227CommandOptions() = default;12281229~CommandOptions() override = default;12301231Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1232ExecutionContext *execution_context) override {1233Status error;1234const int short_option = m_getopt_table[option_idx].val;12351236switch (short_option) {1237case 'f':1238m_filename.assign(std::string(option_arg));1239break;12401241case 'l':1242option_arg.getAsInteger(0, m_line_num);1243break;12441245default:1246llvm_unreachable("Unimplemented option");1247}12481249return error;1250}12511252void OptionParsingStarting(ExecutionContext *execution_context) override {1253m_filename.clear();1254m_line_num = 0;1255}12561257llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1258return llvm::ArrayRef(g_breakpoint_clear_options);1259}12601261// Instance variables to hold the values for command options.12621263std::string m_filename;1264uint32_t m_line_num = 0;1265};12661267protected:1268void DoExecute(Args &command, CommandReturnObject &result) override {1269Target &target = GetSelectedOrDummyTarget();12701271// The following are the various types of breakpoints that could be1272// cleared:1273// 1). -f -l (clearing breakpoint by source location)12741275BreakpointClearType break_type = eClearTypeInvalid;12761277if (m_options.m_line_num != 0)1278break_type = eClearTypeFileAndLine;12791280std::unique_lock<std::recursive_mutex> lock;1281target.GetBreakpointList().GetListMutex(lock);12821283BreakpointList &breakpoints = target.GetBreakpointList();1284size_t num_breakpoints = breakpoints.GetSize();12851286// Early return if there's no breakpoint at all.1287if (num_breakpoints == 0) {1288result.AppendError("Breakpoint clear: No breakpoint cleared.");1289return;1290}12911292// Find matching breakpoints and delete them.12931294// First create a copy of all the IDs.1295std::vector<break_id_t> BreakIDs;1296for (size_t i = 0; i < num_breakpoints; ++i)1297BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID());12981299int num_cleared = 0;1300StreamString ss;1301switch (break_type) {1302case eClearTypeFileAndLine: // Breakpoint by source position1303{1304const ConstString filename(m_options.m_filename.c_str());1305BreakpointLocationCollection loc_coll;13061307for (size_t i = 0; i < num_breakpoints; ++i) {1308Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get();13091310if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) {1311// If the collection size is 0, it's a full match and we can just1312// remove the breakpoint.1313if (loc_coll.GetSize() == 0) {1314bp->GetDescription(&ss, lldb::eDescriptionLevelBrief);1315ss.EOL();1316target.RemoveBreakpointByID(bp->GetID());1317++num_cleared;1318}1319}1320}1321} break;13221323default:1324break;1325}13261327if (num_cleared > 0) {1328Stream &output_stream = result.GetOutputStream();1329output_stream.Printf("%d breakpoints cleared:\n", num_cleared);1330output_stream << ss.GetString();1331output_stream.EOL();1332result.SetStatus(eReturnStatusSuccessFinishNoResult);1333} else {1334result.AppendError("Breakpoint clear: No breakpoint cleared.");1335}1336}13371338private:1339CommandOptions m_options;1340};13411342// CommandObjectBreakpointDelete1343#define LLDB_OPTIONS_breakpoint_delete1344#include "CommandOptions.inc"13451346#pragma mark Delete13471348class CommandObjectBreakpointDelete : public CommandObjectParsed {1349public:1350CommandObjectBreakpointDelete(CommandInterpreter &interpreter)1351: CommandObjectParsed(interpreter, "breakpoint delete",1352"Delete the specified breakpoint(s). If no "1353"breakpoints are specified, delete them all.",1354nullptr) {1355CommandObject::AddIDsArgumentData(eBreakpointArgs);1356}13571358~CommandObjectBreakpointDelete() override = default;13591360void1361HandleArgumentCompletion(CompletionRequest &request,1362OptionElementVector &opt_element_vector) override {1363lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1364GetCommandInterpreter(), lldb::eBreakpointCompletion, request, nullptr);1365}13661367Options *GetOptions() override { return &m_options; }13681369class CommandOptions : public Options {1370public:1371CommandOptions() = default;13721373~CommandOptions() override = default;13741375Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1376ExecutionContext *execution_context) override {1377Status error;1378const int short_option = m_getopt_table[option_idx].val;13791380switch (short_option) {1381case 'f':1382m_force = true;1383break;13841385case 'D':1386m_use_dummy = true;1387break;13881389case 'd':1390m_delete_disabled = true;1391break;13921393default:1394llvm_unreachable("Unimplemented option");1395}13961397return error;1398}13991400void OptionParsingStarting(ExecutionContext *execution_context) override {1401m_use_dummy = false;1402m_force = false;1403m_delete_disabled = false;1404}14051406llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1407return llvm::ArrayRef(g_breakpoint_delete_options);1408}14091410// Instance variables to hold the values for command options.1411bool m_use_dummy = false;1412bool m_force = false;1413bool m_delete_disabled = false;1414};14151416protected:1417void DoExecute(Args &command, CommandReturnObject &result) override {1418Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy);1419result.Clear();14201421std::unique_lock<std::recursive_mutex> lock;1422target.GetBreakpointList().GetListMutex(lock);14231424BreakpointList &breakpoints = target.GetBreakpointList();14251426size_t num_breakpoints = breakpoints.GetSize();14271428if (num_breakpoints == 0) {1429result.AppendError("No breakpoints exist to be deleted.");1430return;1431}14321433// Handle the delete all breakpoints case:1434if (command.empty() && !m_options.m_delete_disabled) {1435if (!m_options.m_force &&1436!m_interpreter.Confirm(1437"About to delete all breakpoints, do you want to do that?",1438true)) {1439result.AppendMessage("Operation cancelled...");1440} else {1441target.RemoveAllowedBreakpoints();1442result.AppendMessageWithFormat(1443"All breakpoints removed. (%" PRIu64 " breakpoint%s)\n",1444(uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : "");1445}1446result.SetStatus(eReturnStatusSuccessFinishNoResult);1447return;1448}14491450// Either we have some kind of breakpoint specification(s),1451// or we are handling "break disable --deleted". Gather the list1452// of breakpoints to delete here, the we'll delete them below.1453BreakpointIDList valid_bp_ids;14541455if (m_options.m_delete_disabled) {1456BreakpointIDList excluded_bp_ids;14571458if (!command.empty()) {1459CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(1460command, &target, result, &excluded_bp_ids,1461BreakpointName::Permissions::PermissionKinds::deletePerm);1462if (!result.Succeeded())1463return;1464}14651466for (auto breakpoint_sp : breakpoints.Breakpoints()) {1467if (!breakpoint_sp->IsEnabled() && breakpoint_sp->AllowDelete()) {1468BreakpointID bp_id(breakpoint_sp->GetID());1469if (!excluded_bp_ids.Contains(bp_id))1470valid_bp_ids.AddBreakpointID(bp_id);1471}1472}1473if (valid_bp_ids.GetSize() == 0) {1474result.AppendError("No disabled breakpoints.");1475return;1476}1477} else {1478CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(1479command, &target, result, &valid_bp_ids,1480BreakpointName::Permissions::PermissionKinds::deletePerm);1481if (!result.Succeeded())1482return;1483}14841485int delete_count = 0;1486int disable_count = 0;1487const size_t count = valid_bp_ids.GetSize();1488for (size_t i = 0; i < count; ++i) {1489BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);14901491if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {1492if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {1493Breakpoint *breakpoint =1494target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();1495BreakpointLocation *location =1496breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();1497// It makes no sense to try to delete individual locations, so we1498// disable them instead.1499if (location) {1500location->SetEnabled(false);1501++disable_count;1502}1503} else {1504target.RemoveBreakpointByID(cur_bp_id.GetBreakpointID());1505++delete_count;1506}1507}1508}1509result.AppendMessageWithFormat(1510"%d breakpoints deleted; %d breakpoint locations disabled.\n",1511delete_count, disable_count);1512result.SetStatus(eReturnStatusSuccessFinishNoResult);1513}15141515private:1516CommandOptions m_options;1517};15181519// CommandObjectBreakpointName1520#define LLDB_OPTIONS_breakpoint_name1521#include "CommandOptions.inc"15221523class BreakpointNameOptionGroup : public OptionGroup {1524public:1525BreakpointNameOptionGroup()1526: m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) {}15271528~BreakpointNameOptionGroup() override = default;15291530llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1531return llvm::ArrayRef(g_breakpoint_name_options);1532}15331534Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1535ExecutionContext *execution_context) override {1536Status error;1537const int short_option = g_breakpoint_name_options[option_idx].short_option;1538const char *long_option = g_breakpoint_name_options[option_idx].long_option;15391540switch (short_option) {1541case 'N':1542if (BreakpointID::StringIsBreakpointName(option_arg, error) &&1543error.Success())1544m_name.SetValueFromString(option_arg);1545break;1546case 'B':1547if (m_breakpoint.SetValueFromString(option_arg).Fail())1548error = CreateOptionParsingError(option_arg, short_option, long_option,1549g_int_parsing_error_message);1550break;1551case 'D':1552if (m_use_dummy.SetValueFromString(option_arg).Fail())1553error = CreateOptionParsingError(option_arg, short_option, long_option,1554g_bool_parsing_error_message);1555break;1556case 'H':1557m_help_string.SetValueFromString(option_arg);1558break;15591560default:1561llvm_unreachable("Unimplemented option");1562}1563return error;1564}15651566void OptionParsingStarting(ExecutionContext *execution_context) override {1567m_name.Clear();1568m_breakpoint.Clear();1569m_use_dummy.Clear();1570m_use_dummy.SetDefaultValue(false);1571m_help_string.Clear();1572}15731574OptionValueString m_name;1575OptionValueUInt64 m_breakpoint;1576OptionValueBoolean m_use_dummy;1577OptionValueString m_help_string;1578};15791580#define LLDB_OPTIONS_breakpoint_access1581#include "CommandOptions.inc"15821583class BreakpointAccessOptionGroup : public OptionGroup {1584public:1585BreakpointAccessOptionGroup() = default;15861587~BreakpointAccessOptionGroup() override = default;15881589llvm::ArrayRef<OptionDefinition> GetDefinitions() override {1590return llvm::ArrayRef(g_breakpoint_access_options);1591}1592Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,1593ExecutionContext *execution_context) override {1594Status error;1595const int short_option =1596g_breakpoint_access_options[option_idx].short_option;1597const char *long_option =1598g_breakpoint_access_options[option_idx].long_option;15991600switch (short_option) {1601case 'L': {1602bool value, success;1603value = OptionArgParser::ToBoolean(option_arg, false, &success);1604if (success) {1605m_permissions.SetAllowList(value);1606} else1607error = CreateOptionParsingError(option_arg, short_option, long_option,1608g_bool_parsing_error_message);1609} break;1610case 'A': {1611bool value, success;1612value = OptionArgParser::ToBoolean(option_arg, false, &success);1613if (success) {1614m_permissions.SetAllowDisable(value);1615} else1616error = CreateOptionParsingError(option_arg, short_option, long_option,1617g_bool_parsing_error_message);1618} break;1619case 'D': {1620bool value, success;1621value = OptionArgParser::ToBoolean(option_arg, false, &success);1622if (success) {1623m_permissions.SetAllowDelete(value);1624} else1625error = CreateOptionParsingError(option_arg, short_option, long_option,1626g_bool_parsing_error_message);1627} break;1628default:1629llvm_unreachable("Unimplemented option");1630}16311632return error;1633}16341635void OptionParsingStarting(ExecutionContext *execution_context) override {}16361637const BreakpointName::Permissions &GetPermissions() const {1638return m_permissions;1639}1640BreakpointName::Permissions m_permissions;1641};16421643class CommandObjectBreakpointNameConfigure : public CommandObjectParsed {1644public:1645CommandObjectBreakpointNameConfigure(CommandInterpreter &interpreter)1646: CommandObjectParsed(1647interpreter, "configure",1648"Configure the options for the breakpoint"1649" name provided. "1650"If you provide a breakpoint id, the options will be copied from "1651"the breakpoint, otherwise only the options specified will be set "1652"on the name.",1653"breakpoint name configure <command-options> "1654"<breakpoint-name-list>") {1655AddSimpleArgumentList(eArgTypeBreakpointName, eArgRepeatOptional);16561657m_option_group.Append(&m_bp_opts, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);1658m_option_group.Append(&m_access_options, LLDB_OPT_SET_ALL,1659LLDB_OPT_SET_ALL);1660m_option_group.Append(&m_bp_id, LLDB_OPT_SET_2 | LLDB_OPT_SET_4,1661LLDB_OPT_SET_ALL);1662m_option_group.Finalize();1663}16641665~CommandObjectBreakpointNameConfigure() override = default;16661667Options *GetOptions() override { return &m_option_group; }16681669protected:1670void DoExecute(Args &command, CommandReturnObject &result) override {16711672const size_t argc = command.GetArgumentCount();1673if (argc == 0) {1674result.AppendError("No names provided.");1675return;1676}16771678Target &target = GetSelectedOrDummyTarget(false);16791680std::unique_lock<std::recursive_mutex> lock;1681target.GetBreakpointList().GetListMutex(lock);16821683// Make a pass through first to see that all the names are legal.1684for (auto &entry : command.entries()) {1685Status error;1686if (!BreakpointID::StringIsBreakpointName(entry.ref(), error)) {1687result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s",1688entry.c_str(), error.AsCString());1689return;1690}1691}1692// Now configure them, we already pre-checked the names so we don't need to1693// check the error:1694BreakpointSP bp_sp;1695if (m_bp_id.m_breakpoint.OptionWasSet()) {1696lldb::break_id_t bp_id =1697m_bp_id.m_breakpoint.GetValueAs<uint64_t>().value_or(0);1698bp_sp = target.GetBreakpointByID(bp_id);1699if (!bp_sp) {1700result.AppendErrorWithFormatv("Could not find specified breakpoint {0}",1701bp_id);1702return;1703}1704}17051706Status error;1707for (auto &entry : command.entries()) {1708ConstString name(entry.c_str());1709BreakpointName *bp_name = target.FindBreakpointName(name, true, error);1710if (!bp_name)1711continue;1712if (m_bp_id.m_help_string.OptionWasSet())1713bp_name->SetHelp(m_bp_id.m_help_string.GetValueAs<llvm::StringRef>()1714.value_or("")1715.str()1716.c_str());17171718if (bp_sp)1719target.ConfigureBreakpointName(*bp_name, bp_sp->GetOptions(),1720m_access_options.GetPermissions());1721else1722target.ConfigureBreakpointName(*bp_name,1723m_bp_opts.GetBreakpointOptions(),1724m_access_options.GetPermissions());1725}1726}17271728private:1729BreakpointNameOptionGroup m_bp_id; // Only using the id part of this.1730BreakpointOptionGroup m_bp_opts;1731BreakpointAccessOptionGroup m_access_options;1732OptionGroupOptions m_option_group;1733};17341735class CommandObjectBreakpointNameAdd : public CommandObjectParsed {1736public:1737CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter)1738: CommandObjectParsed(1739interpreter, "add", "Add a name to the breakpoints provided.",1740"breakpoint name add <command-options> <breakpoint-id-list>") {1741AddSimpleArgumentList(eArgTypeBreakpointID, eArgRepeatOptional);17421743m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);1744m_option_group.Finalize();1745}17461747~CommandObjectBreakpointNameAdd() override = default;17481749void1750HandleArgumentCompletion(CompletionRequest &request,1751OptionElementVector &opt_element_vector) override {1752lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1753GetCommandInterpreter(), lldb::eBreakpointCompletion, request, nullptr);1754}17551756Options *GetOptions() override { return &m_option_group; }17571758protected:1759void DoExecute(Args &command, CommandReturnObject &result) override {1760if (!m_name_options.m_name.OptionWasSet()) {1761result.AppendError("No name option provided.");1762return;1763}17641765Target &target =1766GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());17671768std::unique_lock<std::recursive_mutex> lock;1769target.GetBreakpointList().GetListMutex(lock);17701771const BreakpointList &breakpoints = target.GetBreakpointList();17721773size_t num_breakpoints = breakpoints.GetSize();1774if (num_breakpoints == 0) {1775result.AppendError("No breakpoints, cannot add names.");1776return;1777}17781779// Particular breakpoint selected; disable that breakpoint.1780BreakpointIDList valid_bp_ids;1781CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(1782command, &target, result, &valid_bp_ids,1783BreakpointName::Permissions::PermissionKinds::listPerm);17841785if (result.Succeeded()) {1786if (valid_bp_ids.GetSize() == 0) {1787result.AppendError("No breakpoints specified, cannot add names.");1788return;1789}1790size_t num_valid_ids = valid_bp_ids.GetSize();1791const char *bp_name = m_name_options.m_name.GetCurrentValue();1792Status error; // This error reports illegal names, but we've already1793// checked that, so we don't need to check it again here.1794for (size_t index = 0; index < num_valid_ids; index++) {1795lldb::break_id_t bp_id =1796valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();1797BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);1798target.AddNameToBreakpoint(bp_sp, bp_name, error);1799}1800}1801}18021803private:1804BreakpointNameOptionGroup m_name_options;1805OptionGroupOptions m_option_group;1806};18071808class CommandObjectBreakpointNameDelete : public CommandObjectParsed {1809public:1810CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter)1811: CommandObjectParsed(1812interpreter, "delete",1813"Delete a name from the breakpoints provided.",1814"breakpoint name delete <command-options> <breakpoint-id-list>") {1815AddSimpleArgumentList(eArgTypeBreakpointID, eArgRepeatOptional);18161817m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);1818m_option_group.Finalize();1819}18201821~CommandObjectBreakpointNameDelete() override = default;18221823void1824HandleArgumentCompletion(CompletionRequest &request,1825OptionElementVector &opt_element_vector) override {1826lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(1827GetCommandInterpreter(), lldb::eBreakpointCompletion, request, nullptr);1828}18291830Options *GetOptions() override { return &m_option_group; }18311832protected:1833void DoExecute(Args &command, CommandReturnObject &result) override {1834if (!m_name_options.m_name.OptionWasSet()) {1835result.AppendError("No name option provided.");1836return;1837}18381839Target &target =1840GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());18411842std::unique_lock<std::recursive_mutex> lock;1843target.GetBreakpointList().GetListMutex(lock);18441845const BreakpointList &breakpoints = target.GetBreakpointList();18461847size_t num_breakpoints = breakpoints.GetSize();1848if (num_breakpoints == 0) {1849result.AppendError("No breakpoints, cannot delete names.");1850return;1851}18521853// Particular breakpoint selected; disable that breakpoint.1854BreakpointIDList valid_bp_ids;1855CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(1856command, &target, result, &valid_bp_ids,1857BreakpointName::Permissions::PermissionKinds::deletePerm);18581859if (result.Succeeded()) {1860if (valid_bp_ids.GetSize() == 0) {1861result.AppendError("No breakpoints specified, cannot delete names.");1862return;1863}1864ConstString bp_name(m_name_options.m_name.GetCurrentValue());1865size_t num_valid_ids = valid_bp_ids.GetSize();1866for (size_t index = 0; index < num_valid_ids; index++) {1867lldb::break_id_t bp_id =1868valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();1869BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);1870target.RemoveNameFromBreakpoint(bp_sp, bp_name);1871}1872}1873}18741875private:1876BreakpointNameOptionGroup m_name_options;1877OptionGroupOptions m_option_group;1878};18791880class CommandObjectBreakpointNameList : public CommandObjectParsed {1881public:1882CommandObjectBreakpointNameList(CommandInterpreter &interpreter)1883: CommandObjectParsed(interpreter, "list",1884"List either the names for a breakpoint or info "1885"about a given name. With no arguments, lists all "1886"names",1887"breakpoint name list <command-options>") {1888m_option_group.Append(&m_name_options, LLDB_OPT_SET_3, LLDB_OPT_SET_ALL);1889m_option_group.Finalize();1890}18911892~CommandObjectBreakpointNameList() override = default;18931894Options *GetOptions() override { return &m_option_group; }18951896protected:1897void DoExecute(Args &command, CommandReturnObject &result) override {1898Target &target =1899GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());19001901std::vector<std::string> name_list;1902if (command.empty()) {1903target.GetBreakpointNames(name_list);1904} else {1905for (const Args::ArgEntry &arg : command) {1906name_list.push_back(arg.c_str());1907}1908}19091910if (name_list.empty()) {1911result.AppendMessage("No breakpoint names found.");1912} else {1913for (const std::string &name_str : name_list) {1914const char *name = name_str.c_str();1915// First print out the options for the name:1916Status error;1917BreakpointName *bp_name =1918target.FindBreakpointName(ConstString(name), false, error);1919if (bp_name) {1920StreamString s;1921result.AppendMessageWithFormat("Name: %s\n", name);1922if (bp_name->GetDescription(&s, eDescriptionLevelFull)) {1923result.AppendMessage(s.GetString());1924}19251926std::unique_lock<std::recursive_mutex> lock;1927target.GetBreakpointList().GetListMutex(lock);19281929BreakpointList &breakpoints = target.GetBreakpointList();1930bool any_set = false;1931for (BreakpointSP bp_sp : breakpoints.Breakpoints()) {1932if (bp_sp->MatchesName(name)) {1933StreamString s;1934any_set = true;1935bp_sp->GetDescription(&s, eDescriptionLevelBrief);1936s.EOL();1937result.AppendMessage(s.GetString());1938}1939}1940if (!any_set)1941result.AppendMessage("No breakpoints using this name.");1942} else {1943result.AppendMessageWithFormat("Name: %s not found.\n", name);1944}1945}1946}1947}19481949private:1950BreakpointNameOptionGroup m_name_options;1951OptionGroupOptions m_option_group;1952};19531954// CommandObjectBreakpointName1955class CommandObjectBreakpointName : public CommandObjectMultiword {1956public:1957CommandObjectBreakpointName(CommandInterpreter &interpreter)1958: CommandObjectMultiword(1959interpreter, "name", "Commands to manage breakpoint names") {196019611962SetHelpLong(1963R"(1964Breakpoint names provide a general tagging mechanism for breakpoints. Each1965breakpoint name can be added to any number of breakpoints, and each breakpoint1966can have any number of breakpoint names attached to it. For instance:19671968(lldb) break name add -N MyName 1-1019691970adds the name MyName to breakpoints 1-10, and:19711972(lldb) break set -n myFunc -N Name1 -N Name219731974adds two names to the breakpoint set at myFunc.19751976They have a number of interrelated uses:197719781) They provide a stable way to refer to a breakpoint (e.g. in another1979breakpoint's action). Using the breakpoint ID for this purpose is fragile, since1980it depends on the order of breakpoint creation. Giving a name to the breakpoint1981you want to act on, and then referring to it by name, is more robust:19821983(lldb) break set -n myFunc -N BKPT11984(lldb) break set -n myOtherFunc -C "break disable BKPT1"198519862) This is actually just a specific use of a more general feature of breakpoint1987names. The <breakpt-id-list> argument type used to specify one or more1988breakpoints in most of the commands that deal with breakpoints also accepts1989breakpoint names. That allows you to refer to one breakpoint in a stable1990manner, but also makes them a convenient grouping mechanism, allowing you to1991easily act on a group of breakpoints by using their name, for instance disabling1992them all in one action:19931994(lldb) break set -n myFunc -N Group11995(lldb) break set -n myOtherFunc -N Group11996(lldb) break disable Group1199719983) But breakpoint names are also entities in their own right, and can be1999configured with all the modifiable attributes of a breakpoint. Then when you2000add a breakpoint name to a breakpoint, the breakpoint will be configured to2001match the state of the breakpoint name. The link between the name and the2002breakpoints sharing it remains live, so if you change the configuration on the2003name, it will also change the configurations on the breakpoints:20042005(lldb) break name configure -i 10 IgnoreSome2006(lldb) break set -n myFunc -N IgnoreSome2007(lldb) break list IgnoreSome20082: name = 'myFunc', locations = 0 (pending) Options: ignore: 10 enabled2009Names:2010IgnoreSome2011(lldb) break name configure -i 5 IgnoreSome2012(lldb) break list IgnoreSome20132: name = 'myFunc', locations = 0 (pending) Options: ignore: 5 enabled2014Names:2015IgnoreSome20162017Options that are not configured on a breakpoint name don't affect the value of2018those options on the breakpoints they are added to. So for instance, if Name12019has the -i option configured and Name2 the -c option, adding both names to a2020breakpoint will set the -i option from Name1 and the -c option from Name2, and2021the other options will be unaltered.20222023If you add multiple names to a breakpoint which have configured values for2024the same option, the last name added's value wins.20252026The "liveness" of these settings is one way, from name to breakpoint.2027If you use "break modify" to change an option that is also configured on a name2028which that breakpoint has, the "break modify" command will override the setting2029for that breakpoint, but won't change the value configured in the name or on the2030other breakpoints sharing that name.203120324) Breakpoint names are also a convenient way to copy option sets from one2033breakpoint to another. Using the -B option to "breakpoint name configure" makes2034a name configured with all the options of the original breakpoint. Then2035adding that name to another breakpoint copies over all the values from the2036original breakpoint to the new one.203720385) You can also use breakpoint names to hide breakpoints from the breakpoint2039operations that act on all breakpoints: "break delete", "break disable" and2040"break list". You do that by specifying a "false" value for the2041--allow-{list,delete,disable} options to "breakpoint name configure" and then2042adding that name to a breakpoint.20432044This won't keep the breakpoint from being deleted or disabled if you refer to it2045specifically by ID. The point of the feature is to make sure users don't2046inadvertently delete or disable useful breakpoints (e.g. ones an IDE is using2047for its own purposes) as part of a "delete all" or "disable all" operation. The2048list hiding is because it's confusing for people to see breakpoints they2049didn't set.20502051)");2052CommandObjectSP add_command_object(2053new CommandObjectBreakpointNameAdd(interpreter));2054CommandObjectSP delete_command_object(2055new CommandObjectBreakpointNameDelete(interpreter));2056CommandObjectSP list_command_object(2057new CommandObjectBreakpointNameList(interpreter));2058CommandObjectSP configure_command_object(2059new CommandObjectBreakpointNameConfigure(interpreter));20602061LoadSubCommand("add", add_command_object);2062LoadSubCommand("delete", delete_command_object);2063LoadSubCommand("list", list_command_object);2064LoadSubCommand("configure", configure_command_object);2065}20662067~CommandObjectBreakpointName() override = default;2068};20692070// CommandObjectBreakpointRead2071#pragma mark Read::CommandOptions2072#define LLDB_OPTIONS_breakpoint_read2073#include "CommandOptions.inc"20742075#pragma mark Read20762077class CommandObjectBreakpointRead : public CommandObjectParsed {2078public:2079CommandObjectBreakpointRead(CommandInterpreter &interpreter)2080: CommandObjectParsed(interpreter, "breakpoint read",2081"Read and set the breakpoints previously saved to "2082"a file with \"breakpoint write\". ",2083nullptr) {}20842085~CommandObjectBreakpointRead() override = default;20862087Options *GetOptions() override { return &m_options; }20882089class CommandOptions : public Options {2090public:2091CommandOptions() = default;20922093~CommandOptions() override = default;20942095Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,2096ExecutionContext *execution_context) override {2097Status error;2098const int short_option = m_getopt_table[option_idx].val;2099const char *long_option =2100m_getopt_table[option_idx].definition->long_option;21012102switch (short_option) {2103case 'f':2104m_filename.assign(std::string(option_arg));2105break;2106case 'N': {2107Status name_error;2108if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg),2109name_error)) {2110error = CreateOptionParsingError(option_arg, short_option,2111long_option, name_error.AsCString());2112}2113m_names.push_back(std::string(option_arg));2114break;2115}2116default:2117llvm_unreachable("Unimplemented option");2118}21192120return error;2121}21222123void OptionParsingStarting(ExecutionContext *execution_context) override {2124m_filename.clear();2125m_names.clear();2126}21272128llvm::ArrayRef<OptionDefinition> GetDefinitions() override {2129return llvm::ArrayRef(g_breakpoint_read_options);2130}21312132void HandleOptionArgumentCompletion(2133CompletionRequest &request, OptionElementVector &opt_element_vector,2134int opt_element_index, CommandInterpreter &interpreter) override {2135int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;2136int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;21372138switch (GetDefinitions()[opt_defs_index].short_option) {2139case 'f':2140lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(2141interpreter, lldb::eDiskFileCompletion, request, nullptr);2142break;21432144case 'N':2145std::optional<FileSpec> file_spec;2146const llvm::StringRef dash_f("-f");2147for (int arg_idx = 0; arg_idx < opt_arg_pos; arg_idx++) {2148if (dash_f == request.GetParsedLine().GetArgumentAtIndex(arg_idx)) {2149file_spec.emplace(2150request.GetParsedLine().GetArgumentAtIndex(arg_idx + 1));2151break;2152}2153}2154if (!file_spec)2155return;21562157FileSystem::Instance().Resolve(*file_spec);2158Status error;2159StructuredData::ObjectSP input_data_sp =2160StructuredData::ParseJSONFromFile(*file_spec, error);2161if (!error.Success())2162return;21632164StructuredData::Array *bkpt_array = input_data_sp->GetAsArray();2165if (!bkpt_array)2166return;21672168const size_t num_bkpts = bkpt_array->GetSize();2169for (size_t i = 0; i < num_bkpts; i++) {2170StructuredData::ObjectSP bkpt_object_sp =2171bkpt_array->GetItemAtIndex(i);2172if (!bkpt_object_sp)2173return;21742175StructuredData::Dictionary *bkpt_dict =2176bkpt_object_sp->GetAsDictionary();2177if (!bkpt_dict)2178return;21792180StructuredData::ObjectSP bkpt_data_sp =2181bkpt_dict->GetValueForKey(Breakpoint::GetSerializationKey());2182if (!bkpt_data_sp)2183return;21842185bkpt_dict = bkpt_data_sp->GetAsDictionary();2186if (!bkpt_dict)2187return;21882189StructuredData::Array *names_array;21902191if (!bkpt_dict->GetValueForKeyAsArray("Names", names_array))2192return;21932194size_t num_names = names_array->GetSize();21952196for (size_t i = 0; i < num_names; i++) {2197if (std::optional<llvm::StringRef> maybe_name =2198names_array->GetItemAtIndexAsString(i))2199request.TryCompleteCurrentArg(*maybe_name);2200}2201}2202}2203}22042205std::string m_filename;2206std::vector<std::string> m_names;2207};22082209protected:2210void DoExecute(Args &command, CommandReturnObject &result) override {2211Target &target = GetSelectedOrDummyTarget();22122213std::unique_lock<std::recursive_mutex> lock;2214target.GetBreakpointList().GetListMutex(lock);22152216FileSpec input_spec(m_options.m_filename);2217FileSystem::Instance().Resolve(input_spec);2218BreakpointIDList new_bps;2219Status error = target.CreateBreakpointsFromFile(input_spec,2220m_options.m_names, new_bps);22212222if (!error.Success()) {2223result.AppendError(error.AsCString());2224return;2225}22262227Stream &output_stream = result.GetOutputStream();22282229size_t num_breakpoints = new_bps.GetSize();2230if (num_breakpoints == 0) {2231result.AppendMessage("No breakpoints added.");2232} else {2233// No breakpoint selected; show info about all currently set breakpoints.2234result.AppendMessage("New breakpoints:");2235for (size_t i = 0; i < num_breakpoints; ++i) {2236BreakpointID bp_id = new_bps.GetBreakpointIDAtIndex(i);2237Breakpoint *bp = target.GetBreakpointList()2238.FindBreakpointByID(bp_id.GetBreakpointID())2239.get();2240if (bp)2241bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,2242false);2243}2244}2245}22462247private:2248CommandOptions m_options;2249};22502251// CommandObjectBreakpointWrite2252#pragma mark Write::CommandOptions2253#define LLDB_OPTIONS_breakpoint_write2254#include "CommandOptions.inc"22552256#pragma mark Write2257class CommandObjectBreakpointWrite : public CommandObjectParsed {2258public:2259CommandObjectBreakpointWrite(CommandInterpreter &interpreter)2260: CommandObjectParsed(interpreter, "breakpoint write",2261"Write the breakpoints listed to a file that can "2262"be read in with \"breakpoint read\". "2263"If given no arguments, writes all breakpoints.",2264nullptr) {2265CommandObject::AddIDsArgumentData(eBreakpointArgs);2266}22672268~CommandObjectBreakpointWrite() override = default;22692270void2271HandleArgumentCompletion(CompletionRequest &request,2272OptionElementVector &opt_element_vector) override {2273lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(2274GetCommandInterpreter(), lldb::eBreakpointCompletion, request, nullptr);2275}22762277Options *GetOptions() override { return &m_options; }22782279class CommandOptions : public Options {2280public:2281CommandOptions() = default;22822283~CommandOptions() override = default;22842285Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,2286ExecutionContext *execution_context) override {2287Status error;2288const int short_option = m_getopt_table[option_idx].val;22892290switch (short_option) {2291case 'f':2292m_filename.assign(std::string(option_arg));2293break;2294case 'a':2295m_append = true;2296break;2297default:2298llvm_unreachable("Unimplemented option");2299}23002301return error;2302}23032304void OptionParsingStarting(ExecutionContext *execution_context) override {2305m_filename.clear();2306m_append = false;2307}23082309llvm::ArrayRef<OptionDefinition> GetDefinitions() override {2310return llvm::ArrayRef(g_breakpoint_write_options);2311}23122313// Instance variables to hold the values for command options.23142315std::string m_filename;2316bool m_append = false;2317};23182319protected:2320void DoExecute(Args &command, CommandReturnObject &result) override {2321Target &target = GetSelectedOrDummyTarget();23222323std::unique_lock<std::recursive_mutex> lock;2324target.GetBreakpointList().GetListMutex(lock);23252326BreakpointIDList valid_bp_ids;2327if (!command.empty()) {2328CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(2329command, &target, result, &valid_bp_ids,2330BreakpointName::Permissions::PermissionKinds::listPerm);23312332if (!result.Succeeded()) {2333result.SetStatus(eReturnStatusFailed);2334return;2335}2336}2337FileSpec file_spec(m_options.m_filename);2338FileSystem::Instance().Resolve(file_spec);2339Status error = target.SerializeBreakpointsToFile(file_spec, valid_bp_ids,2340m_options.m_append);2341if (!error.Success()) {2342result.AppendErrorWithFormat("error serializing breakpoints: %s.",2343error.AsCString());2344}2345}23462347private:2348CommandOptions m_options;2349};23502351// CommandObjectMultiwordBreakpoint2352#pragma mark MultiwordBreakpoint23532354CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(2355CommandInterpreter &interpreter)2356: CommandObjectMultiword(2357interpreter, "breakpoint",2358"Commands for operating on breakpoints (see 'help b' for shorthand.)",2359"breakpoint <subcommand> [<command-options>]") {2360CommandObjectSP list_command_object(2361new CommandObjectBreakpointList(interpreter));2362CommandObjectSP enable_command_object(2363new CommandObjectBreakpointEnable(interpreter));2364CommandObjectSP disable_command_object(2365new CommandObjectBreakpointDisable(interpreter));2366CommandObjectSP clear_command_object(2367new CommandObjectBreakpointClear(interpreter));2368CommandObjectSP delete_command_object(2369new CommandObjectBreakpointDelete(interpreter));2370CommandObjectSP set_command_object(2371new CommandObjectBreakpointSet(interpreter));2372CommandObjectSP command_command_object(2373new CommandObjectBreakpointCommand(interpreter));2374CommandObjectSP modify_command_object(2375new CommandObjectBreakpointModify(interpreter));2376CommandObjectSP name_command_object(2377new CommandObjectBreakpointName(interpreter));2378CommandObjectSP write_command_object(2379new CommandObjectBreakpointWrite(interpreter));2380CommandObjectSP read_command_object(2381new CommandObjectBreakpointRead(interpreter));23822383list_command_object->SetCommandName("breakpoint list");2384enable_command_object->SetCommandName("breakpoint enable");2385disable_command_object->SetCommandName("breakpoint disable");2386clear_command_object->SetCommandName("breakpoint clear");2387delete_command_object->SetCommandName("breakpoint delete");2388set_command_object->SetCommandName("breakpoint set");2389command_command_object->SetCommandName("breakpoint command");2390modify_command_object->SetCommandName("breakpoint modify");2391name_command_object->SetCommandName("breakpoint name");2392write_command_object->SetCommandName("breakpoint write");2393read_command_object->SetCommandName("breakpoint read");23942395LoadSubCommand("list", list_command_object);2396LoadSubCommand("enable", enable_command_object);2397LoadSubCommand("disable", disable_command_object);2398LoadSubCommand("clear", clear_command_object);2399LoadSubCommand("delete", delete_command_object);2400LoadSubCommand("set", set_command_object);2401LoadSubCommand("command", command_command_object);2402LoadSubCommand("modify", modify_command_object);2403LoadSubCommand("name", name_command_object);2404LoadSubCommand("write", write_command_object);2405LoadSubCommand("read", read_command_object);2406}24072408CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default;24092410void CommandObjectMultiwordBreakpoint::VerifyIDs(2411Args &args, Target *target, bool allow_locations,2412CommandReturnObject &result, BreakpointIDList *valid_ids,2413BreakpointName::Permissions ::PermissionKinds purpose) {2414// args can be strings representing 1). integers (for breakpoint ids)2415// 2). the full breakpoint & location2416// canonical representation2417// 3). the word "to" or a hyphen,2418// representing a range (in which case there2419// had *better* be an entry both before &2420// after of one of the first two types.2421// 4). A breakpoint name2422// If args is empty, we will use the last created breakpoint (if there is2423// one.)24242425Args temp_args;24262427if (args.empty()) {2428if (target->GetLastCreatedBreakpoint()) {2429valid_ids->AddBreakpointID(BreakpointID(2430target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID));2431result.SetStatus(eReturnStatusSuccessFinishNoResult);2432} else {2433result.AppendError(2434"No breakpoint specified and no last created breakpoint.");2435}2436return;2437}24382439// Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff2440// directly from the old ARGS to the new TEMP_ARGS. Do not copy breakpoint2441// id range strings over; instead generate a list of strings for all the2442// breakpoint ids in the range, and shove all of those breakpoint id strings2443// into TEMP_ARGS.24442445if (llvm::Error err = BreakpointIDList::FindAndReplaceIDRanges(2446args, target, allow_locations, purpose, temp_args)) {2447result.SetError(std::move(err));2448return;2449}2450result.SetStatus(eReturnStatusSuccessFinishNoResult);24512452// NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual2453// BreakpointIDList:24542455for (llvm::StringRef temp_arg : temp_args.GetArgumentArrayRef())2456if (auto bp_id = BreakpointID::ParseCanonicalReference(temp_arg))2457valid_ids->AddBreakpointID(*bp_id);24582459// At this point, all of the breakpoint ids that the user passed in have2460// been converted to breakpoint IDs and put into valid_ids.24612462// Now that we've converted everything from args into a list of breakpoint2463// ids, go through our tentative list of breakpoint id's and verify that2464// they correspond to valid/currently set breakpoints.24652466const size_t count = valid_ids->GetSize();2467for (size_t i = 0; i < count; ++i) {2468BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex(i);2469Breakpoint *breakpoint =2470target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();2471if (breakpoint != nullptr) {2472const size_t num_locations = breakpoint->GetNumLocations();2473if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) {2474StreamString id_str;2475BreakpointID::GetCanonicalReference(2476&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());2477i = valid_ids->GetSize() + 1;2478result.AppendErrorWithFormat(2479"'%s' is not a currently valid breakpoint/location id.\n",2480id_str.GetData());2481}2482} else {2483i = valid_ids->GetSize() + 1;2484result.AppendErrorWithFormat(2485"'%d' is not a currently valid breakpoint ID.\n",2486cur_bp_id.GetBreakpointID());2487}2488}2489}249024912492