diff options
Diffstat (limited to 'lldb')
-rw-r--r-- | lldb/include/lldb/API/SBBreakpoint.h | 12 | ||||
-rw-r--r-- | lldb/include/lldb/Breakpoint/Breakpoint.h | 30 | ||||
-rw-r--r-- | lldb/include/lldb/Breakpoint/BreakpointID.h | 15 | ||||
-rw-r--r-- | lldb/include/lldb/Breakpoint/BreakpointIDList.h | 2 | ||||
-rw-r--r-- | lldb/include/lldb/lldb-enumerations.h | 1 | ||||
-rw-r--r-- | lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme | 9 | ||||
-rw-r--r-- | lldb/scripts/Python/interface/SBBreakpoint.i | 12 | ||||
-rw-r--r-- | lldb/source/API/SBBreakpoint.cpp | 78 | ||||
-rw-r--r-- | lldb/source/Breakpoint/Breakpoint.cpp | 34 | ||||
-rw-r--r-- | lldb/source/Breakpoint/BreakpointID.cpp | 17 | ||||
-rw-r--r-- | lldb/source/Breakpoint/BreakpointIDList.cpp | 44 | ||||
-rw-r--r-- | lldb/source/Breakpoint/BreakpointOptions.cpp | 3 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectBreakpoint.cpp | 439 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectBreakpoint.h | 14 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectBreakpointCommand.cpp | 6 | ||||
-rw-r--r-- | lldb/source/Interpreter/CommandObject.cpp | 17 |
16 files changed, 713 insertions, 20 deletions
diff --git a/lldb/include/lldb/API/SBBreakpoint.h b/lldb/include/lldb/API/SBBreakpoint.h index 86d49c29a82..20a97a1fb5a 100644 --- a/lldb/include/lldb/API/SBBreakpoint.h +++ b/lldb/include/lldb/API/SBBreakpoint.h @@ -123,6 +123,18 @@ public: SBError SetScriptCallbackBody (const char *script_body_text); + + bool + AddName (const char *new_name); + + void + RemoveName (const char *name_to_remove); + + bool + MatchesName (const char *name); + + void + GetNames (SBStringList &names); size_t GetNumResolvedLocations() const; diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h index 682369f7679..61acc061aeb 100644 --- a/lldb/include/lldb/Breakpoint/Breakpoint.h +++ b/lldb/include/lldb/Breakpoint/Breakpoint.h @@ -12,8 +12,11 @@ // C Includes // C++ Includes +#include <unordered_set> + // Other libraries and framework includes // Project includes +#include "lldb/Breakpoint/BreakpointID.h" #include "lldb/Breakpoint/BreakpointLocationList.h" #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Breakpoint/BreakpointLocationCollection.h" @@ -636,6 +639,32 @@ public: return m_filter_sp; } + bool + AddName (const char *new_name, Error &error); + + void + RemoveName (const char *name_to_remove) + { + if (name_to_remove) + m_name_list.erase(name_to_remove); + } + + bool + MatchesName (const char *name) + { + return m_name_list.find(name) != m_name_list.end(); + } + + void + GetNames (std::vector<std::string> &names) + { + names.clear(); + for (auto name : m_name_list) + { + names.push_back(name); + } + } + protected: friend class Target; //------------------------------------------------------------------ @@ -697,6 +726,7 @@ private: bool m_being_created; bool m_hardware; // If this breakpoint is required to use a hardware breakpoint Target &m_target; // The target that holds this breakpoint. + std::unordered_set<std::string> m_name_list; // If not empty, this is the name of this breakpoint (many breakpoints can share the same name.) lldb::SearchFilterSP m_filter_sp; // The filter that constrains the breakpoint's domain. lldb::BreakpointResolverSP m_resolver_sp; // The resolver that defines this breakpoint. BreakpointOptions m_options; // Settable breakpoint options diff --git a/lldb/include/lldb/Breakpoint/BreakpointID.h b/lldb/include/lldb/Breakpoint/BreakpointID.h index 9e352100b9e..5ca09634ee0 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointID.h +++ b/lldb/include/lldb/Breakpoint/BreakpointID.h @@ -93,6 +93,21 @@ public: //------------------------------------------------------------------ + /// Takes an input string and checks to see whether it is a breakpoint name. + /// If it is a mal-formed breakpoint name, error will be set to an appropriate + /// error string. + /// + /// @param[in] input + /// A string containing JUST the breakpoint description. + /// @param[out] error + /// If the name is a well-formed breakpoint name, set to success, otherwise set to an error. + /// @return + /// \b true if the name is a breakpoint name (as opposed to an ID or range) false otherwise. + //------------------------------------------------------------------ + static bool + StringIsBreakpointName (const char *name, Error &error); + + //------------------------------------------------------------------ /// Takes a breakpoint ID and the breakpoint location id and returns /// a string containing the canonical description for the breakpoint /// or breakpoint location. diff --git a/lldb/include/lldb/Breakpoint/BreakpointIDList.h b/lldb/include/lldb/Breakpoint/BreakpointIDList.h index c9fcef0a783..c4278706661 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointIDList.h +++ b/lldb/include/lldb/Breakpoint/BreakpointIDList.h @@ -68,7 +68,7 @@ public: StringContainsIDRangeExpression (const char *in_string, size_t *range_start_len, size_t *range_end_pos); static void - FindAndReplaceIDRanges (Args &old_args, Target *target, CommandReturnObject &result, Args &new_args); + FindAndReplaceIDRanges (Args &old_args, Target *target, bool allow_locations, CommandReturnObject &result, Args &new_args); private: BreakpointIDArray m_breakpoint_ids; diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index b6078cb007a..87ee1487573 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -420,6 +420,7 @@ namespace lldb { eArgTypeBoolean, eArgTypeBreakpointID, eArgTypeBreakpointIDRange, + eArgTypeBreakpointName, eArgTypeByteSize, eArgTypeClassName, eArgTypeCommandName, diff --git a/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme b/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme index a9d04f56f46..7784b75c783 100644 --- a/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme +++ b/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme @@ -84,14 +84,16 @@ <LaunchAction selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - launchStyle = "1" + launchStyle = "0" useCustomWorkingDirectory = "NO" customWorkingDirectory = "/Volumes/work/gclayton/Documents/devb/attach" buildConfiguration = "Debug" ignoresPersistentStateOnLaunch = "YES" debugDocumentVersioning = "YES" + debugServiceExtension = "internal" allowLocationSimulation = "YES"> - <BuildableProductRunnable> + <BuildableProductRunnable + runnableDebuggingMode = "0"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "26F5C26910F3D9A4009D5894" @@ -147,7 +149,8 @@ buildConfiguration = "Release" ignoresPersistentStateOnLaunch = "YES" debugDocumentVersioning = "YES"> - <BuildableProductRunnable> + <BuildableProductRunnable + runnableDebuggingMode = "0"> <BuildableReference BuildableIdentifier = "primary" BlueprintIdentifier = "26F5C26910F3D9A4009D5894" diff --git a/lldb/scripts/Python/interface/SBBreakpoint.i b/lldb/scripts/Python/interface/SBBreakpoint.i index 190c9b90dd6..61093c45237 100644 --- a/lldb/scripts/Python/interface/SBBreakpoint.i +++ b/lldb/scripts/Python/interface/SBBreakpoint.i @@ -200,6 +200,18 @@ public: SBError SetScriptCallbackBody (const char *script_body_text); + bool + AddName (const char *new_name); + + void + RemoveName (const char *name_to_remove); + + bool + MatchesName (const char *name); + + void + GetNames (SBStringList &names); + size_t GetNumResolvedLocations() const; diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index a950ca934c6..dd4c80caf45 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -13,6 +13,7 @@ #include "lldb/API/SBEvent.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" +#include "lldb/API/SBStringList.h" #include "lldb/API/SBThread.h" #include "lldb/Breakpoint/Breakpoint.h" @@ -653,6 +654,83 @@ SBBreakpoint::SetScriptCallbackBody (const char *callback_body_text) return sb_error; } +bool +SBBreakpoint::AddName (const char *new_name) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + if (log) + log->Printf ("SBBreakpoint(%p)::AddName (name=%s)", + static_cast<void*>(m_opaque_sp.get()), + new_name); + + if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex()); + Error error; // Think I'm just going to swallow the error here, it's probably more annoying to have to provide it. + return m_opaque_sp->AddName(new_name, error); + } + + return false; +} + +void +SBBreakpoint::RemoveName (const char *name_to_remove) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + if (log) + log->Printf ("SBBreakpoint(%p)::RemoveName (name=%s)", + static_cast<void*>(m_opaque_sp.get()), + name_to_remove); + + if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex()); + m_opaque_sp->RemoveName(name_to_remove); + } +} + +bool +SBBreakpoint::MatchesName (const char *name) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + if (log) + log->Printf ("SBBreakpoint(%p)::MatchesName (name=%s)", + static_cast<void*>(m_opaque_sp.get()), + name); + + if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex()); + return m_opaque_sp->MatchesName(name); + } + + return false; +} + +void +SBBreakpoint::GetNames (SBStringList &names) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + if (log) + log->Printf ("SBBreakpoint(%p)::GetNames ()", + static_cast<void*>(m_opaque_sp.get())); + + if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex()); + std::vector<std::string> names_vec; + m_opaque_sp->GetNames(names_vec); + for (std::string name : names_vec) + { + names.AppendString (name.c_str()); + } + } +} + lldb_private::Breakpoint * SBBreakpoint::operator->() const { diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp index 1a3a6b552ab..3916b72e775 100644 --- a/lldb/source/Breakpoint/Breakpoint.cpp +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -71,7 +71,8 @@ Breakpoint::Breakpoint (Target &new_target, Breakpoint &source_bp) : m_target(new_target), m_options (source_bp.m_options), m_locations(*this), - m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols) + m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols), + m_name_list (source_bp.m_name_list) { // Now go through and copy the filter & resolver: m_resolver_sp = source_bp.m_resolver_sp->CopyForBreakpoint(*this); @@ -782,6 +783,23 @@ Breakpoint::GetNumLocations() const return m_locations.GetSize(); } +bool +Breakpoint::AddName (const char *new_name, Error &error) +{ + if (!new_name) + return false; + if (!BreakpointID::StringIsBreakpointName(new_name, error)) + { + error.SetErrorStringWithFormat("input name \"%s\" not a breakpoint name.", new_name); + return false; + } + if (!error.Success()) + return false; + + m_name_list.insert(new_name); + return true; +} + void Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_locations) { @@ -832,6 +850,20 @@ Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_l if (level == lldb::eDescriptionLevelFull) { + if (!m_name_list.empty()) + { + s->EOL(); + s->Indent(); + s->Printf ("Names:"); + s->EOL(); + s->IndentMore(); + for (std::string name : m_name_list) + { + s->Indent(); + s->Printf("%s\n", name.c_str()); + } + s->IndentLess(); + } s->IndentLess(); s->EOL(); } diff --git a/lldb/source/Breakpoint/BreakpointID.cpp b/lldb/source/Breakpoint/BreakpointID.cpp index 9963ed68303..31823886dd9 100644 --- a/lldb/source/Breakpoint/BreakpointID.cpp +++ b/lldb/source/Breakpoint/BreakpointID.cpp @@ -18,6 +18,7 @@ #include "lldb/Breakpoint/BreakpointID.h" #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Core/Stream.h" +#include "lldb/Core/Error.h" using namespace lldb; using namespace lldb_private; @@ -121,3 +122,19 @@ BreakpointID::ParseCanonicalReference (const char *input, break_id_t *break_id_p return false; } +bool +BreakpointID::StringIsBreakpointName(const char *name, Error &error) +{ + error.Clear(); + + if (name && (name[0] >= 'A' && name[0] <= 'z')) + { + if (strcspn(name, ".- ") != strlen(name)) + { + error.SetErrorStringWithFormat("invalid breakpoint name: \"%s\"", name); + } + return true; + } + else + return false; +} diff --git a/lldb/source/Breakpoint/BreakpointIDList.cpp b/lldb/source/Breakpoint/BreakpointIDList.cpp index 24101b1442f..b8b506750b3 100644 --- a/lldb/source/Breakpoint/BreakpointIDList.cpp +++ b/lldb/source/Breakpoint/BreakpointIDList.cpp @@ -159,27 +159,52 @@ BreakpointIDList::InsertStringArray (const char **string_array, size_t array_siz // NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced by the members of the range. void -BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, CommandReturnObject &result, +BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, + Target *target, + bool allow_locations, + CommandReturnObject &result, Args &new_args) { std::string range_start; const char *range_end; const char *current_arg; const size_t num_old_args = old_args.GetArgumentCount(); + std::set<std::string> names_found; for (size_t i = 0; i < num_old_args; ++i) { bool is_range = false; + current_arg = old_args.GetArgumentAtIndex (i); + if (!allow_locations && strchr(current_arg, '.') != nullptr) + { + result.AppendErrorWithFormat ("Breakpoint locations not allowed, saw location: %s.", current_arg); + new_args.Clear(); + return; + } size_t range_start_len = 0; size_t range_end_pos = 0; + Error error; + if (BreakpointIDList::StringContainsIDRangeExpression (current_arg, &range_start_len, &range_end_pos)) { is_range = true; range_start.assign (current_arg, range_start_len); range_end = current_arg + range_end_pos; } + else if (BreakpointID::StringIsBreakpointName(current_arg, error)) + { + if (!error.Success()) + { + new_args.Clear(); + result.AppendError (error.AsCString()); + result.SetStatus (eReturnStatusFailed); + return; + } + else + names_found.insert(current_arg); + } else if ((i + 2 < num_old_args) && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1)) && BreakpointID::IsValidIDExpression (current_arg) @@ -342,6 +367,23 @@ BreakpointIDList::FindAndReplaceIDRanges (Args &old_args, Target *target, Comman } } + // Okay, now see if we found any names, and if we did, add them: + if (target && names_found.size()) + { + for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) + { + for (std::string name : names_found) + { + if (bkpt_sp->MatchesName(name.c_str())) + { + StreamString canonical_id_str; + BreakpointID::GetCanonicalReference (&canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID); + new_args.AppendArgument (canonical_id_str.GetData()); + } + } + } + } + result.SetStatus (eReturnStatusSuccessFinishNoResult); return; } diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp index ea8556d0930..db76ffb8685 100644 --- a/lldb/source/Breakpoint/BreakpointOptions.cpp +++ b/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -237,8 +237,7 @@ BreakpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) cons if (m_thread_spec_ap.get()) m_thread_spec_ap->GetDescription (s, level); - else if (level == eDescriptionLevelBrief) - s->PutCString ("thread spec: no "); + if (level == lldb::eDescriptionLevelFull) { s->IndentLess(); diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index 69aa8bf6a48..6b9db6ae85e 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -20,6 +20,8 @@ #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Interpreter/Options.h" +#include "lldb/Interpreter/OptionValueString.h" +#include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/StreamString.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -240,6 +242,13 @@ public: m_func_name_type_mask |= eFunctionNameTypeAuto; break; + case 'N': + if (BreakpointID::StringIsBreakpointName(option_arg, error)) + m_breakpoint_names.push_back (option_arg); + else + error.SetErrorStringWithFormat(error.AsCString()); + break; + case 'o': m_one_shot = true; break; @@ -329,6 +338,7 @@ public: m_skip_prologue = eLazyBoolCalculate; m_one_shot = false; m_use_dummy = false; + m_breakpoint_names.clear(); } const OptionDefinition* @@ -348,6 +358,7 @@ public: uint32_t m_line_num; uint32_t m_column; std::vector<std::string> m_func_names; + std::vector<std::string> m_breakpoint_names; uint32_t m_func_name_type_mask; std::string m_func_regexp; std::string m_source_text_regexp; @@ -558,6 +569,13 @@ protected: if (!m_options.m_condition.empty()) bp->GetOptions()->SetCondition(m_options.m_condition.c_str()); + + if (!m_options.m_breakpoint_names.empty()) + { + Error error; // We don't need to check the error here, since the option parser checked it... + for (auto name : m_options.m_breakpoint_names) + bp->AddName(name.c_str(), error); + } bp->SetOneShot (m_options.m_one_shot); } @@ -719,6 +737,9 @@ CommandObjectBreakpointSet::CommandOptions::g_option_table[] = { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, + { LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointName, + "Adds this to the list of names for this breakopint."}, + { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -954,7 +975,7 @@ protected: BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -1106,7 +1127,7 @@ protected: { // Particular breakpoint selected; enable that breakpoint. BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -1226,7 +1247,7 @@ protected: // Particular breakpoint selected; disable that breakpoint. BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -1419,7 +1440,7 @@ protected: { // Particular breakpoints selected; show info about that breakpoint. BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -1806,7 +1827,7 @@ protected: { // Particular breakpoint selected; disable that breakpoint. BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -1861,6 +1882,401 @@ CommandObjectBreakpointDelete::CommandOptions::g_option_table[] = }; //------------------------------------------------------------------------- +// CommandObjectBreakpointName +//------------------------------------------------------------------------- + +static OptionDefinition +g_breakpoint_name_options[] = +{ + { LLDB_OPT_SET_1, false, "name", 'N', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."}, + { LLDB_OPT_SET_2, false, "breakpoint-id", 'B', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBreakpointID, "Specify a breakpoint id to use."}, + { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, + "Operate on Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, +}; +class BreakpointNameOptionGroup : public OptionGroup +{ +public: + BreakpointNameOptionGroup() : + OptionGroup(), + m_breakpoint(LLDB_INVALID_BREAK_ID), + m_use_dummy (false) + { + + } + + virtual + ~BreakpointNameOptionGroup () + { + } + + virtual uint32_t + GetNumDefinitions () + { + return sizeof (g_breakpoint_name_options) / sizeof (OptionDefinition); + } + + virtual const OptionDefinition* + GetDefinitions () + { + return g_breakpoint_name_options; + } + + virtual Error + SetOptionValue (CommandInterpreter &interpreter, + uint32_t option_idx, + const char *option_value) + { + Error error; + const int short_option = g_breakpoint_name_options[option_idx].short_option; + + switch (short_option) + { + case 'N': + if (BreakpointID::StringIsBreakpointName(option_value, error) && error.Success()) + m_name.SetValueFromCString(option_value); + break; + + case 'B': + if (m_breakpoint.SetValueFromCString(option_value).Fail()) + error.SetErrorStringWithFormat ("unrecognized value \"%s\" for breakpoint", option_value); + break; + case 'D': + if (m_use_dummy.SetValueFromCString(option_value).Fail()) + error.SetErrorStringWithFormat ("unrecognized value \"%s\" for use-dummy", option_value); + break; + + default: + error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); + break; + } + return error; + } + + virtual void + OptionParsingStarting (CommandInterpreter &interpreter) + { + m_name.Clear(); + m_breakpoint.Clear(); + m_use_dummy.Clear(); + m_use_dummy.SetDefaultValue(false); + } + + OptionValueString m_name; + OptionValueUInt64 m_breakpoint; + OptionValueBoolean m_use_dummy; +}; + + +class CommandObjectBreakpointNameAdd : public CommandObjectParsed +{ +public: + CommandObjectBreakpointNameAdd (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "add", + "Add a name to the breakpoints provided.", + "breakpoint name add <command-options> <breakpoint-id-list>"), + m_name_options(), + m_option_group(interpreter) + { + // Create the first variant for the first (and only) argument for this command. + CommandArgumentEntry arg1; + CommandArgumentData id_arg; + id_arg.arg_type = eArgTypeBreakpointID; + id_arg.arg_repetition = eArgRepeatOptional; + arg1.push_back(id_arg); + m_arguments.push_back (arg1); + + m_option_group.Append (&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); + m_option_group.Finalize(); + } + + virtual + ~CommandObjectBreakpointNameAdd () {} + + Options * + GetOptions () + { + return &m_option_group; + } + +protected: + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + if (!m_name_options.m_name.OptionWasSet()) + { + result.SetError("No name option provided."); + return false; + } + + Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); + + if (target == NULL) + { + result.AppendError ("Invalid target. No existing target or breakpoints."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + Mutex::Locker locker; + target->GetBreakpointList().GetListMutex(locker); + + const BreakpointList &breakpoints = target->GetBreakpointList(); + + size_t num_breakpoints = breakpoints.GetSize(); + if (num_breakpoints == 0) + { + result.SetError("No breakpoints, cannot add names."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + // Particular breakpoint selected; disable that breakpoint. + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + if (valid_bp_ids.GetSize() == 0) + { + result.SetError("No breakpoints specified, cannot add names."); + result.SetStatus (eReturnStatusFailed); + return false; + } + size_t num_valid_ids = valid_bp_ids.GetSize(); + for (size_t index = 0; index < num_valid_ids; index++) + { + lldb::break_id_t bp_id = valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); + BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); + Error error; // We don't need to check the error here, since the option parser checked it... + bp_sp->AddName(m_name_options.m_name.GetCurrentValue(), error); + } + } + + return true; + } + +private: + BreakpointNameOptionGroup m_name_options; + OptionGroupOptions m_option_group; +}; + + + +class CommandObjectBreakpointNameDelete : public CommandObjectParsed +{ +public: + CommandObjectBreakpointNameDelete (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "delete", + "Delete a name from the breakpoints provided.", + "breakpoint name delete <command-options> <breakpoint-id-list>"), + m_name_options(), + m_option_group(interpreter) + { + // Create the first variant for the first (and only) argument for this command. + CommandArgumentEntry arg1; + CommandArgumentData id_arg; + id_arg.arg_type = eArgTypeBreakpointID; + id_arg.arg_repetition = eArgRepeatOptional; + arg1.push_back(id_arg); + m_arguments.push_back (arg1); + + m_option_group.Append (&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); + m_option_group.Finalize(); + } + + virtual + ~CommandObjectBreakpointNameDelete () {} + + Options * + GetOptions () + { + return &m_option_group; + } + +protected: + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + if (!m_name_options.m_name.OptionWasSet()) + { + result.SetError("No name option provided."); + return false; + } + + Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); + + if (target == NULL) + { + result.AppendError ("Invalid target. No existing target or breakpoints."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + Mutex::Locker locker; + target->GetBreakpointList().GetListMutex(locker); + + const BreakpointList &breakpoints = target->GetBreakpointList(); + + size_t num_breakpoints = breakpoints.GetSize(); + if (num_breakpoints == 0) + { + result.SetError("No breakpoints, cannot delete names."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + // Particular breakpoint selected; disable that breakpoint. + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + if (valid_bp_ids.GetSize() == 0) + { + result.SetError("No breakpoints specified, cannot delete names."); + result.SetStatus (eReturnStatusFailed); + return false; + } + size_t num_valid_ids = valid_bp_ids.GetSize(); + for (size_t index = 0; index < num_valid_ids; index++) + { + lldb::break_id_t bp_id = valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); + BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); + bp_sp->RemoveName(m_name_options.m_name.GetCurrentValue()); + } + } + + return true; + } + +private: + BreakpointNameOptionGroup m_name_options; + OptionGroupOptions m_option_group; +}; + +class CommandObjectBreakpointNameList : public CommandObjectParsed +{ +public: + CommandObjectBreakpointNameList (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "list", + "List either the names for a breakpoint or the breakpoints for a given name.", + "breakpoint name list <command-options>"), + m_name_options(), + m_option_group(interpreter) + { + m_option_group.Append (&m_name_options); + m_option_group.Finalize(); + } + + virtual + ~CommandObjectBreakpointNameList () {} + + Options * + GetOptions () + { + return &m_option_group; + } + +protected: +protected: + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + Target *target = GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); + + if (target == NULL) + { + result.AppendError ("Invalid target. No existing target or breakpoints."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (m_name_options.m_name.OptionWasSet()) + { + const char *name = m_name_options.m_name.GetCurrentValue(); + Mutex::Locker locker; + target->GetBreakpointList().GetListMutex(locker); + + BreakpointList &breakpoints = target->GetBreakpointList(); + for (BreakpointSP bp_sp : breakpoints.Breakpoints()) + { + if (bp_sp->MatchesName(name)) + { + StreamString s; + bp_sp->GetDescription(&s, eDescriptionLevelBrief); + s.EOL(); + result.AppendMessage(s.GetData()); + } + } + + } + else if (m_name_options.m_breakpoint.OptionWasSet()) + { + BreakpointSP bp_sp = target->GetBreakpointList().FindBreakpointByID(m_name_options.m_breakpoint.GetCurrentValue()); + if (bp_sp) + { + std::vector<std::string> names; + bp_sp->GetNames (names); + result.AppendMessage ("Names:"); + for (auto name : names) + result.AppendMessageWithFormat (" %s\n", name.c_str()); + } + else + { + result.AppendErrorWithFormat ("Could not find breakpoint %" PRId64 ".\n", + m_name_options.m_breakpoint.GetCurrentValue()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + result.SetError ("Must specify -N or -B option to list."); + result.SetStatus (eReturnStatusFailed); + return false; + } + return true; + } + +private: + BreakpointNameOptionGroup m_name_options; + OptionGroupOptions m_option_group; +}; + +//------------------------------------------------------------------------- +// CommandObjectMultiwordBreakpoint +//------------------------------------------------------------------------- +class CommandObjectBreakpointName : public CommandObjectMultiword +{ +public: + CommandObjectBreakpointName (CommandInterpreter &interpreter) : + CommandObjectMultiword(interpreter, + "name", + "A set of commands to manage name tags for breakpoints", + "breakpoint name <command> [<command-options>]") + { + CommandObjectSP add_command_object (new CommandObjectBreakpointNameAdd (interpreter)); + CommandObjectSP delete_command_object (new CommandObjectBreakpointNameDelete (interpreter)); + CommandObjectSP list_command_object (new CommandObjectBreakpointNameList (interpreter)); + + LoadSubCommand ("add", add_command_object); + LoadSubCommand ("delete", delete_command_object); + LoadSubCommand ("list", list_command_object); + + } + + virtual + ~CommandObjectBreakpointName () + { + } + +}; + + +//------------------------------------------------------------------------- // CommandObjectMultiwordBreakpoint //------------------------------------------------------------------------- #pragma mark MultiwordBreakpoint @@ -1879,6 +2295,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter CommandObjectSP set_command_object (new CommandObjectBreakpointSet (interpreter)); CommandObjectSP command_command_object (new CommandObjectBreakpointCommand (interpreter)); CommandObjectSP modify_command_object (new CommandObjectBreakpointModify(interpreter)); + CommandObjectSP name_command_object (new CommandObjectBreakpointName(interpreter)); list_command_object->SetCommandName ("breakpoint list"); enable_command_object->SetCommandName("breakpoint enable"); @@ -1888,6 +2305,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter set_command_object->SetCommandName("breakpoint set"); command_command_object->SetCommandName ("breakpoint command"); modify_command_object->SetCommandName ("breakpoint modify"); + name_command_object->SetCommandName ("breakpoint name"); LoadSubCommand ("list", list_command_object); LoadSubCommand ("enable", enable_command_object); @@ -1897,6 +2315,7 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInter LoadSubCommand ("set", set_command_object); LoadSubCommand ("command", command_command_object); LoadSubCommand ("modify", modify_command_object); + LoadSubCommand ("name", name_command_object); } CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint () @@ -1904,13 +2323,17 @@ CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint () } void -CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, - BreakpointIDList *valid_ids) +CommandObjectMultiwordBreakpoint::VerifyIDs (Args &args, + Target *target, + bool allow_locations, + CommandReturnObject &result, + BreakpointIDList *valid_ids) { // args can be strings representing 1). integers (for breakpoint ids) // 2). the full breakpoint & location canonical representation // 3). the word "to" or a hyphen, representing a range (in which case there // had *better* be an entry both before & after of one of the first two types. + // 4). A breakpoint name // If args is empty, we will use the last created breakpoint (if there is one.) Args temp_args; @@ -1934,7 +2357,7 @@ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *targe // the new TEMP_ARGS. Do not copy breakpoint id range strings over; instead generate a list of strings for // all the breakpoint ids in the range, and shove all of those breakpoint id strings into TEMP_ARGS. - BreakpointIDList::FindAndReplaceIDRanges (args, target, result, temp_args); + BreakpointIDList::FindAndReplaceIDRanges (args, target, allow_locations, result, temp_args); // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual BreakpointIDList: diff --git a/lldb/source/Commands/CommandObjectBreakpoint.h b/lldb/source/Commands/CommandObjectBreakpoint.h index 2d674b22d70..3fdd2a5f56b 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.h +++ b/lldb/source/Commands/CommandObjectBreakpoint.h @@ -38,8 +38,20 @@ public: ~CommandObjectMultiwordBreakpoint (); static void - VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids); + VerifyBreakpointOrLocationIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids) + { + VerifyIDs (args, target, true, result, valid_ids); + } + static void + VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids) + { + VerifyIDs (args, target, false, result, valid_ids); + } + +private: + static void + VerifyIDs (Args &args, Target *target, bool allow_locations, CommandReturnObject &result, BreakpointIDList *valid_ids); }; } // namespace lldb_private diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index ded03c532ce..8f8404b712a 100644 --- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -467,7 +467,7 @@ protected: } BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); m_bp_options_vec.clear(); @@ -714,7 +714,7 @@ protected: } BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { @@ -824,7 +824,7 @@ protected: } BreakpointIDList valid_bp_ids; - CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs (command, target, result, &valid_bp_ids); if (result.Succeeded()) { diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp index 0096541d741..753e720b0f6 100644 --- a/lldb/source/Interpreter/CommandObject.cpp +++ b/lldb/source/Interpreter/CommandObject.cpp @@ -748,6 +748,22 @@ BreakpointIDRangeHelpTextCallback () } static const char * +BreakpointNameHelpTextCallback () +{ + return "A name that can be added to a breakpoint when it is created, or later " + "on with the \"breakpoint name add\" command. " + "Breakpoint names can be used to specify breakpoints in all the places breakpoint ID's " + "and breakpoint ID ranges can be used. As such they provide a convenient way to group breakpoints, " + "and to operate on breakpoints you create without having to track the breakpoint number. " + "Note, the attributes you set when using a breakpoint name in a breakpoint command don't " + "adhere to the name, but instead are set individually on all the breakpoints currently tagged with that name. Future breakpoints " + "tagged with that name will not pick up the attributes previously given using that name. " + "In order to distinguish breakpoint names from breakpoint ID's and ranges, " + "names must start with a letter from a-z or A-Z and cannot contain spaces, \".\" or \"-\". " + "Also, breakpoint names can only be applied to breakpoints, not to breakpoint locations."; +} + +static const char * GDBFormatHelpTextCallback () { return "A GDB format consists of a repeat count, a format letter and a size letter. " @@ -1112,6 +1128,7 @@ CommandObject::g_arguments_data[] = { eArgTypeBoolean, "boolean", CommandCompletions::eNoCompletion, { nullptr, false }, "A Boolean value: 'true' or 'false'" }, { eArgTypeBreakpointID, "breakpt-id", CommandCompletions::eNoCompletion, { BreakpointIDHelpTextCallback, false }, nullptr }, { eArgTypeBreakpointIDRange, "breakpt-id-list", CommandCompletions::eNoCompletion, { BreakpointIDRangeHelpTextCallback, false }, nullptr }, + { eArgTypeBreakpointName, "breakpoint-name", CommandCompletions::eNoCompletion, { BreakpointNameHelpTextCallback, false }, nullptr }, { eArgTypeByteSize, "byte-size", CommandCompletions::eNoCompletion, { nullptr, false }, "Number of bytes to use." }, { eArgTypeClassName, "class-name", CommandCompletions::eNoCompletion, { nullptr, false }, "Then name of a class from the debug information in the program." }, { eArgTypeCommandName, "cmd-name", CommandCompletions::eNoCompletion, { nullptr, false }, "A debugger command (may be multiple words), without any options or arguments." }, |