diff --git a/lldb/include/lldb/API/LLDB.h b/lldb/include/lldb/API/LLDB.h index 3638c63a1657..c51ced893d7a 100644 --- a/lldb/include/lldb/API/LLDB.h +++ b/lldb/include/lldb/API/LLDB.h @@ -18,6 +18,7 @@ #include "lldb/API/SBAttachInfo.h" #include "lldb/API/SBBlock.h" #include "lldb/API/SBBreakpoint.h" +#include "lldb/API/SBBreakpointName.h" #include "lldb/API/SBBreakpointLocation.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandInterpreter.h" diff --git a/lldb/include/lldb/API/SBBreakpoint.h b/lldb/include/lldb/API/SBBreakpoint.h index bdf2f650b522..216d675b9d22 100644 --- a/lldb/include/lldb/API/SBBreakpoint.h +++ b/lldb/include/lldb/API/SBBreakpoint.h @@ -18,9 +18,6 @@ namespace lldb { class LLDB_API SBBreakpoint { public: - typedef bool (*BreakpointHitCallback)(void *baton, SBProcess &process, - SBThread &thread, - lldb::SBBreakpointLocation &location); SBBreakpoint(); @@ -90,7 +87,7 @@ public: const char *GetQueueName() const; - void SetCallback(BreakpointHitCallback callback, void *baton); + void SetCallback(SBBreakpointHitCallback callback, void *baton); void SetScriptCallbackFunction(const char *callback_function_name); @@ -133,14 +130,11 @@ public: private: friend class SBBreakpointList; friend class SBBreakpointLocation; + friend class SBBreakpointName; friend class SBTarget; SBBreakpoint(const lldb::BreakpointSP &bp_sp); - static bool PrivateBreakpointHitCallback( - void *baton, lldb_private::StoppointCallbackContext *context, - lldb::user_id_t break_id, lldb::user_id_t break_loc_id); - lldb::BreakpointSP GetSP() const; lldb::BreakpointWP m_opaque_wp; diff --git a/lldb/include/lldb/API/SBBreakpointLocation.h b/lldb/include/lldb/API/SBBreakpointLocation.h index 5b942f362ea1..4b34bcbf1f28 100644 --- a/lldb/include/lldb/API/SBBreakpointLocation.h +++ b/lldb/include/lldb/API/SBBreakpointLocation.h @@ -86,6 +86,7 @@ public: private: friend class SBBreakpoint; + friend class SBBreakpointCallbackBaton; void SetLocation(const lldb::BreakpointLocationSP &break_loc_sp); BreakpointLocationSP GetSP() const; diff --git a/lldb/include/lldb/API/SBBreakpointName.h b/lldb/include/lldb/API/SBBreakpointName.h new file mode 100644 index 000000000000..34d7db0d7dad --- /dev/null +++ b/lldb/include/lldb/API/SBBreakpointName.h @@ -0,0 +1,115 @@ +//===-- SBBreakpointName.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBBreakpointName_h_ +#define LLDB_SBBreakpointName_h_ + +#include "lldb/API/SBDefines.h" + +class SBBreakpointNameImpl; + +namespace lldb { + +class LLDB_API SBBreakpointName { +public: +// typedef bool (*BreakpointHitCallback)(void *baton, SBProcess &process, +// SBThread &thread, +// lldb::SBBreakpointLocation &location); + + SBBreakpointName(); + + SBBreakpointName(SBTarget &target, const char *name); + + SBBreakpointName(SBBreakpoint &bkpt, const char *name); + + SBBreakpointName(const lldb::SBBreakpointName &rhs); + + ~SBBreakpointName(); + + const lldb::SBBreakpointName &operator=(const lldb::SBBreakpointName &rhs); + + // Tests to see if the opaque breakpoint object in this object matches the + // opaque breakpoint object in "rhs". + bool operator==(const lldb::SBBreakpointName &rhs); + + bool operator!=(const lldb::SBBreakpointName &rhs); + + bool IsValid() const; + + const char *GetName() const; + + void SetEnabled(bool enable); + + bool IsEnabled(); + + void SetOneShot(bool one_shot); + + bool IsOneShot() const; + + void SetIgnoreCount(uint32_t count); + + uint32_t GetIgnoreCount() const; + + void SetCondition(const char *condition); + + const char *GetCondition(); + + void SetAutoContinue(bool auto_continue); + + bool GetAutoContinue(); + + void SetThreadID(lldb::tid_t sb_thread_id); + + lldb::tid_t GetThreadID(); + + void SetThreadIndex(uint32_t index); + + uint32_t GetThreadIndex() const; + + void SetThreadName(const char *thread_name); + + const char *GetThreadName() const; + + void SetQueueName(const char *queue_name); + + const char *GetQueueName() const; + + void SetCallback(SBBreakpointHitCallback callback, void *baton); + + void SetScriptCallbackFunction(const char *callback_function_name); + + void SetCommandLineCommands(SBStringList &commands); + + bool GetCommandLineCommands(SBStringList &commands); + + SBError SetScriptCallbackBody(const char *script_body_text); + + bool GetAllowList() const; + void SetAllowList(bool value); + + bool GetAllowDelete(); + void SetAllowDelete(bool value); + + bool GetAllowDisable(); + void SetAllowDisable(bool value); + + bool GetDescription(lldb::SBStream &description); + +private: + friend class SBTarget; + + lldb_private::BreakpointName *GetBreakpointName() const; + void UpdateName(lldb_private::BreakpointName &bp_name); + + std::unique_ptr m_impl_up; +}; + +} // namespace lldb + +#endif // LLDB_SBBreakpointName_h_ diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h index 28088b1b36ba..8379a6911afc 100644 --- a/lldb/include/lldb/API/SBDebugger.h +++ b/lldb/include/lldb/API/SBDebugger.h @@ -109,6 +109,8 @@ public: const char *archname); lldb::SBTarget CreateTarget(const char *filename); + + lldb::SBTarget GetDummyTarget(); // Return true if target is deleted from the target list of the debugger. bool DeleteTarget(lldb::SBTarget &target); diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h index 6c545ee20619..ec92c9196737 100644 --- a/lldb/include/lldb/API/SBDefines.h +++ b/lldb/include/lldb/API/SBDefines.h @@ -32,6 +32,8 @@ class LLDB_API SBAddress; class LLDB_API SBBlock; class LLDB_API SBBreakpoint; class LLDB_API SBBreakpointLocation; +class LLDB_API SBBreakpointName; +class LLDB_API SBBreakpointNameImpl; class LLDB_API SBBroadcaster; class LLDB_API SBCommand; class LLDB_API SBCommandInterpreter; @@ -99,6 +101,10 @@ class LLDB_API SBValueList; class LLDB_API SBVariablesOptions; class LLDB_API SBWatchpoint; class LLDB_API SBUnixSignals; + +typedef bool (*SBBreakpointHitCallback)(void *baton, SBProcess &process, + SBThread &thread, + lldb::SBBreakpointLocation &location); } #endif // LLDB_SBDefines_h_ diff --git a/lldb/include/lldb/API/SBError.h b/lldb/include/lldb/API/SBError.h index a099a9be271a..a27d2d042690 100644 --- a/lldb/include/lldb/API/SBError.h +++ b/lldb/include/lldb/API/SBError.h @@ -67,6 +67,7 @@ protected: friend class SBWatchpoint; friend class SBBreakpoint; friend class SBBreakpointLocation; + friend class SBBreakpointName; lldb_private::Status *get(); diff --git a/lldb/include/lldb/API/SBStream.h b/lldb/include/lldb/API/SBStream.h index 68fcae21c08e..a75afc7ee375 100644 --- a/lldb/include/lldb/API/SBStream.h +++ b/lldb/include/lldb/API/SBStream.h @@ -53,6 +53,7 @@ protected: friend class SBBlock; friend class SBBreakpoint; friend class SBBreakpointLocation; + friend class SBBreakpointName; friend class SBCommandReturnObject; friend class SBCompileUnit; friend class SBData; diff --git a/lldb/include/lldb/API/SBStringList.h b/lldb/include/lldb/API/SBStringList.h index c50594db07f6..943384e544cd 100644 --- a/lldb/include/lldb/API/SBStringList.h +++ b/lldb/include/lldb/API/SBStringList.h @@ -45,6 +45,7 @@ protected: friend class SBDebugger; friend class SBBreakpoint; friend class SBBreakpointLocation; + friend class SBBreakpointName; SBStringList(const lldb_private::StringList *lldb_strings); diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 1ea963818848..4085a16b43fb 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -716,6 +716,10 @@ public: // Finds all breakpoints by name, returning the list in bkpt_list. Returns // false if the name is not a valid breakpoint name, true otherwise. bool FindBreakpointsByName(const char *name, SBBreakpointList &bkpt_list); + + void GetBreakpointNames(SBStringList &names); + + void DeleteBreakpointName(const char *name); bool EnableAllBreakpoints(); @@ -810,6 +814,7 @@ protected: friend class SBAddress; friend class SBBlock; friend class SBBreakpointList; + friend class SBBreakpointNameImpl; friend class SBDebugger; friend class SBExecutionContext; friend class SBFunction; diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h index 502e5c973ef5..7f1cf10cc456 100644 --- a/lldb/include/lldb/API/SBThread.h +++ b/lldb/include/lldb/API/SBThread.h @@ -196,6 +196,7 @@ public: protected: friend class SBBreakpoint; friend class SBBreakpointLocation; + friend class SBBreakpointCallbackBaton; friend class SBExecutionContext; friend class SBFrame; friend class SBProcess; diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h index 6deaeaad2b94..9a798090a59f 100644 --- a/lldb/include/lldb/Breakpoint/Breakpoint.h +++ b/lldb/include/lldb/Breakpoint/Breakpoint.h @@ -22,6 +22,7 @@ #include "lldb/Breakpoint/BreakpointID.h" #include "lldb/Breakpoint/BreakpointLocationCollection.h" #include "lldb/Breakpoint/BreakpointLocationList.h" +#include "lldb/Breakpoint/BreakpointName.h" #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Breakpoint/Stoppoint.h" #include "lldb/Core/Event.h" @@ -602,6 +603,16 @@ public: //------------------------------------------------------------------ BreakpointOptions *GetOptions(); + //------------------------------------------------------------------ + /// Returns the BreakpointOptions structure set at the breakpoint level. + /// + /// Meant to be used by the BreakpointLocation class. + /// + /// @return + /// A pointer to this breakpoint's BreakpointOptions. + //------------------------------------------------------------------ + const BreakpointOptions *GetOptions() const; + //------------------------------------------------------------------ /// Invoke the callback action when the breakpoint is hit. /// @@ -625,13 +636,16 @@ public: lldb::SearchFilterSP GetSearchFilter() { return m_filter_sp; } - bool AddName(llvm::StringRef new_name, Status &error); +private: // The target needs to manage adding & removing names. It will do the + // checking for name validity as well. + bool AddName(llvm::StringRef new_name); void RemoveName(const char *name_to_remove) { if (name_to_remove) m_name_list.erase(name_to_remove); } - + +public: bool MatchesName(const char *name) { return m_name_list.find(name) != m_name_list.end(); } @@ -663,6 +677,25 @@ public: bool EvaluatePrecondition(StoppointCallbackContext &context); BreakpointPreconditionSP GetPrecondition() { return m_precondition_sp; } + + // Produces the OR'ed values for all the names assigned to this breakpoint. + const BreakpointName::Permissions &GetPermissions() const { + return m_permissions; + } + + BreakpointName::Permissions &GetPermissions() { + return m_permissions; + } + + bool AllowList() const { + return GetPermissions().GetAllowList(); + } + bool AllowDisable() const { + return GetPermissions().GetAllowDisable(); + } + bool AllowDelete() const { + return GetPermissions().GetAllowDelete(); + } protected: friend class Target; @@ -762,6 +795,7 @@ private: // hit. This is kept // separately from the locations hit counts, since locations can go away when // their backing library gets unloaded, and we would lose hit counts. + BreakpointName::Permissions m_permissions; void SendBreakpointChangedEvent(lldb::BreakpointEventType eventKind); diff --git a/lldb/include/lldb/Breakpoint/BreakpointIDList.h b/lldb/include/lldb/Breakpoint/BreakpointIDList.h index 34cfbfe3268d..5877b6c551ad 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointIDList.h +++ b/lldb/include/lldb/Breakpoint/BreakpointIDList.h @@ -18,7 +18,9 @@ // Other libraries and framework includes // Project includes +#include "lldb/lldb-enumerations.h" #include "lldb/Breakpoint/BreakpointID.h" +#include "lldb/Breakpoint/BreakpointName.h" #include "lldb/lldb-private.h" namespace lldb_private { @@ -64,6 +66,8 @@ public: static void FindAndReplaceIDRanges(Args &old_args, Target *target, bool allow_locations, + BreakpointName::Permissions + ::PermissionKinds purpose, CommandReturnObject &result, Args &new_args); diff --git a/lldb/include/lldb/Breakpoint/BreakpointList.h b/lldb/include/lldb/Breakpoint/BreakpointList.h index 2865288acc59..9f38f8aa120d 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointList.h +++ b/lldb/include/lldb/Breakpoint/BreakpointList.h @@ -154,11 +154,20 @@ public: void SetEnabledAll(bool enabled); + void SetEnabledAllowed(bool enabled); + //------------------------------------------------------------------ /// Removes all the breakpoints from this list. //------------------------------------------------------------------ void RemoveAll(bool notify); + //------------------------------------------------------------------ + /// Removes all the breakpoints from this list - first checking the + /// ePermDelete on the breakpoints. This call should be used unless you + /// are shutting down and need to actually clear them all. + //------------------------------------------------------------------ + void RemoveAllowed(bool notify); + //------------------------------------------------------------------ /// Tell all the breakpoints to update themselves due to a change in the /// modules in \a module_list. \a added says whether the module was loaded diff --git a/lldb/include/lldb/Breakpoint/BreakpointName.h b/lldb/include/lldb/Breakpoint/BreakpointName.h new file mode 100644 index 000000000000..1cfa141011a0 --- /dev/null +++ b/lldb/include/lldb/Breakpoint/BreakpointName.h @@ -0,0 +1,213 @@ +//===-- BreakpointName.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Breakpoint_Name_h_ +#define liblldb_Breakpoint_Name_h_ + +// C Includes +// C++ Includes +#include +#include +#include +#include + +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/BreakpointID.h" +#include "lldb/Breakpoint/BreakpointLocationCollection.h" +#include "lldb/Breakpoint/BreakpointLocationList.h" +#include "lldb/Breakpoint/BreakpointOptions.h" +#include "lldb/Breakpoint/Stoppoint.h" +#include "lldb/Core/Event.h" +#include "lldb/Core/SearchFilter.h" +#include "lldb/Utility/Flags.h" +#include "lldb/Utility/StringList.h" +#include "lldb/Utility/StructuredData.h" + +namespace lldb_private { + +class BreakpointName { +public: + class Permissions + { + public: + + enum PermissionKinds { listPerm = 0, disablePerm = 1, + deletePerm = 2, allPerms = 3 }; + + Permissions(bool in_list, bool in_disable, bool in_delete) + { + m_permissions[listPerm] = in_list; + m_permissions[disablePerm] = in_disable; + m_permissions[deletePerm] = in_delete; + m_set_mask.Set(permissions_mask[allPerms]); + } + + Permissions(const Permissions &rhs) + { + m_permissions[listPerm] = rhs.m_permissions[listPerm]; + m_permissions[disablePerm] = rhs.m_permissions[disablePerm]; + m_permissions[deletePerm] = rhs.m_permissions[deletePerm]; + m_set_mask = rhs.m_set_mask; + } + + Permissions() + { + m_permissions[listPerm] = true; + m_permissions[disablePerm] = true; + m_permissions[deletePerm] = true; + m_set_mask.Clear(); + } + + const Permissions &operator= (const Permissions &rhs) + { + if (this != &rhs) { + m_permissions[listPerm] = rhs.m_permissions[listPerm]; + m_permissions[disablePerm] = rhs.m_permissions[disablePerm]; + m_permissions[deletePerm] = rhs.m_permissions[deletePerm]; + m_set_mask = rhs.m_set_mask; + } + return *this; + } + + void Clear() { + *this = Permissions(); + } + + // Merge the permissions from incoming into this set of permissions. + // Only merge set permissions, and most restrictive permission wins. + void MergeInto(const Permissions &incoming) + { + MergePermission(incoming, listPerm); + MergePermission(incoming, disablePerm); + MergePermission(incoming, deletePerm); + } + + bool GetAllowList() const { return GetPermission(listPerm); } + bool SetAllowList(bool value) { return SetPermission(listPerm, value); } + + bool GetAllowDelete() const { return GetPermission(deletePerm); } + bool SetAllowDelete(bool value) { return SetPermission(deletePerm, value); } + + bool GetAllowDisable() const { return GetPermission(disablePerm); } + bool SetAllowDisable(bool value) { return SetPermission(disablePerm, + value); } + + bool GetPermission(enum PermissionKinds permission) const + { + return m_permissions[permission]; + } + + bool GetDescription(Stream *s, lldb::DescriptionLevel level); + + bool IsSet(enum PermissionKinds permission) const + { + return m_set_mask.Test(permissions_mask[permission]); + } + + bool AnySet() { + return m_set_mask.AnySet(permissions_mask[allPerms]); + } + + private: + static const Flags::ValueType permissions_mask[allPerms + 1]; + + bool m_permissions[allPerms]; + Flags m_set_mask; + + bool SetPermission(enum PermissionKinds permission, bool value) + { + bool old_value = m_permissions[permission]; + m_permissions[permission] = value; + m_set_mask.Set(permissions_mask[permission]); + return old_value; + } + + // If either side disallows the permission, the resultant disallows it. + void MergePermission(const Permissions &incoming, + enum PermissionKinds permission) + { + if (incoming.IsSet(permission)) + { + SetPermission(permission, !(m_permissions[permission] | + incoming.m_permissions[permission])); + } + } + }; + + BreakpointName(const ConstString &name, const char *help = nullptr) : + m_name(name), m_options(false) + { + SetHelp(help); + } + + BreakpointName(const ConstString &name, + BreakpointOptions &options, + const Permissions &permissions = Permissions(), + const char *help = nullptr) : + m_name(name), m_options(options), + m_permissions(permissions) { + SetHelp(help); + }; + + BreakpointName(const BreakpointName &rhs) : + m_name(rhs.m_name), m_options(rhs.m_options), + m_permissions(rhs.m_permissions), m_help(rhs.m_help) + {} + + BreakpointName(const ConstString &name, const Breakpoint &bkpt, + const char *help); + + const ConstString &GetName() const { return m_name; } + BreakpointOptions &GetOptions() { return m_options; } + const BreakpointOptions &GetOptions() const { return m_options; } + + void SetOptions(const BreakpointOptions &options) { + m_options = options; + } + + Permissions &GetPermissions() { return m_permissions; } + const Permissions &GetPermissions() const { return m_permissions; } + void SetPermissions(const Permissions &permissions) { + m_permissions = permissions; + } + + bool GetPermission(Permissions::PermissionKinds permission) const + { + return m_permissions.GetPermission(permission); + } + + void SetHelp(const char *description) + { + if (description) + m_help.assign(description); + else + m_help.clear(); + } + + const char *GetHelp() + { + return m_help.c_str(); + } + + // Returns true if any options were set in the name + bool GetDescription(Stream *s, lldb::DescriptionLevel level); + + void ConfigureBreakpoint(lldb::BreakpointSP bp_sp); + +private: + ConstString m_name; + BreakpointOptions m_options; + Permissions m_permissions; + std::string m_help; +}; + +} // namespace lldb_private + +#endif // liblldb_Breakpoint_Name_h_ diff --git a/lldb/include/lldb/Breakpoint/BreakpointOptions.h b/lldb/include/lldb/Breakpoint/BreakpointOptions.h index b0276cb15686..0229d52df471 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointOptions.h +++ b/lldb/include/lldb/Breakpoint/BreakpointOptions.h @@ -34,6 +34,8 @@ namespace lldb_private { class BreakpointOptions { friend class BreakpointLocation; +friend class BreakpointName; +friend class lldb_private::BreakpointOptionGroup; friend class Breakpoint; public: @@ -44,7 +46,9 @@ public: eIgnoreCount = 1 << 3, eThreadSpec = 1 << 4, eCondition = 1 << 5, - eAutoContinue = 1 << 6 + eAutoContinue = 1 << 6, + eAllOptions = (eCallback | eEnabled | eOneShot | eIgnoreCount | eThreadSpec + | eCondition | eAutoContinue) }; struct CommandData { CommandData() @@ -97,6 +101,10 @@ public: typedef std::shared_ptr CommandBatonSP; + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + //------------------------------------------------------------------ /// This constructor allows you to specify all the breakpoint options /// except the callback. That one is more complicated, and better @@ -116,6 +124,13 @@ public: int32_t ignore = 0, bool one_shot = false, bool auto_continue = false); + //------------------------------------------------------------------ + /// Breakpoints make options with all flags set. Locations and Names make options + /// with no flags set. + //------------------------------------------------------------------ + BreakpointOptions(bool all_flags_set); + BreakpointOptions(const BreakpointOptions &rhs); + virtual ~BreakpointOptions(); static std::unique_ptr @@ -131,6 +146,11 @@ public: // Operators //------------------------------------------------------------------ const BreakpointOptions &operator=(const BreakpointOptions &rhs); + + //------------------------------------------------------------------ + /// Copy over only the options set in the incoming BreakpointOptions. + //------------------------------------------------------------------ + void CopyOverSetOptions(const BreakpointOptions &rhs); //------------------------------------------------------------------ // Callbacks @@ -387,17 +407,13 @@ public: //------------------------------------------------------------------ void SetCommandDataCallback(std::unique_ptr &cmd_data); + void Clear(); + + bool AnySet() const { + return m_set_flags.AnySet(eAllOptions); + } + protected: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - //------------------------------------------------------------------ - /// Breakpoints make options with all flags set. Locations make options - /// with no flags set. Nobody else should make breakpoint options. - //------------------------------------------------------------------ - BreakpointOptions(bool all_flags_set); - BreakpointOptions(const BreakpointOptions &rhs); - //------------------------------------------------------------------ // Classes that inherit from BreakpointOptions can see and modify these //------------------------------------------------------------------ diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index ff9451939909..44f0b5ae28fd 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -21,6 +21,7 @@ // Other libraries and framework includes // Project includes #include "lldb/Breakpoint/BreakpointList.h" +#include "lldb/Breakpoint/BreakpointName.h" #include "lldb/Breakpoint/WatchpointList.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Broadcaster.h" @@ -651,12 +652,45 @@ public: } WatchpointList &GetWatchpointList() { return m_watchpoint_list; } - + + // Manages breakpoint names: + void AddNameToBreakpoint(BreakpointID &id, const char *name, Status &error); + + void AddNameToBreakpoint(lldb::BreakpointSP &bp_sp, const char *name, + Status &error); + + void RemoveNameFromBreakpoint(lldb::BreakpointSP &bp_sp, + const ConstString &name); + + BreakpointName *FindBreakpointName(const ConstString &name, bool can_create, + Status &error); + + void DeleteBreakpointName(const ConstString &name); + + void ConfigureBreakpointName(BreakpointName &bp_name, + const BreakpointOptions &options, + const BreakpointName::Permissions &permissions); + void ApplyNameToBreakpoints(BreakpointName &bp_name); + + + // This takes ownership of the name obj passed in. + void AddBreakpointName(BreakpointName *bp_name); + + void GetBreakpointNames(std::vector &names); + + //This call removes ALL breakpoints regardless of permission. void RemoveAllBreakpoints(bool internal_also = false); + + // This removes all the breakpoints, but obeys the ePermDelete on them. + void RemoveAllowedBreakpoints(); void DisableAllBreakpoints(bool internal_also = false); + + void DisableAllowedBreakpoints(); void EnableAllBreakpoints(bool internal_also = false); + + void EnableAllowedBreakpoints(); bool DisableBreakpointByID(lldb::break_id_t break_id); @@ -1218,6 +1252,9 @@ protected: SectionLoadHistory m_section_load_history; BreakpointList m_breakpoint_list; BreakpointList m_internal_breakpoint_list; + using BreakpointNameList = std::map; + BreakpointNameList m_breakpoint_names; + lldb::BreakpointSP m_last_created_breakpoint; WatchpointList m_watchpoint_list; lldb::WatchpointSP m_last_created_watchpoint; diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index 392dc641558d..a324edf9da3b 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -38,6 +38,8 @@ class BreakpointList; class BreakpointLocation; class BreakpointLocationCollection; class BreakpointLocationList; +class BreakpointName; +class BreakpointOptionGroup; class BreakpointOptions; class BreakpointResolver; class BreakpointSite; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 1bf87375b681..0559ab9672ee 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -714,18 +714,23 @@ 49E4F66B1C9CAD16008487EA /* DiagnosticManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49E4F6681C9CAD12008487EA /* DiagnosticManager.cpp */; }; 49F811F31E931B2100F4E163 /* CPlusPlusNameParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49F811EF1E931B1500F4E163 /* CPlusPlusNameParser.cpp */; }; 4C0083401B9F9BA900D5CF24 /* UtilityFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C00833F1B9F9BA900D5CF24 /* UtilityFunction.cpp */; }; + 4C05332B1F62121E00DED368 /* SBBreakpointOptionCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C0533291F6211FB00DED368 /* SBBreakpointOptionCommon.cpp */; }; 4C2479BD1BA39295009C9A7B /* FunctionCaller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C0083321B9A5DE200D5CF24 /* FunctionCaller.cpp */; }; 4C3ADCD61810D88B00357218 /* BreakpointResolverFileRegex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CAA56141422D986001FFA01 /* BreakpointResolverFileRegex.cpp */; }; 4C4EB7811E6A4DCC002035C0 /* DumpDataExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C4EB77F1E6A4DB8002035C0 /* DumpDataExtractor.cpp */; }; + 4C54B27B1F61CE2800D469CA /* SBBreakpointName.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C54B2781F61CE1200D469CA /* SBBreakpointName.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4C54B27E1F61CE6300D469CA /* SBBreakpointName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C54B27C1F61CE5300D469CA /* SBBreakpointName.cpp */; }; 4C562CC71CC07DF700C52EAC /* PDBASTParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C562CC21CC07DDD00C52EAC /* PDBASTParser.cpp */; }; 4C56543119D1EFAA002E9C44 /* ThreadPlanPython.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C56543019D1EFAA002E9C44 /* ThreadPlanPython.cpp */; }; 4C56543519D2297A002E9C44 /* SBThreadPlan.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C56543419D2297A002E9C44 /* SBThreadPlan.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4C56543719D22B32002E9C44 /* SBThreadPlan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C56543619D22B32002E9C44 /* SBThreadPlan.cpp */; }; 4C7D48241F5099A1005314B4 /* SymbolFileDWARFDwp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C7D481C1F509963005314B4 /* SymbolFileDWARFDwp.cpp */; }; 4C7D48251F5099B2005314B4 /* SymbolFileDWARFDwoDwp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C7D481F1F509964005314B4 /* SymbolFileDWARFDwoDwp.cpp */; }; + 4C7D482C1F509CF5005314B4 /* BreakpointName.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4C7D482B1F509CF5005314B4 /* BreakpointName.h */; }; 4C877B391F30EF990068FCFB /* SBProcessInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4987FB201F30EC9900E5C17D /* SBProcessInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4C88BC2A1BA3722B00AA0964 /* Expression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C88BC291BA3722B00AA0964 /* Expression.cpp */; }; 4C88BC2D1BA391B000AA0964 /* UserExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C0083331B9A5DE200D5CF24 /* UserExpression.cpp */; }; + 4CAA19E61F5A40040099E692 /* BreakpointName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C7D48281F509CCD005314B4 /* BreakpointName.cpp */; }; 4CABA9E0134A8BCD00539BDD /* ValueObjectMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */; }; 4CC7C6501D5298F30076FF94 /* OCamlLanguage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7C64D1D5298E20076FF94 /* OCamlLanguage.cpp */; }; 4CC7C6571D52997A0076FF94 /* OCamlASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CC7C6551D52996C0076FF94 /* OCamlASTContext.cpp */; }; @@ -1230,6 +1235,7 @@ files = ( 9A20570F1F3B821A00F6C293 /* test-dwarf.cpp in CopyFiles */, 9A2057101F3B821A00F6C293 /* test-dwarf.exe in CopyFiles */, + 4C7D482C1F509CF5005314B4 /* BreakpointName.h in CopyFiles */, AF90106515AB7D3600FF120D /* lldb.1 in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; @@ -2523,6 +2529,8 @@ 4C00833F1B9F9BA900D5CF24 /* UtilityFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UtilityFunction.cpp; path = source/Expression/UtilityFunction.cpp; sourceTree = ""; }; 4C00986F11500B4300F316B0 /* UnixSignals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnixSignals.h; path = include/lldb/Target/UnixSignals.h; sourceTree = ""; }; 4C00987011500B4300F316B0 /* UnixSignals.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnixSignals.cpp; path = source/Target/UnixSignals.cpp; sourceTree = ""; }; + 4C0533291F6211FB00DED368 /* SBBreakpointOptionCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBBreakpointOptionCommon.cpp; path = source/API/SBBreakpointOptionCommon.cpp; sourceTree = ""; }; + 4C05332C1F63092A00DED368 /* SBBreakpointName.i */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBBreakpointName.i; sourceTree = ""; }; 4C08CDE711C81EF8001610A8 /* ThreadSpec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadSpec.cpp; path = source/Target/ThreadSpec.cpp; sourceTree = ""; }; 4C08CDEB11C81F1E001610A8 /* ThreadSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadSpec.h; path = include/lldb/Target/ThreadSpec.h; sourceTree = ""; }; 4C09CB73116BD98B00C7A725 /* CommandCompletions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandCompletions.h; path = include/lldb/Interpreter/CommandCompletions.h; sourceTree = ""; }; @@ -2539,6 +2547,9 @@ 4C43DF8A11069C3200E55CBF /* ThreadPlanStepOverRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanStepOverRange.cpp; path = source/Target/ThreadPlanStepOverRange.cpp; sourceTree = ""; }; 4C4EB77F1E6A4DB8002035C0 /* DumpDataExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DumpDataExtractor.cpp; path = source/Core/DumpDataExtractor.cpp; sourceTree = ""; }; 4C4EB7821E6A4DE7002035C0 /* DumpDataExtractor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DumpDataExtractor.h; path = include/lldb/Core/DumpDataExtractor.h; sourceTree = ""; }; + 4C54B2781F61CE1200D469CA /* SBBreakpointName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBBreakpointName.h; path = include/lldb/API/SBBreakpointName.h; sourceTree = ""; }; + 4C54B27C1F61CE5300D469CA /* SBBreakpointName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBBreakpointName.cpp; path = source/API/SBBreakpointName.cpp; sourceTree = ""; }; + 4C54B2811F62081300D469CA /* SBBreakpointOptionCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBBreakpointOptionCommon.h; path = include/lldb/API/SBBreakpointOptionCommon.h; sourceTree = ""; }; 4C562CC21CC07DDD00C52EAC /* PDBASTParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PDBASTParser.cpp; path = PDB/PDBASTParser.cpp; sourceTree = ""; }; 4C562CC31CC07DDD00C52EAC /* PDBASTParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PDBASTParser.h; path = PDB/PDBASTParser.h; sourceTree = ""; }; 4C56543019D1EFAA002E9C44 /* ThreadPlanPython.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanPython.cpp; path = source/Target/ThreadPlanPython.cpp; sourceTree = ""; }; @@ -2555,6 +2566,8 @@ 4C7D481D1F509964005314B4 /* SymbolFileDWARFDwoDwp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolFileDWARFDwoDwp.h; sourceTree = ""; }; 4C7D481E1F509964005314B4 /* SymbolFileDWARFDwp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolFileDWARFDwp.h; sourceTree = ""; }; 4C7D481F1F509964005314B4 /* SymbolFileDWARFDwoDwp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolFileDWARFDwoDwp.cpp; sourceTree = ""; }; + 4C7D48281F509CCD005314B4 /* BreakpointName.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BreakpointName.cpp; path = source/Breakpoint/BreakpointName.cpp; sourceTree = ""; }; + 4C7D482B1F509CF5005314B4 /* BreakpointName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointName.h; path = include/lldb/Breakpoint/BreakpointName.h; sourceTree = ""; }; 4C88BC291BA3722B00AA0964 /* Expression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Expression.cpp; path = source/Expression/Expression.cpp; sourceTree = ""; }; 4C98D3DA118FB96F00E575D0 /* ClangFunctionCaller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangFunctionCaller.cpp; path = ExpressionParser/Clang/ClangFunctionCaller.cpp; sourceTree = ""; }; 4C98D3DB118FB96F00E575D0 /* IRExecutionUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRExecutionUnit.cpp; path = source/Expression/IRExecutionUnit.cpp; sourceTree = ""; }; @@ -2575,6 +2588,7 @@ 4CB443BC1249920C00C13DC2 /* CPPLanguageRuntime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CPPLanguageRuntime.cpp; path = source/Target/CPPLanguageRuntime.cpp; sourceTree = ""; }; 4CB443F212499B5000C13DC2 /* ObjCLanguageRuntime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ObjCLanguageRuntime.cpp; path = source/Target/ObjCLanguageRuntime.cpp; sourceTree = ""; }; 4CB443F612499B6E00C13DC2 /* ObjCLanguageRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjCLanguageRuntime.h; path = include/lldb/Target/ObjCLanguageRuntime.h; sourceTree = ""; }; + 4CBFF0471F579A36004AFA92 /* Flags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Flags.h; path = include/lldb/Utility/Flags.h; sourceTree = ""; }; 4CC2A148128C73ED001531C4 /* ThreadPlanTracer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanTracer.cpp; path = source/Target/ThreadPlanTracer.cpp; sourceTree = ""; }; 4CC2A14C128C7409001531C4 /* ThreadPlanTracer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanTracer.h; path = include/lldb/Target/ThreadPlanTracer.h; sourceTree = ""; }; 4CC7C64C1D5298E20076FF94 /* OCamlLanguage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OCamlLanguage.h; path = Language/OCaml/OCamlLanguage.h; sourceTree = ""; }; @@ -3939,6 +3953,7 @@ 2611FEF0142D83060017FEA3 /* SBBlock.i */, 2611FEF1142D83060017FEA3 /* SBBreakpoint.i */, 2611FEF2142D83060017FEA3 /* SBBreakpointLocation.i */, + 4C05332C1F63092A00DED368 /* SBBreakpointName.i */, 2611FEF3142D83060017FEA3 /* SBBroadcaster.i */, 2611FEF4142D83060017FEA3 /* SBCommandInterpreter.i */, 2611FEF5142D83060017FEA3 /* SBCommandReturnObject.i */, @@ -4032,6 +4047,10 @@ 9AF16A9C11402D5B007A7B3F /* SBBreakpoint.cpp */, 9AF16CC611408686007A7B3F /* SBBreakpointLocation.h */, 9AF16CC7114086A1007A7B3F /* SBBreakpointLocation.cpp */, + 4C54B2781F61CE1200D469CA /* SBBreakpointName.h */, + 4C54B27C1F61CE5300D469CA /* SBBreakpointName.cpp */, + 4C54B2811F62081300D469CA /* SBBreakpointOptionCommon.h */, + 4C0533291F6211FB00DED368 /* SBBreakpointOptionCommon.cpp */, 9A9830F31125FC5800A56CB0 /* SBBroadcaster.h */, 9A9830F21125FC5800A56CB0 /* SBBroadcaster.cpp */, 9A9830F71125FC5800A56CB0 /* SBCommandInterpreter.h */, @@ -4353,6 +4372,7 @@ 26BC7DD310F1B7D500F91463 /* Endian.h */, AFC2DCE61E6E2ED000283714 /* FastDemangle.cpp */, AFC2DCED1E6E2F9800283714 /* FastDemangle.h */, + 4CBFF0471F579A36004AFA92 /* Flags.h */, AFC2DCF21E6E30CF00283714 /* History.cpp */, AFC2DCF41E6E30D800283714 /* History.h */, 236124A61986B50E004EFC37 /* IOObject.h */, @@ -5041,6 +5061,8 @@ 26BC7E0F10F1B83100F91463 /* BreakpointLocationCollection.cpp */, 26BC7CF410F1B71400F91463 /* BreakpointLocationList.h */, 26BC7E1010F1B83100F91463 /* BreakpointLocationList.cpp */, + 4C7D48281F509CCD005314B4 /* BreakpointName.cpp */, + 4C7D482B1F509CF5005314B4 /* BreakpointName.h */, 26BC7CF510F1B71400F91463 /* BreakpointOptions.h */, 26BC7E1110F1B83100F91463 /* BreakpointOptions.cpp */, 26BC7CF610F1B71400F91463 /* BreakpointResolver.h */, @@ -6662,6 +6684,7 @@ 26C72C94124322890068DC16 /* SBStream.h in Headers */, 9A357671116E7B5200E8ED2F /* SBStringList.h in Headers */, 26DE205B11618FF600A093E2 /* SBSymbol.h in Headers */, + 4C54B27B1F61CE2800D469CA /* SBBreakpointName.h in Headers */, 262F12B71835469C00AEB384 /* SBPlatform.h in Headers */, 23DCBEA31D63E71F0084C36B /* SBStructuredData.h in Headers */, 26DE204111618AB900A093E2 /* SBSymbolContext.h in Headers */, @@ -7266,6 +7289,7 @@ 2668032C116005E2008E1FE4 /* SBFrame.cpp in Sources */, 2668032D116005E3008E1FE4 /* SBFileSpec.cpp in Sources */, 2668032E116005E5008E1FE4 /* SBEvent.cpp in Sources */, + 4C54B27E1F61CE6300D469CA /* SBBreakpointName.cpp in Sources */, 2668032F116005E6008E1FE4 /* SBError.cpp in Sources */, 23DCEA461D1C4D0F00A602B4 /* SBMemoryRegionInfo.cpp in Sources */, 26680330116005E7008E1FE4 /* SBDebugger.cpp in Sources */, @@ -7289,6 +7313,7 @@ 26DE20651161904E00A093E2 /* SBSymbol.cpp in Sources */, 9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */, 261744781168585B005ADD65 /* SBType.cpp in Sources */, + 4C05332B1F62121E00DED368 /* SBBreakpointOptionCommon.cpp in Sources */, 9A35758E116CFE0F00E8ED2F /* SBValueList.cpp in Sources */, 9A357673116E7B6400E8ED2F /* SBStringList.cpp in Sources */, 9A1E595C1EB2B141002206A5 /* SBTrace.cpp in Sources */, @@ -7629,6 +7654,7 @@ 947CF7771DC7B20D00EF980B /* ThreadMinidump.cpp in Sources */, 268900C913353E5F00698AC0 /* NameToDIE.cpp in Sources */, 268900CA13353E5F00698AC0 /* SymbolFileDWARF.cpp in Sources */, + 4CAA19E61F5A40040099E692 /* BreakpointName.cpp in Sources */, 268900CB13353E5F00698AC0 /* LogChannelDWARF.cpp in Sources */, 268900CC13353E5F00698AC0 /* SymbolFileDWARFDebugMap.cpp in Sources */, 268900CD13353E5F00698AC0 /* UniqueDWARFASTType.cpp in Sources */, diff --git a/lldb/lldb.xcodeproj/xcshareddata/xcschemes/LLDB.xcscheme b/lldb/lldb.xcodeproj/xcshareddata/xcschemes/LLDB.xcscheme index 881829e27feb..95f7ce4efd49 100644 --- a/lldb/lldb.xcodeproj/xcshareddata/xcschemes/LLDB.xcscheme +++ b/lldb/lldb.xcodeproj/xcshareddata/xcschemes/LLDB.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB" + language = "" shouldUseLaunchSchemeArgsEnv = "YES"> @@ -54,6 +55,7 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" displayScaleIsEnabled = "NO" displayScale = "1.00" + language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/auto_continue/TestBreakpointAutoContinue.py b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/auto_continue/TestBreakpointAutoContinue.py index b1b37ae38172..9630e39e0142 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/auto_continue/TestBreakpointAutoContinue.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/auto_continue/TestBreakpointAutoContinue.py @@ -73,7 +73,7 @@ class BreakpointAutoContinue(TestBase): self.assertEqual(bkpt.GetHitCount(), 2, "Should have run through the breakpoint twice") def auto_continue_with_command(self): - bpno = self.make_target_and_bkpt("-N BKPT -d 'break modify --auto-continue 0 BKPT'") + bpno = self.make_target_and_bkpt("-N BKPT -C 'break modify --auto-continue 0 BKPT'") process = self.launch_it(lldb.eStateStopped) state = process.GetState() self.assertEqual(state, lldb.eStateStopped, "Process should be stopped") diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py index cb4aeadbf93d..386eafbb0b60 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py @@ -287,7 +287,7 @@ class BreakpointCommandTestCase(TestBase): # Add a breakpoint. lldbutil.run_break_set_by_file_and_line( self, "main.c", self.line, num_expected_locations=1, loc_exact=True, - extra_options='-d bt -d "thread list" -d continue') + extra_options='-C bt -C "thread list" -C continue') bkpt = target.FindBreakpointByID(1) self.assertTrue(bkpt.IsValid(), "Couldn't find breakpoint 1") diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_names/TestBreakpointNames.py b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_names/TestBreakpointNames.py index cc31ef80e8a3..a758f76cc570 100644 --- a/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_names/TestBreakpointNames.py +++ b/lldb/packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_names/TestBreakpointNames.py @@ -17,6 +17,7 @@ from lldbsuite.test import lldbutil class BreakpointNames(TestBase): mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True @add_test_categories(['pyapi']) def test_setting_names(self): @@ -37,6 +38,25 @@ class BreakpointNames(TestBase): self.setup_target() self.do_check_using_names() + def test_configuring_names(self): + """Use Python APIs to test that configuring options on breakpoint names works correctly.""" + self.build() + self.make_a_dummy_name() + self.setup_target() + self.do_check_configuring_names() + + def test_configuring_permissions_sb(self): + """Use Python APIs to test that configuring permissions on names works correctly.""" + self.build() + self.setup_target() + self.do_check_configuring_permissions_sb() + + def test_configuring_permissions_cli(self): + """Use Python APIs to test that configuring permissions on names works correctly.""" + self.build() + self.setup_target() + self.do_check_configuring_permissions_cli() + def setup_target(self): exe = os.path.join(os.getcwd(), "a.out") @@ -45,10 +65,35 @@ class BreakpointNames(TestBase): self.assertTrue(self.target, VALID_TARGET) self.main_file_spec = lldb.SBFileSpec(os.path.join(os.getcwd(), "main.c")) + def check_name_in_target(self, bkpt_name): + name_list = lldb.SBStringList() + self.target.GetBreakpointNames(name_list) + found_it = False + for name in name_list: + if name == bkpt_name: + found_it = True + break + self.assertTrue(found_it, "Didn't find the name %s in the target's name list:"%(bkpt_name)) + def setUp(self): # Call super's setUp(). TestBase.setUp(self) + # These are the settings we're going to be putting into names & breakpoints: + self.bp_name_string = "ABreakpoint" + self.is_one_shot = True + self.ignore_count = 1000 + self.condition = "1 == 2" + self.auto_continue = True + self.tid = 0xaaaa + self.tidx = 10 + self.thread_name = "Fooey" + self.queue_name = "Blooey" + self.cmd_list = lldb.SBStringList() + self.cmd_list.AppendString("frame var") + self.cmd_list.AppendString("bt") + + def do_check_names(self): """Use Python APIs to check that we can set & retrieve breakpoint names""" bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) @@ -66,11 +111,15 @@ class BreakpointNames(TestBase): matches = bkpt.MatchesName("NotABreakpoint") self.assertTrue(not matches, "We matched a name we didn't set.") + # Make sure the name is also in the target: + self.check_name_in_target(bkpt_name) + # Add another name, make sure that works too: bkpt.AddName(other_bkpt_name) matches = bkpt.MatchesName(bkpt_name) self.assertTrue(matches, "Adding a name means we didn't match the name we just set") + self.check_name_in_target(other_bkpt_name) # Remove the name and make sure we no longer match it: bkpt.RemoveName(bkpt_name) @@ -89,26 +138,21 @@ class BreakpointNames(TestBase): def do_check_illegal_names(self): """Use Python APIs to check that we reject illegal names.""" bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) - success = bkpt.AddName("-CantStartWithADash") - self.assertTrue(not success,"We allowed a name starting with a dash.") + bad_names = ["-CantStartWithADash", + "1CantStartWithANumber", + "^CantStartWithNonAlpha", + "CantHave-ADash", + "Cant Have Spaces"] + for bad_name in bad_names: + success = bkpt.AddName(bad_name) + self.assertTrue(not success,"We allowed an illegal name: %s"%(bad_name)) + bp_name = lldb.SBBreakpointName(self.target, bad_name) + self.assertFalse(bp_name.IsValid(), "We made a breakpoint name with an illegal name: %s"%(bad_name)); - success = bkpt.AddName("1CantStartWithANumber") - self.assertTrue(not success, "We allowed a name starting with a number.") + retval =lldb.SBCommandReturnObject() + self.dbg.GetCommandInterpreter().HandleCommand("break set -n whatever -N '%s'"%(bad_name), retval) + self.assertTrue(not retval.Succeeded(), "break set succeeded with: illegal name: %s"%(bad_name)) - success = bkpt.AddName("^CantStartWithNonAlpha") - self.assertTrue(not success, "We allowed a name starting with an ^.") - - success = bkpt.AddName("CantHave-ADash") - self.assertTrue(not success, "We allowed a name with a dash in it.") - - success = bkpt.AddName("Cant Have Spaces") - self.assertTrue(not success, "We allowed a name with spaces.") - - # Check from the command line as well: - retval =lldb.SBCommandReturnObject() - self.dbg.GetCommandInterpreter().HandleCommand("break set -n whatever -N has-dashes", retval) - self.assertTrue(not retval.Succeeded(), "break set succeeded with: illegal name") - def do_check_using_names(self): """Use Python APIs to check names work in place of breakpoint ID's.""" @@ -133,9 +177,174 @@ class BreakpointNames(TestBase): self.assertTrue(not bkpt.IsEnabled(), "We didn't disable the breakpoint.") # Also make sure we don't apply commands to non-matching names: - self.dbg.GetCommandInterpreter().HandleCommand("break modify --one-shot 1 %s"%(bkpt_name), retval) + self.dbg.GetCommandInterpreter().HandleCommand("break modify --one-shot 1 %s"%(other_bkpt_name), retval) self.assertTrue(retval.Succeeded(), "break modify failed with: %s."%(retval.GetError())) self.assertTrue(not bkpt.IsOneShot(), "We applied one-shot to the wrong breakpoint.") + def check_option_values(self, bp_object): + self.assertEqual(bp_object.IsOneShot(), self.is_one_shot, "IsOneShot") + self.assertEqual(bp_object.GetIgnoreCount(), self.ignore_count, "IgnoreCount") + self.assertEqual(bp_object.GetCondition(), self.condition, "Condition") + self.assertEqual(bp_object.GetAutoContinue(), self.auto_continue, "AutoContinue") + self.assertEqual(bp_object.GetThreadID(), self.tid, "Thread ID") + self.assertEqual(bp_object.GetThreadIndex(), self.tidx, "Thread Index") + self.assertEqual(bp_object.GetThreadName(), self.thread_name, "Thread Name") + self.assertEqual(bp_object.GetQueueName(), self.queue_name, "Queue Name") + set_cmds = lldb.SBStringList() + bp_object.GetCommandLineCommands(set_cmds) + self.assertEqual(set_cmds.GetSize(), self.cmd_list.GetSize(), "Size of command line commands") + for idx in range(0, set_cmds.GetSize()): + self.assertEqual(self.cmd_list.GetStringAtIndex(idx), set_cmds.GetStringAtIndex(idx), "Command %d"%(idx)) + + def make_a_dummy_name(self): + "This makes a breakpoint name in the dummy target to make sure it gets copied over" + + dummy_target = self.dbg.GetDummyTarget() + self.assertTrue(dummy_target.IsValid(), "Dummy target was not valid.") + + def cleanup (): + self.dbg.GetDummyTarget().DeleteBreakpointName(self.bp_name_string) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + # Now find it in the dummy target, and make sure these settings took: + bp_name = lldb.SBBreakpointName(dummy_target, self.bp_name_string) + # Make sure the name is right: + self.assertTrue (bp_name.GetName() == self.bp_name_string, "Wrong bp_name: %s"%(bp_name.GetName())) + bp_name.SetOneShot(self.is_one_shot) + bp_name.SetIgnoreCount(self.ignore_count) + bp_name.SetCondition(self.condition) + bp_name.SetAutoContinue(self.auto_continue) + bp_name.SetThreadID(self.tid) + bp_name.SetThreadIndex(self.tidx) + bp_name.SetThreadName(self.thread_name) + bp_name.SetQueueName(self.queue_name) + bp_name.SetCommandLineCommands(self.cmd_list) + + # Now look it up again, and make sure it got set correctly. + bp_name = lldb.SBBreakpointName(dummy_target, self.bp_name_string) + self.assertTrue(bp_name.IsValid(), "Failed to make breakpoint name.") + self.check_option_values(bp_name) + + def do_check_configuring_names(self): + """Use Python APIs to check that configuring breakpoint names works correctly.""" + other_bp_name_string = "AnotherBreakpointName" + cl_bp_name_string = "CLBreakpointName" + + # Now find the version copied in from the dummy target, and make sure these settings took: + bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string) + self.assertTrue(bp_name.IsValid(), "Failed to make breakpoint name.") + self.check_option_values(bp_name) + + # Now add this name to a breakpoint, and make sure it gets configured properly + bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) + success = bkpt.AddName(self.bp_name_string) + self.assertTrue(success, "Couldn't add this name to the breakpoint") + self.check_option_values(bkpt) + + # Now make a name from this breakpoint, and make sure the new name is properly configured: + new_name = lldb.SBBreakpointName(bkpt, other_bp_name_string) + self.assertTrue(new_name.IsValid(), "Couldn't make a valid bp_name from a breakpoint.") + self.check_option_values(bkpt) + + # Now change the name's option and make sure it gets propagated to + # the breakpoint: + new_auto_continue = not self.auto_continue + bp_name.SetAutoContinue(new_auto_continue) + self.assertEqual(bp_name.GetAutoContinue(), new_auto_continue, "Couldn't change auto-continue on the name") + self.assertEqual(bkpt.GetAutoContinue(), new_auto_continue, "Option didn't propagate to the breakpoint.") + # Now make this same breakpoint name - but from the command line + cmd_str = "breakpoint name configure %s -o %d -i %d -c '%s' -G %d -t %d -x %d -T '%s' -q '%s'"%(cl_bp_name_string, + self.is_one_shot, + self.ignore_count, + self.condition, + self.auto_continue, + self.tid, + self.tidx, + self.thread_name, + self.queue_name) + for cmd in self.cmd_list: + cmd_str += " -C '%s'"%(cmd) + result = lldb.SBCommandReturnObject() + self.dbg.GetCommandInterpreter().HandleCommand(cmd_str, result) + self.assertTrue(result.Succeeded()) + # Now look up this name again and check its options: + cl_name = lldb.SBBreakpointName(self.target, cl_bp_name_string) + self.check_option_values(cl_name) + + # We should have three names now, make sure the target can list them: + name_list = lldb.SBStringList() + self.target.GetBreakpointNames(name_list) + for name_string in [self.bp_name_string, other_bp_name_string, cl_bp_name_string]: + self.assertTrue(name_string in name_list, "Didn't find %s in names"%(name_string)) + + # Test that deleting the name we injected into the dummy target works (there's also a + # cleanup that will do this, but that won't test the result... + dummy_target = self.dbg.GetDummyTarget() + dummy_target.DeleteBreakpointName(self.bp_name_string) + name_list.Clear() + dummy_target.GetBreakpointNames(name_list) + self.assertTrue(self.bp_name_string not in name_list, "Didn't delete %s from the dummy target"%(self.bp_name_string)) + + def check_permission_results(self, bp_name): + self.assertEqual(bp_name.GetAllowDelete(), False, "Didn't set allow delete.") + protected_bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) + protected_id = protected_bkpt.GetID() + + unprotected_bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) + unprotected_id = unprotected_bkpt.GetID() + + success = protected_bkpt.AddName(self.bp_name_string) + self.assertTrue(success, "Couldn't add this name to the breakpoint") + + self.target.DisableAllBreakpoints() + self.assertEqual(protected_bkpt.IsEnabled(), True, "Didnt' keep breakpoint from being disabled") + self.assertEqual(unprotected_bkpt.IsEnabled(), False, "Protected too many breakpoints from disabling.") + + # Try from the command line too: + unprotected_bkpt.SetEnabled(True) + result = lldb.SBCommandReturnObject() + self.dbg.GetCommandInterpreter().HandleCommand("break disable", result) + self.assertTrue(result.Succeeded()) + self.assertEqual(protected_bkpt.IsEnabled(), True, "Didnt' keep breakpoint from being disabled") + self.assertEqual(unprotected_bkpt.IsEnabled(), False, "Protected too many breakpoints from disabling.") + + self.target.DeleteAllBreakpoints() + bkpt = self.target.FindBreakpointByID(protected_id) + self.assertTrue(bkpt.IsValid(), "Didn't keep the breakpoint from being deleted.") + bkpt = self.target.FindBreakpointByID(unprotected_id) + self.assertFalse(bkpt.IsValid(), "Protected too many breakpoints from deletion.") + + # Remake the unprotected breakpoint and try again from the command line: + unprotected_bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) + unprotected_id = unprotected_bkpt.GetID() + + self.dbg.GetCommandInterpreter().HandleCommand("break delete -f", result) + self.assertTrue(result.Succeeded()) + bkpt = self.target.FindBreakpointByID(protected_id) + self.assertTrue(bkpt.IsValid(), "Didn't keep the breakpoint from being deleted.") + bkpt = self.target.FindBreakpointByID(unprotected_id) + self.assertFalse(bkpt.IsValid(), "Protected too many breakpoints from deletion.") + + def do_check_configuring_permissions_sb(self): + bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string) + + # Make a breakpoint name with delete disallowed: + bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string) + self.assertTrue(bp_name.IsValid(), "Failed to make breakpoint name for valid name.") + + bp_name.SetAllowDelete(False) + bp_name.SetAllowDisable(False) + bp_name.SetAllowList(False) + self.check_permission_results(bp_name) + + def do_check_configuring_permissions_cli(self): + # Make the name with the right options using the command line: + self.runCmd("breakpoint name configure -L 0 -D 0 -A 0 %s"%(self.bp_name_string), check=True) + # Now look up the breakpoint we made, and check that it works. + bp_name = lldb.SBBreakpointName(self.target, self.bp_name_string) + self.assertTrue(bp_name.IsValid(), "Didn't make a breakpoint name we could find.") + self.check_permission_results(bp_name) diff --git a/lldb/packages/Python/lldbsuite/test/python_api/default-constructor/TestDefaultConstructorForAPIObjects.py b/lldb/packages/Python/lldbsuite/test/python_api/default-constructor/TestDefaultConstructorForAPIObjects.py index bea9f5962d63..5c0c7bbd766a 100644 --- a/lldb/packages/Python/lldbsuite/test/python_api/default-constructor/TestDefaultConstructorForAPIObjects.py +++ b/lldb/packages/Python/lldbsuite/test/python_api/default-constructor/TestDefaultConstructorForAPIObjects.py @@ -71,6 +71,17 @@ class APIDefaultConstructorTestCase(TestBase): import sb_breakpointlocation sb_breakpointlocation.fuzz_obj(obj) + @add_test_categories(['pyapi']) + @no_debug_info_test + def test_SBBreakpointName(self): + obj = lldb.SBBreakpointName() + if self.TraceOn(): + print(obj) + self.assertFalse(obj) + # Do fuzz testing on the invalid obj, it should not crash lldb. + import sb_breakpointname + sb_breakpointname.fuzz_obj(obj) + @add_test_categories(['pyapi']) @no_debug_info_test def test_SBBroadcaster(self): diff --git a/lldb/packages/Python/lldbsuite/test/python_api/default-constructor/sb_breakpointname.py b/lldb/packages/Python/lldbsuite/test/python_api/default-constructor/sb_breakpointname.py new file mode 100644 index 000000000000..56016c05c313 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/python_api/default-constructor/sb_breakpointname.py @@ -0,0 +1,42 @@ +""" +Fuzz tests an object after the default construction to make sure it does not crash lldb. +""" + +import sys +import lldb + + +def fuzz_obj(obj): + obj.IsValid() + obj.GetName() + obj.SetEnabled(True) + obj.IsEnabled() + obj.SetOneShot(True) + obj.IsOneShot() + obj.SetIgnoreCount(1) + obj.GetIgnoreCount() + obj.SetCondition("1 == 2") + obj.GetCondition() + obj.SetAutoContinue(False) + obj.GetAutoContinue() + obj.SetThreadID(0x1234) + obj.GetThreadID() + obj.SetThreadIndex(10) + obj.GetThreadIndex() + obj.SetThreadName("AThread") + obj.GetThreadName() + obj.SetQueueName("AQueue") + obj.GetQueueName() + obj.SetScriptCallbackFunction("AFunction") + commands = lldb.SBStringList() + obj.SetCommandLineCommands(commands) + obj.GetCommandLineCommands(commands) + obj.SetScriptCallbackBody("Insert Python Code here") + obj.GetAllowList() + obj.SetAllowList(False) + obj.GetAllowDelete() + obj.SetAllowDelete(False) + obj.GetAllowDisable() + obj.SetAllowDisable(False) + stream = lldb.SBStream() + obj.GetDescription(stream) diff --git a/lldb/scripts/Python/python-extensions.swig b/lldb/scripts/Python/python-extensions.swig index 693b06b9aab3..d79917b92158 100644 --- a/lldb/scripts/Python/python-extensions.swig +++ b/lldb/scripts/Python/python-extensions.swig @@ -71,6 +71,21 @@ } } +%extend lldb::SBBreakpointName { + PyObject *lldb::SBBreakpointName::__str__ (){ + lldb::SBStream description; + $self->GetDescription (description); + const char *desc = description.GetData(); + size_t desc_len = description.GetSize(); + if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r')) + --desc_len; + if (desc_len > 0) + return lldb_private::PythonString(llvm::StringRef(desc, desc_len)).release(); + else + return lldb_private::PythonString("").release(); + } +} + %extend lldb::SBBroadcaster { %pythoncode %{ def __eq__(self, rhs): diff --git a/lldb/scripts/Python/python-swigsafecast.swig b/lldb/scripts/Python/python-swigsafecast.swig index ea3f21f859ad..ffd7546323a0 100644 --- a/lldb/scripts/Python/python-swigsafecast.swig +++ b/lldb/scripts/Python/python-swigsafecast.swig @@ -113,6 +113,13 @@ SBTypeToSWIGWrapper (lldb::SBBreakpointLocation* breakpoint_location_sb) return SWIG_NewPointerObj((void *) breakpoint_location_sb, SWIGTYPE_p_lldb__SBBreakpointLocation, 0); } +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBBreakpointName* breakpoint_name_sb) +{ + return SWIG_NewPointerObj((void *) breakpoint_name_sb, SWIGTYPE_p_lldb__SBBreakpointName, 0); +} + template <> PyObject* SBTypeToSWIGWrapper (lldb::SBValue* value_sb) diff --git a/lldb/scripts/interface/SBBreakpoint.i b/lldb/scripts/interface/SBBreakpoint.i index 76ddd7259e9c..525797ad91f1 100644 --- a/lldb/scripts/interface/SBBreakpoint.i +++ b/lldb/scripts/interface/SBBreakpoint.i @@ -6,7 +6,6 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// - namespace lldb { %feature("docstring", @@ -81,11 +80,6 @@ class SBBreakpoint { public: - typedef bool (*BreakpointHitCallback) (void *baton, - SBProcess &process, - SBThread &thread, - lldb::SBBreakpointLocation &location); - SBBreakpoint (); SBBreakpoint (const lldb::SBBreakpoint& rhs); diff --git a/lldb/scripts/interface/SBBreakpointName.i b/lldb/scripts/interface/SBBreakpointName.i new file mode 100644 index 000000000000..76f087cb3145 --- /dev/null +++ b/lldb/scripts/interface/SBBreakpointName.i @@ -0,0 +1,108 @@ +//===-- SWIG interface for SBBreakpointName.h -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { +%feature("docstring", +"Represents a breakpoint name registered in a given SBTarget. + +Breakpoint names provide a way to act on groups of breakpoints. When you add a +name to a group of breakpoints, you can then use the name in all the command +line lldb commands for that name. You can also configure the SBBreakpointName +options and those options will be propagated to any SBBreakpoints currently +using that name. Adding a name to a breakpoint will also apply any of the +set options to that breakpoint. + +You can also set permissions on a breakpoint name to disable listing, deleting +and disabling breakpoints. That will disallow the given operation for breakpoints +except when the breakpoint is mentioned by ID. So for instance deleting all the +breakpoints won't delete breakpoints so marked." +) SBBreakpointName; +class LLDB_API SBBreakpointName { +public: + SBBreakpointName(); + + SBBreakpointName(SBTarget &target, const char *name); + + SBBreakpointName(SBBreakpoint &bkpt, const char *name); + + SBBreakpointName(const lldb::SBBreakpointName &rhs); + + ~SBBreakpointName(); + + const lldb::SBBreakpointName &operator=(const lldb::SBBreakpointName &rhs); + + // Tests to see if the opaque breakpoint object in this object matches the + // opaque breakpoint object in "rhs". + bool operator==(const lldb::SBBreakpointName &rhs); + + bool operator!=(const lldb::SBBreakpointName &rhs); + + bool IsValid() const; + + const char *GetName() const; + + void SetEnabled(bool enable); + + bool IsEnabled(); + + void SetOneShot(bool one_shot); + + bool IsOneShot() const; + + void SetIgnoreCount(uint32_t count); + + uint32_t GetIgnoreCount() const; + + void SetCondition(const char *condition); + + const char *GetCondition(); + + void SetAutoContinue(bool auto_continue); + + bool GetAutoContinue(); + + void SetThreadID(lldb::tid_t sb_thread_id); + + lldb::tid_t GetThreadID(); + + void SetThreadIndex(uint32_t index); + + uint32_t GetThreadIndex() const; + + void SetThreadName(const char *thread_name); + + const char *GetThreadName() const; + + void SetQueueName(const char *queue_name); + + const char *GetQueueName() const; + + void SetScriptCallbackFunction(const char *callback_function_name); + + void SetCommandLineCommands(SBStringList &commands); + + bool GetCommandLineCommands(SBStringList &commands); + + SBError SetScriptCallbackBody(const char *script_body_text); + + bool GetAllowList() const; + void SetAllowList(bool value); + + bool GetAllowDelete(); + void SetAllowDelete(bool value); + + bool GetAllowDisable(); + void SetAllowDisable(bool value); + + bool GetDescription(lldb::SBStream &description); + +}; + +} // namespace lldb + diff --git a/lldb/scripts/interface/SBDebugger.i b/lldb/scripts/interface/SBDebugger.i index 07f049b82bad..9f746d36348c 100644 --- a/lldb/scripts/interface/SBDebugger.i +++ b/lldb/scripts/interface/SBDebugger.i @@ -213,6 +213,11 @@ public: lldb::SBTarget CreateTarget (const char *filename); + %feature("docstring", + "The dummy target holds breakpoints and breakpoint names that will prime newly created targets." + ) GetDummyTarget; + lldb::SBTarget GetDummyTarget(); + %feature("docstring", "Return true if target is deleted from the target list of the debugger." ) DeleteTarget; diff --git a/lldb/scripts/interface/SBTarget.i b/lldb/scripts/interface/SBTarget.i index c1d749c7ce75..bcec606005f4 100644 --- a/lldb/scripts/interface/SBTarget.i +++ b/lldb/scripts/interface/SBTarget.i @@ -711,6 +711,10 @@ public: bool FindBreakpointsByName(const char *name, SBBreakpointList &bkpt_list); + void DeleteBreakpointName(const char *name); + + void GetBreakpointNames(SBStringList &names); + bool EnableAllBreakpoints (); diff --git a/lldb/scripts/lldb.swig b/lldb/scripts/lldb.swig index 044cfc0b2cda..dc987040e768 100644 --- a/lldb/scripts/lldb.swig +++ b/lldb/scripts/lldb.swig @@ -82,6 +82,7 @@ import six #include "lldb/API/SBBlock.h" #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBBreakpointLocation.h" +#include "lldb/API/SBBreakpointName.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandInterpreter.h" #include "lldb/API/SBCommandReturnObject.h" @@ -168,6 +169,7 @@ import six %include "./interface/SBBlock.i" %include "./interface/SBBreakpoint.i" %include "./interface/SBBreakpointLocation.i" +%include "./interface/SBBreakpointName.i" %include "./interface/SBBroadcaster.i" %include "./interface/SBCommandInterpreter.i" %include "./interface/SBCommandReturnObject.i" diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index 9abdce0c928a..6a0ff9536c2c 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -37,6 +37,8 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" +#include "SBBreakpointOptionCommon.h" + #include "lldb/lldb-enumerations.h" #include "llvm/ADT/STLExtras.h" @@ -44,21 +46,6 @@ using namespace lldb; using namespace lldb_private; -struct CallbackData { - SBBreakpoint::BreakpointHitCallback callback; - void *callback_baton; -}; - -class SBBreakpointCallbackBaton : public TypedBaton { -public: - SBBreakpointCallbackBaton(SBBreakpoint::BreakpointHitCallback callback, - void *baton) - : TypedBaton(llvm::make_unique()) { - getItem()->callback = callback; - getItem()->callback_baton = baton; - } -}; - SBBreakpoint::SBBreakpoint() {} SBBreakpoint::SBBreakpoint(const SBBreakpoint &rhs) @@ -500,37 +487,9 @@ bool SBBreakpoint::GetDescription(SBStream &s, bool include_locations) { return false; } -bool SBBreakpoint::PrivateBreakpointHitCallback(void *baton, - StoppointCallbackContext *ctx, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id) { - ExecutionContext exe_ctx(ctx->exe_ctx_ref); - BreakpointSP bp_sp( - exe_ctx.GetTargetRef().GetBreakpointList().FindBreakpointByID(break_id)); - if (baton && bp_sp) { - CallbackData *data = (CallbackData *)baton; - lldb_private::Breakpoint *bp = bp_sp.get(); - if (bp && data->callback) { - Process *process = exe_ctx.GetProcessPtr(); - if (process) { - SBProcess sb_process(process->shared_from_this()); - SBThread sb_thread; - SBBreakpointLocation sb_location; - assert(bp_sp); - sb_location.SetLocation(bp_sp->FindLocationByID(break_loc_id)); - Thread *thread = exe_ctx.GetThreadPtr(); - if (thread) - sb_thread.SetThread(thread->shared_from_this()); - - return data->callback(data->callback_baton, sb_process, sb_thread, - sb_location); - } - } - } - return true; // Return true if we should stop at this breakpoint -} - -void SBBreakpoint::SetCallback(BreakpointHitCallback callback, void *baton) { +void SBBreakpoint + ::SetCallback(SBBreakpointHitCallback callback, + void *baton) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); BreakpointSP bkpt_sp = GetSP(); LLDB_LOG(log, "breakpoint = {0}, callback = {1}, baton = {2}", bkpt_sp.get(), @@ -540,7 +499,8 @@ void SBBreakpoint::SetCallback(BreakpointHitCallback callback, void *baton) { std::lock_guard guard( bkpt_sp->GetTarget().GetAPIMutex()); BatonSP baton_sp(new SBBreakpointCallbackBaton(callback, baton)); - bkpt_sp->SetCallback(SBBreakpoint::PrivateBreakpointHitCallback, baton_sp, + bkpt_sp->SetCallback(SBBreakpointCallbackBaton + ::PrivateBreakpointHitCallback, baton_sp, false); } } @@ -599,10 +559,17 @@ bool SBBreakpoint::AddName(const char *new_name) { bkpt_sp->GetTarget().GetAPIMutex()); Status error; // Think I'm just going to swallow the error here, it's // probably more annoying to have to provide it. - return bkpt_sp->AddName(new_name, error); + bkpt_sp->GetTarget().AddNameToBreakpoint(bkpt_sp, new_name, error); + if (error.Fail()) + { + if (log) + log->Printf("Failed to add name: '%s' to breakpoint: %s", + new_name, error.AsCString()); + return false; + } } - return false; + return true; } void SBBreakpoint::RemoveName(const char *name_to_remove) { @@ -613,7 +580,8 @@ void SBBreakpoint::RemoveName(const char *name_to_remove) { if (bkpt_sp) { std::lock_guard guard( bkpt_sp->GetTarget().GetAPIMutex()); - bkpt_sp->RemoveName(name_to_remove); + bkpt_sp->GetTarget().RemoveNameFromBreakpoint(bkpt_sp, + ConstString(name_to_remove)); } } diff --git a/lldb/source/API/SBBreakpointName.cpp b/lldb/source/API/SBBreakpointName.cpp new file mode 100644 index 000000000000..b2ed5e71699d --- /dev/null +++ b/lldb/source/API/SBBreakpointName.cpp @@ -0,0 +1,662 @@ +//===-- SBBreakpointName.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/API/SBBreakpointName.h" +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBStream.h" +#include "lldb/API/SBStringList.h" +#include "lldb/API/SBTarget.h" + +#include "lldb/Breakpoint/BreakpointName.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadSpec.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Stream.h" + +#include "SBBreakpointOptionCommon.h" + +using namespace lldb; +using namespace lldb_private; + +namespace lldb +{ +class SBBreakpointNameImpl { +public: + SBBreakpointNameImpl(SBTarget &sb_target, const char *name) + { + if (!name || name[0] == '\0') + return; + m_name.assign(name); + + if (!sb_target.IsValid()) + return; + + TargetSP target_sp = sb_target.GetSP(); + if (!target_sp) + return; + + m_target_wp = target_sp; + } + + SBBreakpointNameImpl(TargetSP target_sp, const char *name) + { + if (!name || name[0] == '\0') + return; + m_name.assign(name); + + if (!target_sp) + return; + + m_target_wp = target_sp; + } + + bool operator==(const SBBreakpointNameImpl &rhs) { + return m_name == rhs.m_name + && m_target_wp.lock() == rhs.m_target_wp.lock(); + } + + bool operator!=(const SBBreakpointNameImpl &rhs) { + return m_name != rhs.m_name + || m_target_wp.lock() != rhs.m_target_wp.lock(); + } + // For now we take a simple approach and only keep the name, and relook + // up the location when we need it. + + TargetSP GetTarget() { + return m_target_wp.lock(); + } + + const char *GetName() { + return m_name.c_str(); + } + + bool IsValid() { + return !m_name.empty() && m_target_wp.lock(); + } + + lldb_private::BreakpointName *GetBreakpointName() + { + if (!IsValid()) + return nullptr; + TargetSP target_sp = GetTarget(); + if (!target_sp) + return nullptr; + Status error; + return target_sp->FindBreakpointName(ConstString(m_name), true, error); + } + + const lldb_private::BreakpointName *GetBreakpointName() const + { + return GetBreakpointName(); + } + +private: + TargetWP m_target_wp; + std::string m_name; +}; +} // namespace lldb + +SBBreakpointName::SBBreakpointName() {} + +SBBreakpointName::SBBreakpointName(SBTarget &sb_target, const char *name) +{ + m_impl_up.reset(new SBBreakpointNameImpl(sb_target, name)); + // Call FindBreakpointName here to make sure the name is valid, reset if + // not: + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + m_impl_up.reset(); +} + +SBBreakpointName::SBBreakpointName(SBBreakpoint &sb_bkpt, const char *name) +{ + if (!sb_bkpt.IsValid()) { + m_impl_up.reset(); + return; + } + BreakpointSP bkpt_sp = sb_bkpt.GetSP(); + Target &target = bkpt_sp->GetTarget(); + + m_impl_up.reset(new SBBreakpointNameImpl(target.shared_from_this(), name)); + + // Call FindBreakpointName here to make sure the name is valid, reset if + // not: + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) { + m_impl_up.reset(); + return; + } + + // Now copy over the breakpoint's options: + target.ConfigureBreakpointName(*bp_name, *bkpt_sp->GetOptions(), + BreakpointName::Permissions()); +} + +SBBreakpointName::SBBreakpointName(const SBBreakpointName &rhs) +{ + if (!rhs.m_impl_up) + return; + else + m_impl_up.reset(new SBBreakpointNameImpl(rhs.m_impl_up->GetTarget(), + rhs.m_impl_up->GetName())); +} + +SBBreakpointName::~SBBreakpointName() = default; + +const SBBreakpointName &SBBreakpointName::operator=(const SBBreakpointName &rhs) +{ + if (!rhs.m_impl_up) { + m_impl_up.reset(); + return *this; + } + + m_impl_up.reset(new SBBreakpointNameImpl(rhs.m_impl_up->GetTarget(), + rhs.m_impl_up->GetName())); + return *this; +} + +bool SBBreakpointName::operator==(const lldb::SBBreakpointName &rhs) { + return *m_impl_up.get() == *rhs.m_impl_up.get(); +} + +bool SBBreakpointName::operator!=(const lldb::SBBreakpointName &rhs) { + return *m_impl_up.get() != *rhs.m_impl_up.get(); +} + +bool SBBreakpointName::IsValid() const { + if (!m_impl_up) + return false; + return m_impl_up->IsValid(); +} + +const char *SBBreakpointName::GetName() const { + if (!m_impl_up) + return ""; + return m_impl_up->GetName(); +} + +void SBBreakpointName::SetEnabled(bool enable) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + + LLDB_LOG(log, "Name: {0} enabled: {1}\n", bp_name->GetName(), enable); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + bp_name->GetOptions().SetEnabled(enable); +} + +void SBBreakpointName::UpdateName(BreakpointName &bp_name) { + if (!IsValid()) + return; + + TargetSP target_sp = m_impl_up->GetTarget(); + if (!target_sp) + return; + target_sp->ApplyNameToBreakpoints(bp_name); + +} + +bool SBBreakpointName::IsEnabled() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return false; + + LLDB_LOG(log, "Name: {0}\n", bp_name->GetName()); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + return bp_name->GetOptions().IsEnabled(); +} + +void SBBreakpointName::SetOneShot(bool one_shot) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + + LLDB_LOG(log, "Name: {0} one_shot: {1}\n", bp_name->GetName(), one_shot); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + bp_name->GetOptions().SetOneShot(one_shot); + UpdateName(*bp_name); +} + +bool SBBreakpointName::IsOneShot() const { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + const BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return false; + + LLDB_LOG(log, "Name: {0}\n", bp_name->GetName()); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + return bp_name->GetOptions().IsOneShot(); +} + +void SBBreakpointName::SetIgnoreCount(uint32_t count) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + + LLDB_LOG(log, "Name: {0} one_shot: {1}\n", bp_name->GetName(), count); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + bp_name->GetOptions().SetIgnoreCount(count); + UpdateName(*bp_name); +} + +uint32_t SBBreakpointName::GetIgnoreCount() const { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return false; + + LLDB_LOG(log, "Name: {0}\n", bp_name->GetName()); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + return bp_name->GetOptions().GetIgnoreCount(); +} + +void SBBreakpointName::SetCondition(const char *condition) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + + LLDB_LOG(log, "Name: {0} one_shot: {1}\n", bp_name->GetName(), + condition ? condition : ""); + + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + bp_name->GetOptions().SetCondition(condition); + UpdateName(*bp_name); +} + +const char *SBBreakpointName::GetCondition() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return nullptr; + + LLDB_LOG(log, "Name: {0}\n", bp_name->GetName()); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + return bp_name->GetOptions().GetConditionText(); +} + +void SBBreakpointName::SetAutoContinue(bool auto_continue) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + + LLDB_LOG(log, "Name: {0} auto-continue: {1}\n", bp_name->GetName(), auto_continue); + + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + bp_name->GetOptions().SetAutoContinue(auto_continue); + UpdateName(*bp_name); +} + +bool SBBreakpointName::GetAutoContinue() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return nullptr; + + LLDB_LOG(log, "Name: {0}\n", bp_name->GetName()); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + return bp_name->GetOptions().IsAutoContinue(); +} + +void SBBreakpointName::SetThreadID(tid_t tid) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + + LLDB_LOG(log, "Name: {0} tid: {1:x}\n", bp_name->GetName(), tid); + + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + bp_name->GetOptions().SetThreadID(tid); + UpdateName(*bp_name); +} + +tid_t SBBreakpointName::GetThreadID() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return LLDB_INVALID_THREAD_ID; + + LLDB_LOG(log, "Name: {0}\n", bp_name->GetName()); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + return bp_name->GetOptions().GetThreadSpec()->GetTID(); +} + +void SBBreakpointName::SetThreadIndex(uint32_t index) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + + LLDB_LOG(log, "Name: {0} thread index: {1}\n", bp_name->GetName(), index); + + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + bp_name->GetOptions().GetThreadSpec()->SetIndex(index); + UpdateName(*bp_name); +} + +uint32_t SBBreakpointName::GetThreadIndex() const { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return LLDB_INVALID_THREAD_ID; + + LLDB_LOG(log, "Name: {0}\n", bp_name->GetName()); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + return bp_name->GetOptions().GetThreadSpec()->GetIndex(); +} + +void SBBreakpointName::SetThreadName(const char *thread_name) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + + LLDB_LOG(log, "Name: {0} thread name: {1}\n", bp_name->GetName(), thread_name); + + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + bp_name->GetOptions().GetThreadSpec()->SetName(thread_name); + UpdateName(*bp_name); +} + +const char *SBBreakpointName::GetThreadName() const { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return nullptr; + + LLDB_LOG(log, "Name: {0}\n", bp_name->GetName()); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + return bp_name->GetOptions().GetThreadSpec()->GetName(); +} + +void SBBreakpointName::SetQueueName(const char *queue_name) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + + LLDB_LOG(log, "Name: {0} queue name: {1}\n", bp_name->GetName(), queue_name); + + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + bp_name->GetOptions().GetThreadSpec()->SetQueueName(queue_name); + UpdateName(*bp_name); +} + +const char *SBBreakpointName::GetQueueName() const { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return nullptr; + + LLDB_LOG(log, "Name: {0}\n", bp_name->GetName()); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + return bp_name->GetOptions().GetThreadSpec()->GetQueueName(); +} + +void SBBreakpointName::SetCommandLineCommands(SBStringList &commands) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + if (commands.GetSize() == 0) + return; + + LLDB_LOG(log, "Name: {0} commands\n", bp_name->GetName()); + + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + std::unique_ptr cmd_data_up( + new BreakpointOptions::CommandData(*commands, eScriptLanguageNone)); + + bp_name->GetOptions().SetCommandDataCallback(cmd_data_up); + UpdateName(*bp_name); +} + +bool SBBreakpointName::GetCommandLineCommands(SBStringList &commands) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return false; + + LLDB_LOG(log, "Name: {0}\n", bp_name->GetName()); + StringList command_list; + bool has_commands = + bp_name->GetOptions().GetCommandLineCallbacks(command_list); + if (has_commands) + commands.AppendList(command_list); + return has_commands; +} + +bool SBBreakpointName::GetDescription(SBStream &s) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + { + s.Printf("No value"); + return false; + } + + LLDB_LOG(log, "Name: {0}\n", bp_name->GetName()); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + bp_name->GetDescription(s.get(), eDescriptionLevelFull); + return true; +} + +void SBBreakpointName::SetCallback(SBBreakpointHitCallback callback, + void *baton) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + LLDB_LOG(log, "callback = {1}, baton = {2}", callback, baton); + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + BatonSP baton_sp(new SBBreakpointCallbackBaton(callback, baton)); + bp_name->GetOptions().SetCallback(SBBreakpointCallbackBaton + ::PrivateBreakpointHitCallback, + baton_sp, + false); + UpdateName(*bp_name); +} + +void SBBreakpointName::SetScriptCallbackFunction( + const char *callback_function_name) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + + LLDB_LOG(log, "Name: {0} callback: {1}\n", bp_name->GetName(), + callback_function_name); + + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + BreakpointOptions &bp_options = bp_name->GetOptions(); + m_impl_up->GetTarget() + ->GetDebugger() + .GetCommandInterpreter() + .GetScriptInterpreter() + ->SetBreakpointCommandCallbackFunction(&bp_options, + callback_function_name); + UpdateName(*bp_name); +} + +SBError SBBreakpointName::SetScriptCallbackBody(const char *callback_body_text) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + SBError sb_error; + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return sb_error; + + LLDB_LOG(log, "Name: {0} callback: {1}\n", bp_name->GetName(), + callback_body_text); + + std::lock_guard guard( + m_impl_up->GetTarget()->GetAPIMutex()); + + BreakpointOptions &bp_options = bp_name->GetOptions(); + Status error = + m_impl_up->GetTarget() + ->GetDebugger() + .GetCommandInterpreter() + .GetScriptInterpreter() + ->SetBreakpointCommandCallback(&bp_options, callback_body_text); + sb_error.SetError(error); + if (!sb_error.Fail()) + UpdateName(*bp_name); + + return sb_error; +} + +bool SBBreakpointName::GetAllowList() const +{ + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return false; + return bp_name->GetPermissions().GetAllowList(); +} + +void SBBreakpointName::SetAllowList(bool value) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + if (log) + log->Printf("Setting allow list to %u for %s.", value, + bp_name->GetName().AsCString()); + bp_name->GetPermissions().SetAllowList(value); +} + +bool SBBreakpointName::GetAllowDelete() +{ + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return false; + return bp_name->GetPermissions().GetAllowDelete(); +} + +void SBBreakpointName::SetAllowDelete(bool value) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + if (log) + log->Printf("Setting allow delete to %u for %s.", value, + bp_name->GetName().AsCString()); + bp_name->GetPermissions().SetAllowDelete(value); +} + +bool SBBreakpointName::GetAllowDisable() +{ + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return false; + return bp_name->GetPermissions().GetAllowDisable(); +} + +void SBBreakpointName::SetAllowDisable(bool value) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + + BreakpointName *bp_name = GetBreakpointName(); + if (!bp_name) + return; + if (log) + log->Printf("Setting allow disable to %u for %s.", value, + bp_name->GetName().AsCString()); + bp_name->GetPermissions().SetAllowDisable(value); +} + +lldb_private::BreakpointName *SBBreakpointName::GetBreakpointName() const +{ + if (!IsValid()) + return nullptr; + return m_impl_up->GetBreakpointName(); +} + diff --git a/lldb/source/API/SBBreakpointOptionCommon.cpp b/lldb/source/API/SBBreakpointOptionCommon.cpp new file mode 100644 index 000000000000..2a12491d6ec8 --- /dev/null +++ b/lldb/source/API/SBBreakpointOptionCommon.cpp @@ -0,0 +1,84 @@ +//===-- SBBreakpointName.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/API/SBBreakpointName.h" +#include "lldb/API/SBBreakpointLocation.h" +#include "lldb/API/SBDebugger.h" +#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/BreakpointName.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadSpec.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Stream.h" + +#include "lldb/lldb-enumerations.h" + +#include "SBBreakpointOptionCommon.h" + +#include "llvm/ADT/STLExtras.h" + +using namespace lldb; +using namespace lldb_private; + +SBBreakpointCallbackBaton::SBBreakpointCallbackBaton(SBBreakpointHitCallback + callback, + void *baton) + : TypedBaton(llvm::make_unique()) { + getItem()->callback = callback; + getItem()->callback_baton = baton; + } + + bool SBBreakpointCallbackBaton::PrivateBreakpointHitCallback(void *baton, + StoppointCallbackContext *ctx, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) +{ + ExecutionContext exe_ctx(ctx->exe_ctx_ref); + BreakpointSP bp_sp( + exe_ctx.GetTargetRef().GetBreakpointList().FindBreakpointByID(break_id)); + if (baton && bp_sp) { + CallbackData *data = (CallbackData *)baton; + lldb_private::Breakpoint *bp = bp_sp.get(); + if (bp && data->callback) { + Process *process = exe_ctx.GetProcessPtr(); + if (process) { + SBProcess sb_process(process->shared_from_this()); + SBThread sb_thread; + SBBreakpointLocation sb_location; + assert(bp_sp); + sb_location.SetLocation(bp_sp->FindLocationByID(break_loc_id)); + Thread *thread = exe_ctx.GetThreadPtr(); + if (thread) + sb_thread.SetThread(thread->shared_from_this()); + + return data->callback(data->callback_baton, sb_process, sb_thread, + sb_location); + } + } + } + return true; // Return true if we should stop at this breakpoint +} + diff --git a/lldb/source/API/SBBreakpointOptionCommon.h b/lldb/source/API/SBBreakpointOptionCommon.h new file mode 100644 index 000000000000..212fe398dd7b --- /dev/null +++ b/lldb/source/API/SBBreakpointOptionCommon.h @@ -0,0 +1,35 @@ +//===-- SBBreakpointOptionCommon.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBBreakpointOptionCommons_h_ +#define LLDB_SBBreakpointOptionCommons_h_ + +#include "lldb/API/SBDefines.h" +#include "lldb/Utility/Baton.h" + +namespace lldb +{ +struct CallbackData { + SBBreakpointHitCallback callback; + void *callback_baton; +}; + +class SBBreakpointCallbackBaton : public lldb_private::TypedBaton { +public: + SBBreakpointCallbackBaton(SBBreakpointHitCallback callback, + void *baton); + + static bool PrivateBreakpointHitCallback(void *baton, + lldb_private::StoppointCallbackContext *ctx, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); +}; + +} // namespace lldb +#endif // LLDB_SBBreakpointOptionCommons_h_ diff --git a/lldb/source/API/SBDebugger.cpp b/lldb/source/API/SBDebugger.cpp index cf6a27a049b1..0185f1e9ec45 100644 --- a/lldb/source/API/SBDebugger.cpp +++ b/lldb/source/API/SBDebugger.cpp @@ -622,6 +622,20 @@ SBTarget SBDebugger::CreateTarget(const char *filename) { return sb_target; } +SBTarget SBDebugger::GetDummyTarget() { + SBTarget sb_target; + if (m_opaque_sp) { + sb_target.SetSP(m_opaque_sp->GetDummyTarget()->shared_from_this()); + } + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); + if (log) + log->Printf( + "SBDebugger(%p)::GetDummyTarget() => SBTarget(%p)", + static_cast(m_opaque_sp.get()), + static_cast(sb_target.GetSP().get())); + return sb_target; +} + bool SBDebugger::DeleteTarget(lldb::SBTarget &target) { bool result = false; if (m_opaque_sp) { diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 417a15074c73..93869d71c623 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -1087,11 +1087,38 @@ bool SBTarget::FindBreakpointsByName(const char *name, return true; } +void SBTarget::GetBreakpointNames(SBStringList &names) +{ + names.Clear(); + + TargetSP target_sp(GetSP()); + if (target_sp) { + std::lock_guard guard(target_sp->GetAPIMutex()); + + std::vector name_vec; + target_sp->GetBreakpointNames(name_vec); + for (auto name : name_vec) + names.AppendString(name.c_str()); + } +} + +void SBTarget::DeleteBreakpointName(const char *name) +{ + TargetSP target_sp(GetSP()); + if (target_sp) { + std::lock_guard guard(target_sp->GetAPIMutex()); + + std::vector name_vec; + target_sp->DeleteBreakpointName(ConstString(name)); + + } +} + bool SBTarget::EnableAllBreakpoints() { TargetSP target_sp(GetSP()); if (target_sp) { std::lock_guard guard(target_sp->GetAPIMutex()); - target_sp->EnableAllBreakpoints(); + target_sp->EnableAllowedBreakpoints(); return true; } return false; @@ -1101,7 +1128,7 @@ bool SBTarget::DisableAllBreakpoints() { TargetSP target_sp(GetSP()); if (target_sp) { std::lock_guard guard(target_sp->GetAPIMutex()); - target_sp->DisableAllBreakpoints(); + target_sp->DisableAllowedBreakpoints(); return true; } return false; @@ -1111,7 +1138,7 @@ bool SBTarget::DeleteAllBreakpoints() { TargetSP target_sp(GetSP()); if (target_sp) { std::lock_guard guard(target_sp->GetAPIMutex()); - target_sp->RemoveAllBreakpoints(); + target_sp->RemoveAllowedBreakpoints(); return true; } return false; diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp index fd606aa83d66..3f6c63e1e5ba 100644 --- a/lldb/source/Breakpoint/Breakpoint.cpp +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -210,7 +210,7 @@ lldb::BreakpointSP Breakpoint::CreateFromStructuredData( llvm::StringRef name; Status error; success = names_array->GetItemAtIndexAsString(i, name); - result_sp->AddName(name, error); + target.AddNameToBreakpoint(result_sp, name.str().c_str(), error); } } @@ -455,6 +455,10 @@ bool Breakpoint::InvokeCallback(StoppointCallbackContext *context, BreakpointOptions *Breakpoint::GetOptions() { return m_options_up.get(); } +const BreakpointOptions *Breakpoint::GetOptions() const { + return m_options_up.get(); +} + void Breakpoint::ResolveBreakpoint() { if (m_resolver_sp) m_resolver_sp->ResolveBreakpoint(*m_filter_sp); @@ -841,18 +845,8 @@ size_t Breakpoint::GetNumResolvedLocations() const { size_t Breakpoint::GetNumLocations() const { return m_locations.GetSize(); } -bool Breakpoint::AddName(llvm::StringRef new_name, Status &error) { - if (new_name.empty()) - return false; - if (!BreakpointID::StringIsBreakpointName(new_name, error)) { - error.SetErrorStringWithFormatv("input name \"{0}\" not a breakpoint name.", - new_name); - return false; - } - if (!error.Success()) - return false; - - m_name_list.insert(new_name); +bool Breakpoint::AddName(llvm::StringRef new_name) { + m_name_list.insert(new_name.str().c_str()); return true; } diff --git a/lldb/source/Breakpoint/BreakpointID.cpp b/lldb/source/Breakpoint/BreakpointID.cpp index 112f7c0b5195..b80106546822 100644 --- a/lldb/source/Breakpoint/BreakpointID.cpp +++ b/lldb/source/Breakpoint/BreakpointID.cpp @@ -101,15 +101,24 @@ BreakpointID::ParseCanonicalReference(llvm::StringRef input) { bool BreakpointID::StringIsBreakpointName(llvm::StringRef str, Status &error) { error.Clear(); if (str.empty()) + { + error.SetErrorStringWithFormat("Empty breakpoint names are not allowed"); return false; + } // First character must be a letter or _ if (!isalpha(str[0]) && str[0] != '_') + { + error.SetErrorStringWithFormat("Breakpoint names must start with a " + "character or underscore: %s", + str.str().c_str()); return false; + } // Cannot contain ., -, or space. if (str.find_first_of(".- ") != llvm::StringRef::npos) { - error.SetErrorStringWithFormat("invalid breakpoint name: \"%s\"", + error.SetErrorStringWithFormat("Breakpoint names cannot contain " + "'.' or '-': \"%s\"", str.str().c_str()); return false; } diff --git a/lldb/source/Breakpoint/BreakpointIDList.cpp b/lldb/source/Breakpoint/BreakpointIDList.cpp index 7b461147a4e9..0a704fdc9186 100644 --- a/lldb/source/Breakpoint/BreakpointIDList.cpp +++ b/lldb/source/Breakpoint/BreakpointIDList.cpp @@ -11,6 +11,7 @@ // C++ Includes // Other libraries and framework includes // Project includes +#include "lldb/lldb-enumerations.h" #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/Breakpoint.h" @@ -117,6 +118,8 @@ void BreakpointIDList::InsertStringArray(const char **string_array, void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target, bool allow_locations, + BreakpointName::Permissions + ::PermissionKinds purpose, CommandReturnObject &result, Args &new_args) { llvm::StringRef range_from; @@ -302,14 +305,29 @@ void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target, } // 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.GetString()); + if (target && !names_found.empty()) { + Status error; + // Remove any names that aren't visible for this purpose: + auto iter = names_found.begin(); + while (iter != names_found.end()) { + BreakpointName *bp_name = target->FindBreakpointName(ConstString(*iter), + true, + error); + if (bp_name && !bp_name->GetPermission(purpose)) + iter = names_found.erase(iter); + else + iter++; + } + + if (!names_found.empty()) { + 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.GetString()); + } } } } diff --git a/lldb/source/Breakpoint/BreakpointList.cpp b/lldb/source/Breakpoint/BreakpointList.cpp index 15bcb34a3d85..01ac59f0a903 100644 --- a/lldb/source/Breakpoint/BreakpointList.cpp +++ b/lldb/source/Breakpoint/BreakpointList.cpp @@ -71,6 +71,13 @@ void BreakpointList::SetEnabledAll(bool enabled) { bp_sp->SetEnabled(enabled); } +void BreakpointList::SetEnabledAllowed(bool enabled) { + std::lock_guard guard(m_mutex); + for (const auto &bp_sp : m_breakpoints) + if (bp_sp->AllowDisable()) + bp_sp->SetEnabled(enabled); +} + void BreakpointList::RemoveAll(bool notify) { std::lock_guard guard(m_mutex); ClearAllBreakpointSites(); @@ -90,6 +97,32 @@ void BreakpointList::RemoveAll(bool notify) { m_breakpoints.erase(m_breakpoints.begin(), m_breakpoints.end()); } +void BreakpointList::RemoveAllowed(bool notify) { + std::lock_guard guard(m_mutex); + + bp_collection::iterator pos, end = m_breakpoints.end(); + if (notify) { + for (pos = m_breakpoints.begin(); pos != end; ++pos) { + if(!(*pos)->AllowDelete()) + continue; + if ((*pos)->GetTarget().EventTypeHasListeners( + Target::eBroadcastBitBreakpointChanged)) { + (*pos)->GetTarget().BroadcastEvent( + Target::eBroadcastBitBreakpointChanged, + new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved, + *pos)); + } + } + } + pos = m_breakpoints.begin(); + while ( pos != end) { + if((*pos)->AllowDelete()) + pos = m_breakpoints.erase(pos); + else + pos++; + } +} + class BreakpointIDMatches { public: BreakpointIDMatches(break_id_t break_id) : m_break_id(break_id) {} diff --git a/lldb/source/Breakpoint/BreakpointName.cpp b/lldb/source/Breakpoint/BreakpointName.cpp new file mode 100644 index 000000000000..7b9a2acfbc4a --- /dev/null +++ b/lldb/source/Breakpoint/BreakpointName.cpp @@ -0,0 +1,88 @@ +//===-- Breakpoint.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details-> +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "llvm/Support/Casting.h" + +// Project includes +#include "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Breakpoint/BreakpointOptions.h" +#include "lldb/Breakpoint/BreakpointLocationCollection.h" +#include "lldb/Breakpoint/BreakpointResolver.h" +#include "lldb/Breakpoint/BreakpointResolverFileLine.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StreamString.h" + +using namespace lldb; +using namespace lldb_private; + +const Flags::ValueType BreakpointName::Permissions::permissions_mask + [BreakpointName::Permissions::PermissionKinds::allPerms + 1] = { + (1u << 0), + (1u << 1), + (1u << 2), + (0x5u) +}; + +BreakpointName::BreakpointName(const ConstString &name, const Breakpoint &bkpt, + const char *help) : + m_name(name), m_options(bkpt.GetOptions()) +{ + SetHelp(help); +} + +bool BreakpointName::Permissions::GetDescription(Stream *s, + lldb::DescriptionLevel level) { + if (!AnySet()) + return false; + s->IndentMore(); + s->Indent(); + if (IsSet(listPerm)) + s->Printf("list: %s", GetAllowList() ? "allowed" : "disallowed"); + + if (IsSet(disablePerm)) + s->Printf("disable: %s", GetAllowDisable() ? "allowed" : "disallowed"); + + if (IsSet(deletePerm)) + s->Printf("delete: %s", GetAllowDelete() ? "allowed" : "disallowed"); + s->IndentLess(); + return true; +} + +bool BreakpointName::GetDescription(Stream *s, lldb::DescriptionLevel level) { + bool printed_any = false; + if (GetOptions().AnySet()) + { + s->PutCString("Options: \n"); + s->IndentMore(); + s->Indent(); + GetOptions().GetDescription(s, level); + printed_any = true; + s->IndentLess(); + } + if (GetPermissions().AnySet()) + { + s->PutCString("Permissions: \n"); + s->IndentMore(); + s->Indent(); + GetPermissions().GetDescription(s, level); + printed_any = true; + s->IndentLess(); + } + return printed_any; +} + +void BreakpointName::ConfigureBreakpoint(lldb::BreakpointSP bp_sp) +{ + bp_sp->GetOptions()->CopyOverSetOptions(GetOptions()); + bp_sp->GetPermissions().MergeInto(GetPermissions()); +} diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp index 7159688102d5..662b288794d3 100644 --- a/lldb/source/Breakpoint/BreakpointOptions.cpp +++ b/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -132,7 +132,7 @@ BreakpointOptions::BreakpointOptions(bool all_flags_set) m_baton_is_command_baton(false), m_callback_is_synchronous(false), m_enabled(true), m_one_shot(false), m_ignore_count(0), m_thread_spec_ap(), m_condition_text(), m_condition_text_hash(0), m_auto_continue(false), - m_set_flags() { + m_set_flags(0) { if (all_flags_set) m_set_flags.Set(~((Flags::ValueType) 0)); } @@ -142,11 +142,14 @@ BreakpointOptions::BreakpointOptions(const char *condition, bool enabled, bool auto_continue) : m_callback(nullptr), m_baton_is_command_baton(false), m_callback_is_synchronous(false), m_enabled(enabled), - m_one_shot(one_shot), m_ignore_count(ignore), m_condition_text(condition), + m_one_shot(one_shot), m_ignore_count(ignore), m_condition_text_hash(0), m_auto_continue(auto_continue) { m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot - | eCondition | eAutoContinue); + | eAutoContinue); + if (condition && *condition != '\0') { + SetCondition(condition); + } } //---------------------------------------------------------------------- @@ -187,6 +190,59 @@ operator=(const BreakpointOptions &rhs) { return *this; } +void BreakpointOptions::CopyOverSetOptions(const BreakpointOptions &incoming) +{ + if (incoming.m_set_flags.Test(eEnabled)) + { + m_enabled = incoming.m_enabled; + m_set_flags.Set(eEnabled); + } + if (incoming.m_set_flags.Test(eOneShot)) + { + m_one_shot = incoming.m_one_shot; + m_set_flags.Set(eOneShot); + } + if (incoming.m_set_flags.Test(eCallback)) + { + m_callback = incoming.m_callback; + m_callback_baton_sp = incoming.m_callback_baton_sp; + m_callback_is_synchronous = incoming.m_callback_is_synchronous; + m_baton_is_command_baton = incoming.m_baton_is_command_baton; + m_set_flags.Set(eCallback); + } + if (incoming.m_set_flags.Test(eIgnoreCount)) + { + m_ignore_count = incoming.m_ignore_count; + m_set_flags.Set(eIgnoreCount); + } + if (incoming.m_set_flags.Test(eCondition)) + { + // If we're copying over an empty condition, mark it as unset. + if (incoming.m_condition_text.empty()) { + m_condition_text.clear(); + m_condition_text_hash = 0; + m_set_flags.Clear(eCondition); + } else { + m_condition_text = incoming.m_condition_text; + m_condition_text_hash = incoming.m_condition_text_hash; + m_set_flags.Set(eCondition); + } + } + if (incoming.m_set_flags.Test(eAutoContinue)) + { + m_auto_continue = incoming.m_auto_continue; + m_set_flags.Set(eAutoContinue); + } + if (incoming.m_set_flags.Test(eThreadSpec) && incoming.m_thread_spec_ap) + { + if (!m_thread_spec_ap) + m_thread_spec_ap.reset(new ThreadSpec(*incoming.m_thread_spec_ap.get())); + else + *m_thread_spec_ap.get() = *incoming.m_thread_spec_ap.get(); + m_set_flags.Set(eThreadSpec); + } +} + //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- @@ -327,23 +383,23 @@ std::unique_ptr BreakpointOptions::CreateFromStructuredData( StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() { StructuredData::DictionarySP options_dict_sp( new StructuredData::Dictionary()); - if (m_set_flags.Set(eEnabled)) + if (m_set_flags.Test(eEnabled)) options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState), m_enabled); - if (m_set_flags.Set(eOneShot)) + if (m_set_flags.Test(eOneShot)) options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState), m_one_shot); - if (m_set_flags.Set(eAutoContinue)) + if (m_set_flags.Test(eAutoContinue)) options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue), m_auto_continue); - if (m_set_flags.Set(eIgnoreCount)) + if (m_set_flags.Test(eIgnoreCount)) options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount), m_ignore_count); - if (m_set_flags.Set(eCondition)) + if (m_set_flags.Test(eCondition)) options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText), m_condition_text); - if (m_set_flags.Set(eCallback) && m_baton_is_command_baton) { + if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) { auto cmd_baton = std::static_pointer_cast(m_callback_baton_sp); StructuredData::ObjectSP commands_sp = @@ -353,7 +409,7 @@ StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() { BreakpointOptions::CommandData::GetSerializationKey(), commands_sp); } } - if (m_set_flags.Set(eThreadSpec) && m_thread_spec_ap) { + if (m_set_flags.Test(eThreadSpec) && m_thread_spec_ap) { StructuredData::ObjectSP thread_spec_sp = m_thread_spec_ap->SerializeToStructuredData(); options_dict_sp->AddItem(ThreadSpec::GetSerializationKey(), thread_spec_sp); @@ -618,3 +674,18 @@ bool BreakpointOptions::BreakpointOptionsCallbackFunction( } return ret_value; } + +void BreakpointOptions::Clear() +{ + m_set_flags.Clear(); + m_thread_spec_ap.release(); + m_one_shot = false; + m_ignore_count = 0; + m_auto_continue = false; + m_callback = nullptr; + m_callback_baton_sp.reset(); + m_baton_is_command_baton = false; + m_callback_is_synchronous = false; + m_enabled = false; + m_condition_text.clear(); +} diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index d53e681514db..f4276e4e979c 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -45,6 +45,203 @@ static void AddBreakpointDescription(Stream *s, Breakpoint *bp, s->EOL(); } +//------------------------------------------------------------------------- +// Modifiable Breakpoint Options +//------------------------------------------------------------------------- +#pragma mark Modify::CommandOptions +static OptionDefinition g_breakpoint_modify_options[] = { + // clang-format off + { LLDB_OPT_SET_1, false, "ignore-count", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." }, + { LLDB_OPT_SET_1, false, "one-shot", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "The breakpoint is deleted the first time it stop causes a stop." }, + { LLDB_OPT_SET_1, false, "thread-index", 'x', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose index matches this argument." }, + { LLDB_OPT_SET_1, false, "thread-id", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadID, "The breakpoint stops only for the thread whose TID matches this argument." }, + { LLDB_OPT_SET_1, false, "thread-name", 'T', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadName, "The breakpoint stops only for the thread whose thread name matches this argument." }, + { LLDB_OPT_SET_1, false, "queue-name", 'q', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeQueueName, "The breakpoint stops only for threads in the queue whose name is given by this argument." }, + { LLDB_OPT_SET_1, false, "condition", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true." }, + { LLDB_OPT_SET_1, false, "auto-continue",'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "The breakpoint will auto-continue after running its commands." }, + { LLDB_OPT_SET_2, false, "enable", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable the breakpoint." }, + { LLDB_OPT_SET_3, false, "disable", 'd', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Disable the breakpoint." }, + { LLDB_OPT_SET_4, false, "command", 'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCommand, "A command to run when the breakpoint is hit, can be provided more than once, the commands will get run in order left to right." }, + // clang-format on +}; +class lldb_private::BreakpointOptionGroup : public OptionGroup +{ +public: + BreakpointOptionGroup() : + OptionGroup(), + m_bp_opts(false) {} + + ~BreakpointOptionGroup() override = default; + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_breakpoint_modify_options); + } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = g_breakpoint_modify_options[option_idx].short_option; + + switch (short_option) { + case 'c': + // Normally an empty breakpoint condition marks is as unset. + // But we need to say it was passed in. + m_bp_opts.SetCondition(option_arg.str().c_str()); + m_bp_opts.m_set_flags.Set(BreakpointOptions::eCondition); + break; + case 'C': + m_commands.push_back(option_arg); + break; + case 'd': + m_bp_opts.SetEnabled(false); + break; + case 'e': + m_bp_opts.SetEnabled(true); + break; + case 'G': { + bool value, success; + value = Args::StringToBoolean(option_arg, false, &success); + if (success) { + m_bp_opts.SetAutoContinue(value); + } else + error.SetErrorStringWithFormat( + "invalid boolean value '%s' passed for -G option", + option_arg.str().c_str()); + } + break; + case 'i': + { + uint32_t ignore_count; + if (option_arg.getAsInteger(0, ignore_count)) + error.SetErrorStringWithFormat("invalid ignore count '%s'", + option_arg.str().c_str()); + else + m_bp_opts.SetIgnoreCount(ignore_count); + } + break; + case 'o': { + bool value, success; + value = Args::StringToBoolean(option_arg, false, &success); + if (success) { + m_bp_opts.SetOneShot(value); + } else + error.SetErrorStringWithFormat( + "invalid boolean value '%s' passed for -o option", + option_arg.str().c_str()); + } break; + case 't': + { + lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID; + if (option_arg[0] != '\0') { + if (option_arg.getAsInteger(0, thread_id)) + error.SetErrorStringWithFormat("invalid thread id string '%s'", + option_arg.str().c_str()); + } + m_bp_opts.SetThreadID(thread_id); + } + break; + case 'T': + m_bp_opts.GetThreadSpec()->SetName(option_arg.str().c_str()); + break; + case 'q': + m_bp_opts.GetThreadSpec()->SetQueueName(option_arg.str().c_str()); + break; + case 'x': + { + uint32_t thread_index = UINT32_MAX; + if (option_arg[0] != '\n') { + if (option_arg.getAsInteger(0, thread_index)) + error.SetErrorStringWithFormat("invalid thread index string '%s'", + option_arg.str().c_str()); + } + m_bp_opts.GetThreadSpec()->SetIndex(thread_index); + } + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_bp_opts.Clear(); + m_commands.clear(); + } + + Status OptionParsingFinished(ExecutionContext *execution_context) override { + if (!m_commands.empty()) + { + if (!m_commands.empty()) + { + auto cmd_data = llvm::make_unique(); + + for (std::string &str : m_commands) + cmd_data->user_source.AppendString(str); + + cmd_data->stop_on_error = true; + m_bp_opts.SetCommandDataCallback(cmd_data); + } + } + return Status(); + } + + const BreakpointOptions &GetBreakpointOptions() + { + return m_bp_opts; + } + + std::vector m_commands; + BreakpointOptions m_bp_opts; + +}; +static OptionDefinition g_breakpoint_dummy_options[] = { + // clang-format off + { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Act on Dummy breakpoints - i.e. breakpoints set before a file is provided, " + "which prime new targets." }, + // clang-format on +}; + +class BreakpointDummyOptionGroup : public OptionGroup +{ +public: + BreakpointDummyOptionGroup() : + OptionGroup() {} + + ~BreakpointDummyOptionGroup() override = default; + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_breakpoint_dummy_options); + } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = g_breakpoint_modify_options[option_idx].short_option; + + switch (short_option) { + case 'D': + m_use_dummy = true; + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_use_dummy = false; + } + + bool m_use_dummy; + +}; + // If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to // update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately. #define LLDB_OPT_FILE (LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2) @@ -58,18 +255,7 @@ static OptionDefinition g_breakpoint_set_options[] = { // clang-format off { LLDB_OPT_NOT_10, false, "shlib", 's', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Set the breakpoint only in this shared library. Can repeat this option " "multiple times to specify multiple shared libraries." }, - { LLDB_OPT_SET_ALL, false, "ignore-count", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." }, - { LLDB_OPT_SET_ALL, false, "one-shot", 'o', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "The breakpoint is deleted the first time it causes a stop." }, - { LLDB_OPT_SET_ALL, false, "auto-continue", 'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "The breakpoint will auto-continue after running its commands." }, - { LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true." }, - { LLDB_OPT_SET_ALL, false, "command", 'd', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCommand, "A command to run when the breakpoint is hit, can be provided more than once, the commands will get run in order left to right." }, - { LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose indeX matches this argument." }, - { LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadID, "The breakpoint stops only for the thread whose TID matches this argument." }, - { LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadName, "The breakpoint stops only for the thread whose thread name matches this " - "argument." }, { LLDB_OPT_SET_ALL, false, "hardware", 'H', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Require the breakpoint to use hardware breakpoints." }, - { LLDB_OPT_SET_ALL, false, "queue-name", 'q', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeQueueName, "The breakpoint stops only for threads in the queue whose name is given by " - "this argument." }, { LLDB_OPT_FILE, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specifies the source file in which to set this breakpoint. Note, by default " "lldb only looks for files that are #included if they use the standard include " "file extensions. To set breakpoints on .c/.cpp/.m/.mm files that are " @@ -127,8 +313,6 @@ static OptionDefinition g_breakpoint_set_options[] = { "If not set the target.language setting is used." }, { LLDB_OPT_SKIP_PROLOGUE, false, "skip-prologue", 'K', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "sKip the prologue if the breakpoint is at the beginning of a function. " "If not set the target.skip-prologue setting is used." }, - { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 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, nullptr, nullptr, 0, eArgTypeBreakpointName, "Adds this to the list of names for this breakpoint." }, { LLDB_OPT_OFFSET_APPLIES, false, "address-slide", 'R', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeAddress, "Add the specified offset to whatever address(es) the breakpoint resolves to. " "At present this applies the offset directly as given, and doesn't try to align it to instruction boundaries." }, @@ -158,24 +342,30 @@ public: interpreter, "breakpoint set", "Sets a breakpoint or set of breakpoints in the executable.", "breakpoint set "), - m_options() {} + m_bp_opts(), m_options() { + // We're picking up all the normal options, commands and disable. + m_all_options.Append(&m_bp_opts, + LLDB_OPT_SET_1 | LLDB_OPT_SET_3 | LLDB_OPT_SET_4, + LLDB_OPT_SET_ALL); + m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); + m_all_options.Append(&m_options); + m_all_options.Finalize(); + } ~CommandObjectBreakpointSet() override = default; - Options *GetOptions() override { return &m_options; } + Options *GetOptions() override { return &m_all_options; } - class CommandOptions : public Options { + class CommandOptions : public OptionGroup { public: CommandOptions() - : Options(), m_condition(), m_filenames(), m_line_num(0), m_column(0), + : OptionGroup(), m_condition(), m_filenames(), m_line_num(0), m_column(0), m_func_names(), m_func_name_type_mask(eFunctionNameTypeNone), m_func_regexp(), m_source_text_regexp(), m_modules(), m_load_addr(), - m_ignore_count(0), m_thread_id(LLDB_INVALID_THREAD_ID), - m_thread_index(UINT32_MAX), m_thread_name(), m_queue_name(), m_catch_bp(false), m_throw_bp(true), m_hardware(false), m_exception_language(eLanguageTypeUnknown), m_language(lldb::eLanguageTypeUnknown), - m_skip_prologue(eLazyBoolCalculate), m_one_shot(false), + m_skip_prologue(eLazyBoolCalculate), m_all_files(false), m_move_to_nearest_code(eLazyBoolCalculate) {} ~CommandOptions() override = default; @@ -183,7 +373,7 @@ public: Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override { Status error; - const int short_option = m_getopt_table[option_idx].val; + const int short_option = g_breakpoint_set_options[option_idx].short_option; switch (short_option) { case 'a': { @@ -206,18 +396,6 @@ public: option_arg.str().c_str()); break; - case 'c': - m_condition.assign(option_arg); - break; - - case 'd': - m_commands.push_back(option_arg); - break; - - case 'D': - m_use_dummy = true; - break; - case 'E': { LanguageType language = Language::GetLanguageTypeFromString(option_arg); @@ -262,15 +440,6 @@ public: m_func_name_type_mask |= eFunctionNameTypeFull; break; - case 'G' : { - bool success; - m_auto_continue = Args::StringToBoolean(option_arg, true, &success); - if (!success) - error.SetErrorStringWithFormat( - "Invalid boolean value for auto-continue option: '%s'", - option_arg.str().c_str()); - } break; - case 'h': { bool success; m_catch_bp = Args::StringToBoolean(option_arg, true, &success); @@ -284,12 +453,6 @@ public: m_hardware = true; break; - case 'i': - if (option_arg.getAsInteger(0, m_ignore_count)) - error.SetErrorStringWithFormat("invalid ignore count '%s'", - option_arg.str().c_str()); - break; - case 'K': { bool success; bool value; @@ -362,10 +525,6 @@ public: m_offset_addr = tmp_offset_addr; } break; - case 'o': - m_one_shot = true; - break; - case 'O': m_exception_extra_args.AppendArgument("-O"); m_exception_extra_args.AppendArgument(option_arg); @@ -375,10 +534,6 @@ public: m_source_text_regexp.assign(option_arg); break; - case 'q': - m_queue_name.assign(option_arg); - break; - case 'r': m_func_regexp.assign(option_arg); break; @@ -392,16 +547,6 @@ public: m_func_name_type_mask |= eFunctionNameTypeSelector; break; - case 't': - if (option_arg.getAsInteger(0, m_thread_id)) - error.SetErrorStringWithFormat("invalid thread id string '%s'", - option_arg.str().c_str()); - break; - - case 'T': - m_thread_name.assign(option_arg); - break; - case 'w': { bool success; m_throw_bp = Args::StringToBoolean(option_arg, true, &success); @@ -411,12 +556,6 @@ public: option_arg.str().c_str()); } break; - case 'x': - if (option_arg.getAsInteger(0, m_thread_index)) - error.SetErrorStringWithFormat("invalid thread index string '%s'", - option_arg.str().c_str()); - break; - case 'X': m_source_regex_func_names.insert(option_arg); break; @@ -431,7 +570,6 @@ public: } void OptionParsingStarting(ExecutionContext *execution_context) override { - m_condition.clear(); m_filenames.Clear(); m_line_num = 0; m_column = 0; @@ -442,26 +580,17 @@ public: m_modules.Clear(); m_load_addr = LLDB_INVALID_ADDRESS; m_offset_addr = 0; - m_ignore_count = 0; - m_thread_id = LLDB_INVALID_THREAD_ID; - m_thread_index = UINT32_MAX; - m_thread_name.clear(); - m_queue_name.clear(); m_catch_bp = false; m_throw_bp = true; m_hardware = false; m_exception_language = eLanguageTypeUnknown; m_language = lldb::eLanguageTypeUnknown; m_skip_prologue = eLazyBoolCalculate; - m_one_shot = false; - m_use_dummy = false; m_breakpoint_names.clear(); m_all_files = false; m_exception_extra_args.Clear(); m_move_to_nearest_code = eLazyBoolCalculate; m_source_regex_func_names.clear(); - m_commands.clear(); - m_auto_continue = false; } llvm::ArrayRef GetDefinitions() override { @@ -482,30 +611,21 @@ public: FileSpecList m_modules; lldb::addr_t m_load_addr; lldb::addr_t m_offset_addr; - uint32_t m_ignore_count; - lldb::tid_t m_thread_id; - uint32_t m_thread_index; - std::string m_thread_name; - std::string m_queue_name; bool m_catch_bp; bool m_throw_bp; bool m_hardware; // Request to use hardware breakpoints lldb::LanguageType m_exception_language; lldb::LanguageType m_language; LazyBool m_skip_prologue; - bool m_one_shot; - bool m_use_dummy; bool m_all_files; Args m_exception_extra_args; LazyBool m_move_to_nearest_code; std::unordered_set m_source_regex_func_names; - std::vector m_commands; - bool m_auto_continue; }; protected: bool DoExecute(Args &command, CommandReturnObject &result) override { - Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); + Target *target = GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy); if (target == nullptr) { result.AppendError("Invalid target. Must set target before setting " @@ -540,7 +660,7 @@ protected: else if (m_options.m_exception_language != eLanguageTypeUnknown) break_type = eSetTypeException; - Breakpoint *bp = nullptr; + BreakpointSP bp_sp = nullptr; FileSpec module_spec; const bool internal = false; @@ -572,35 +692,32 @@ protected: // Only check for inline functions if LazyBool check_inlines = eLazyBoolCalculate; - bp = target - ->CreateBreakpoint(&(m_options.m_modules), file, - m_options.m_line_num, m_options.m_offset_addr, - check_inlines, m_options.m_skip_prologue, - internal, m_options.m_hardware, - m_options.m_move_to_nearest_code) - .get(); + bp_sp = target->CreateBreakpoint(&(m_options.m_modules), + file, + m_options.m_line_num, + m_options.m_offset_addr, + check_inlines, + m_options.m_skip_prologue, + internal, + m_options.m_hardware, + m_options.m_move_to_nearest_code); } break; case eSetTypeAddress: // Breakpoint by address { // If a shared library has been specified, make an lldb_private::Address - // with the library, and - // use that. That way the address breakpoint will track the load location - // of the library. + // with the library, and use that. That way the address breakpoint + // will track the load location of the library. size_t num_modules_specified = m_options.m_modules.GetSize(); if (num_modules_specified == 1) { const FileSpec *file_spec = m_options.m_modules.GetFileSpecPointerAtIndex(0); - bp = target - ->CreateAddressInModuleBreakpoint(m_options.m_load_addr, - internal, file_spec, - m_options.m_hardware) - .get(); + bp_sp = target->CreateAddressInModuleBreakpoint(m_options.m_load_addr, + internal, file_spec, + m_options.m_hardware); } else if (num_modules_specified == 0) { - bp = target - ->CreateBreakpoint(m_options.m_load_addr, internal, - m_options.m_hardware) - .get(); + bp_sp = target->CreateBreakpoint(m_options.m_load_addr, internal, + m_options.m_hardware); } else { result.AppendError("Only one shared library can be specified for " "address breakpoints."); @@ -616,13 +733,15 @@ protected: if (name_type_mask == 0) name_type_mask = eFunctionNameTypeAuto; - bp = target - ->CreateBreakpoint( - &(m_options.m_modules), &(m_options.m_filenames), - m_options.m_func_names, name_type_mask, m_options.m_language, - m_options.m_offset_addr, m_options.m_skip_prologue, internal, - m_options.m_hardware) - .get(); + bp_sp = target->CreateBreakpoint(&(m_options.m_modules), + &(m_options.m_filenames), + m_options.m_func_names, + name_type_mask, + m_options.m_language, + m_options.m_offset_addr, + m_options.m_skip_prologue, + internal, + m_options.m_hardware); } break; case eSetTypeFunctionRegexp: // Breakpoint by regular expression function @@ -639,12 +758,13 @@ protected: return false; } - bp = target - ->CreateFuncRegexBreakpoint( - &(m_options.m_modules), &(m_options.m_filenames), regexp, - m_options.m_language, m_options.m_skip_prologue, internal, - m_options.m_hardware) - .get(); + bp_sp = target->CreateFuncRegexBreakpoint(&(m_options.m_modules), + &(m_options.m_filenames), + regexp, + m_options.m_language, + m_options.m_skip_prologue, + internal, + m_options.m_hardware); } break; case eSetTypeSourceRegexp: // Breakpoint by regexp on source text. @@ -673,26 +793,30 @@ protected: result.SetStatus(eReturnStatusFailed); return false; } - bp = target - ->CreateSourceRegexBreakpoint( - &(m_options.m_modules), &(m_options.m_filenames), - m_options.m_source_regex_func_names, regexp, internal, - m_options.m_hardware, m_options.m_move_to_nearest_code) - .get(); + bp_sp = + target->CreateSourceRegexBreakpoint(&(m_options.m_modules), + &(m_options.m_filenames), + m_options + .m_source_regex_func_names, + regexp, + internal, + m_options.m_hardware, + m_options.m_move_to_nearest_code); } break; case eSetTypeException: { Status precond_error; - bp = target - ->CreateExceptionBreakpoint( - m_options.m_exception_language, m_options.m_catch_bp, - m_options.m_throw_bp, internal, - &m_options.m_exception_extra_args, &precond_error) - .get(); + bp_sp = target->CreateExceptionBreakpoint(m_options.m_exception_language, + m_options.m_catch_bp, + m_options.m_throw_bp, + internal, + &m_options + .m_exception_extra_args, + &precond_error); if (precond_error.Fail()) { result.AppendErrorWithFormat( "Error setting extra exception arguments: %s", precond_error.AsCString()); - target->RemoveBreakpointByID(bp->GetID()); + target->RemoveBreakpointByID(bp_sp->GetID()); result.SetStatus(eReturnStatusFailed); return false; } @@ -702,76 +826,43 @@ protected: } // Now set the various options that were passed in: - if (bp) { - if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID) - bp->SetThreadID(m_options.m_thread_id); - - if (m_options.m_thread_index != UINT32_MAX) - bp->GetOptions()->GetThreadSpec()->SetIndex(m_options.m_thread_index); - - if (!m_options.m_thread_name.empty()) - bp->GetOptions()->GetThreadSpec()->SetName( - m_options.m_thread_name.c_str()); - - if (!m_options.m_queue_name.empty()) - bp->GetOptions()->GetThreadSpec()->SetQueueName( - m_options.m_queue_name.c_str()); - - if (m_options.m_ignore_count != 0) - bp->GetOptions()->SetIgnoreCount(m_options.m_ignore_count); - - if (!m_options.m_condition.empty()) - bp->GetOptions()->SetCondition(m_options.m_condition.c_str()); + if (bp_sp) { + bp_sp->GetOptions()->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions()); if (!m_options.m_breakpoint_names.empty()) { Status name_error; for (auto name : m_options.m_breakpoint_names) { - bp->AddName(name.c_str(), name_error); + target->AddNameToBreakpoint(bp_sp, name.c_str(), name_error); if (name_error.Fail()) { result.AppendErrorWithFormat("Invalid breakpoint name: %s", name.c_str()); - target->RemoveBreakpointByID(bp->GetID()); + target->RemoveBreakpointByID(bp_sp->GetID()); result.SetStatus(eReturnStatusFailed); return false; } } } - - bp->SetOneShot(m_options.m_one_shot); - bp->SetAutoContinue(m_options.m_auto_continue); - - if (!m_options.m_commands.empty()) - { - auto cmd_data = llvm::make_unique(); - - for (std::string &str : m_options.m_commands) - cmd_data->user_source.AppendString(str); - - cmd_data->stop_on_error = true; - bp->GetOptions()->SetCommandDataCallback(cmd_data); - } } - - if (bp) { + + if (bp_sp) { Stream &output_stream = result.GetOutputStream(); const bool show_locations = false; - bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, + bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, show_locations); if (target == m_interpreter.GetDebugger().GetDummyTarget()) output_stream.Printf("Breakpoint set in dummy target, will get copied " "into future targets.\n"); else { // Don't print out this warning for exception breakpoints. They can get - // set before the target - // is set, but we won't know how to actually set the breakpoint till we - // run. - if (bp->GetNumLocations() == 0 && break_type != eSetTypeException) { + // set before the target is set, but we won't know how to actually set + // the breakpoint till we run. + if (bp_sp->GetNumLocations() == 0 && break_type != eSetTypeException) { output_stream.Printf("WARNING: Unable to resolve breakpoint to any " "actual locations.\n"); } } result.SetStatus(eReturnStatusSuccessFinishResult); - } else if (!bp) { + } else if (!bp_sp) { result.AppendError("Breakpoint creation failed: No breakpoint created."); result.SetStatus(eReturnStatusFailed); } @@ -813,30 +904,15 @@ private: return true; } + BreakpointOptionGroup m_bp_opts; + BreakpointDummyOptionGroup m_dummy_options; CommandOptions m_options; + OptionGroupOptions m_all_options; }; //------------------------------------------------------------------------- // CommandObjectBreakpointModify //------------------------------------------------------------------------- - -#pragma mark Modify::CommandOptions -static OptionDefinition g_breakpoint_modify_options[] = { - // clang-format off - { LLDB_OPT_SET_ALL, false, "ignore-count", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." }, - { LLDB_OPT_SET_ALL, false, "one-shot", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "The breakpoint is deleted the first time it stop causes a stop." }, - { LLDB_OPT_SET_ALL, false, "thread-index", 'x', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose index matches this argument." }, - { LLDB_OPT_SET_ALL, false, "thread-id", 't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadID, "The breakpoint stops only for the thread whose TID matches this argument." }, - { LLDB_OPT_SET_ALL, false, "thread-name", 'T', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadName, "The breakpoint stops only for the thread whose thread name matches this argument." }, - { LLDB_OPT_SET_ALL, false, "queue-name", 'q', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeQueueName, "The breakpoint stops only for threads in the queue whose name is given by this argument." }, - { LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true." }, - { LLDB_OPT_SET_1, false, "enable", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable the breakpoint." }, - { LLDB_OPT_SET_2, false, "disable", 'd', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Disable the breakpoint." }, - { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Sets Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets." }, - { LLDB_OPT_SET_ALL, false, "auto-continue", 'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "The breakpoint will auto-continue after running its commands." }, - // clang-format on -}; - #pragma mark Modify class CommandObjectBreakpointModify : public CommandObjectParsed { @@ -857,163 +933,21 @@ public: // Add the entry for the first argument for this command to the object's // arguments vector. m_arguments.push_back(arg); + + m_options.Append(&m_bp_opts, + LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, + LLDB_OPT_SET_ALL); + m_options.Append(&m_dummy_opts, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); + m_options.Finalize(); } ~CommandObjectBreakpointModify() override = default; Options *GetOptions() override { return &m_options; } - class CommandOptions : public Options { - public: - CommandOptions() - : Options(), m_ignore_count(0), m_thread_id(LLDB_INVALID_THREAD_ID), - m_thread_id_passed(false), m_thread_index(UINT32_MAX), - m_thread_index_passed(false), m_thread_name(), m_queue_name(), - m_condition(), m_one_shot(false), m_enable_passed(false), - m_enable_value(false), m_name_passed(false), m_queue_passed(false), - m_condition_passed(false), m_one_shot_passed(false), - m_use_dummy(false) {} - - ~CommandOptions() override = default; - - Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *execution_context) override { - Status error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) { - case 'c': - m_condition = option_arg; - m_condition_passed = true; - break; - case 'd': - m_enable_passed = true; - m_enable_value = false; - break; - case 'D': - m_use_dummy = true; - break; - case 'e': - m_enable_passed = true; - m_enable_value = true; - break; - case 'G': { - bool value, success; - value = Args::StringToBoolean(option_arg, false, &success); - if (success) { - m_auto_continue_passed = true; - m_auto_continue = value; - } else - error.SetErrorStringWithFormat( - "invalid boolean value '%s' passed for -G option", - option_arg.str().c_str()); - } break; - case 'i': - if (option_arg.getAsInteger(0, m_ignore_count)) - error.SetErrorStringWithFormat("invalid ignore count '%s'", - option_arg.str().c_str()); - break; - case 'o': { - bool value, success; - value = Args::StringToBoolean(option_arg, false, &success); - if (success) { - m_one_shot_passed = true; - m_one_shot = value; - } else - error.SetErrorStringWithFormat( - "invalid boolean value '%s' passed for -o option", - option_arg.str().c_str()); - } break; - case 't': - if (option_arg[0] == '\0') { - m_thread_id = LLDB_INVALID_THREAD_ID; - m_thread_id_passed = true; - } else { - if (option_arg.getAsInteger(0, m_thread_id)) - error.SetErrorStringWithFormat("invalid thread id string '%s'", - option_arg.str().c_str()); - else - m_thread_id_passed = true; - } - break; - case 'T': - m_thread_name = option_arg; - m_name_passed = true; - break; - case 'q': - m_queue_name = option_arg; - m_queue_passed = true; - break; - case 'x': - if (option_arg[0] == '\n') { - m_thread_index = UINT32_MAX; - m_thread_index_passed = true; - } else { - if (option_arg.getAsInteger(0, m_thread_index)) - error.SetErrorStringWithFormat("invalid thread index string '%s'", - option_arg.str().c_str()); - else - m_thread_index_passed = true; - } - break; - default: - error.SetErrorStringWithFormat("unrecognized option '%c'", - short_option); - break; - } - - return error; - } - - void OptionParsingStarting(ExecutionContext *execution_context) override { - m_ignore_count = 0; - m_thread_id = LLDB_INVALID_THREAD_ID; - m_thread_id_passed = false; - m_thread_index = UINT32_MAX; - m_thread_index_passed = false; - m_thread_name.clear(); - m_queue_name.clear(); - m_condition.clear(); - m_one_shot = false; - m_enable_passed = false; - m_queue_passed = false; - m_name_passed = false; - m_condition_passed = false; - m_one_shot_passed = false; - m_use_dummy = false; - m_auto_continue = false; - m_auto_continue_passed = false; - } - - llvm::ArrayRef GetDefinitions() override { - return llvm::makeArrayRef(g_breakpoint_modify_options); - } - - // Instance variables to hold the values for command options. - - uint32_t m_ignore_count; - lldb::tid_t m_thread_id; - bool m_thread_id_passed; - uint32_t m_thread_index; - bool m_thread_index_passed; - std::string m_thread_name; - std::string m_queue_name; - std::string m_condition; - bool m_one_shot; - bool m_enable_passed; - bool m_enable_value; - bool m_name_passed; - bool m_queue_passed; - bool m_condition_passed; - bool m_one_shot_passed; - bool m_use_dummy; - bool m_auto_continue; - bool m_auto_continue_passed; - }; - protected: bool DoExecute(Args &command, CommandReturnObject &result) override { - Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); + Target *target = GetSelectedOrDummyTarget(m_dummy_opts.m_use_dummy); if (target == nullptr) { result.AppendError("Invalid target. No existing target or breakpoints."); result.SetStatus(eReturnStatusFailed); @@ -1026,7 +960,8 @@ protected: BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( - command, target, result, &valid_bp_ids); + command, target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::disablePerm); if (result.Succeeded()) { const size_t count = valid_bp_ids.GetSize(); @@ -1039,55 +974,12 @@ protected: if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { BreakpointLocation *location = bp->FindLocationByID(cur_bp_id.GetLocationID()).get(); - if (location) { - if (m_options.m_thread_id_passed) - location->SetThreadID(m_options.m_thread_id); - - if (m_options.m_thread_index_passed) - location->SetThreadIndex(m_options.m_thread_index); - - if (m_options.m_name_passed) - location->SetThreadName(m_options.m_thread_name.c_str()); - - if (m_options.m_queue_passed) - location->SetQueueName(m_options.m_queue_name.c_str()); - - if (m_options.m_ignore_count != 0) - location->SetIgnoreCount(m_options.m_ignore_count); - - if (m_options.m_enable_passed) - location->SetEnabled(m_options.m_enable_value); - - if (m_options.m_condition_passed) - location->SetCondition(m_options.m_condition.c_str()); - - if (m_options.m_auto_continue_passed) - location->SetAutoContinue(m_options.m_auto_continue); - } + if (location) + location->GetLocationOptions() + ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions()); } else { - if (m_options.m_thread_id_passed) - bp->SetThreadID(m_options.m_thread_id); - - if (m_options.m_thread_index_passed) - bp->SetThreadIndex(m_options.m_thread_index); - - if (m_options.m_name_passed) - bp->SetThreadName(m_options.m_thread_name.c_str()); - - if (m_options.m_queue_passed) - bp->SetQueueName(m_options.m_queue_name.c_str()); - - if (m_options.m_ignore_count != 0) - bp->SetIgnoreCount(m_options.m_ignore_count); - - if (m_options.m_enable_passed) - bp->SetEnabled(m_options.m_enable_value); - - if (m_options.m_condition_passed) - bp->SetCondition(m_options.m_condition.c_str()); - - if (m_options.m_auto_continue_passed) - bp->SetAutoContinue(m_options.m_auto_continue); + bp->GetOptions() + ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions()); } } } @@ -1097,7 +989,9 @@ protected: } private: - CommandOptions m_options; + BreakpointOptionGroup m_bp_opts; + BreakpointDummyOptionGroup m_dummy_opts; + OptionGroupOptions m_options; }; //------------------------------------------------------------------------- @@ -1146,7 +1040,7 @@ protected: if (command.empty()) { // No breakpoint selected; enable all currently set breakpoints. - target->EnableAllBreakpoints(); + target->EnableAllowedBreakpoints(); result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64 " breakpoints)\n", (uint64_t)num_breakpoints); @@ -1155,7 +1049,8 @@ protected: // Particular breakpoint selected; enable that breakpoint. BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( - command, target, result, &valid_bp_ids); + command, target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::disablePerm); if (result.Succeeded()) { int enable_count = 0; @@ -1259,7 +1154,7 @@ protected: if (command.empty()) { // No breakpoint selected; disable all currently set breakpoints. - target->DisableAllBreakpoints(); + target->DisableAllowedBreakpoints(); result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu64 " breakpoints)\n", (uint64_t)num_breakpoints); @@ -1269,7 +1164,8 @@ protected: BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( - command, target, result, &valid_bp_ids); + command, target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::disablePerm); if (result.Succeeded()) { int disable_count = 0; @@ -1436,14 +1332,17 @@ protected: result.AppendMessage("Current breakpoints:"); for (size_t i = 0; i < num_breakpoints; ++i) { Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get(); - AddBreakpointDescription(&output_stream, breakpoint, m_options.m_level); + if (breakpoint->AllowList()) + AddBreakpointDescription(&output_stream, breakpoint, + m_options.m_level); } result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { // Particular breakpoints selected; show info about that breakpoint. BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( - command, target, result, &valid_bp_ids); + command, target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::listPerm); if (result.Succeeded()) { for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) { @@ -1731,7 +1630,7 @@ protected: true)) { result.AppendMessage("Operation cancelled..."); } else { - target->RemoveAllBreakpoints(); + target->RemoveAllowedBreakpoints(); result.AppendMessageWithFormat( "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n", (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : ""); @@ -1741,7 +1640,8 @@ protected: // Particular breakpoint selected; disable that breakpoint. BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( - command, target, result, &valid_bp_ids); + command, target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::deletePerm); if (result.Succeeded()) { int delete_count = 0; @@ -1789,7 +1689,7 @@ static OptionDefinition g_breakpoint_name_options[] = { // clang-format off {LLDB_OPT_SET_1, false, "name", 'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."}, {LLDB_OPT_SET_2, false, "breakpoint-id", 'B', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointID, "Specify a breakpoint ID to use."}, - {LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Operate on Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, + {LLDB_OPT_SET_3, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Operate on Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."}, // clang-format on }; class BreakpointNameOptionGroup : public OptionGroup { @@ -1849,6 +1749,188 @@ public: OptionValueBoolean m_use_dummy; }; +static OptionDefinition g_breakpoint_access_options[] = { + // clang-format off + {LLDB_OPT_SET_1, false, "allow-list", 'L', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Determines whether the breakpoint will show up in break list if not referred to explicitly."}, + {LLDB_OPT_SET_2, false, "allow-disable", 'A', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Determines whether the breakpoint can be disabled by name or when all breakpoints are disabled."}, + {LLDB_OPT_SET_3, false, "allow-delete", 'D', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Determines whether the breakpoint can be deleted by name or when all breakpoints are deleted."}, + // clang-format on +}; + +class BreakpointAccessOptionGroup : public OptionGroup +{ +public: + BreakpointAccessOptionGroup() : + OptionGroup() + {} + + ~BreakpointAccessOptionGroup() override = default; + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_breakpoint_access_options); + } + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option + = g_breakpoint_access_options[option_idx].short_option; + + switch (short_option) { + case 'L': { + bool value, success; + value = Args::StringToBoolean(option_arg, false, &success); + if (success) { + m_permissions.SetAllowList(value); + } else + error.SetErrorStringWithFormat( + "invalid boolean value '%s' passed for -L option", + option_arg.str().c_str()); + } break; + case 'A': { + bool value, success; + value = Args::StringToBoolean(option_arg, false, &success); + if (success) { + m_permissions.SetAllowDisable(value); + } else + error.SetErrorStringWithFormat( + "invalid boolean value '%s' passed for -L option", + option_arg.str().c_str()); + } break; + case 'D': { + bool value, success; + value = Args::StringToBoolean(option_arg, false, &success); + if (success) { + m_permissions.SetAllowDelete(value); + } else + error.SetErrorStringWithFormat( + "invalid boolean value '%s' passed for -L option", + option_arg.str().c_str()); + } break; + + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + } + + const BreakpointName::Permissions &GetPermissions() const + { + return m_permissions; + } + BreakpointName::Permissions m_permissions; +}; + +class CommandObjectBreakpointNameConfigure : public CommandObjectParsed { +public: + CommandObjectBreakpointNameConfigure(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "configure", "Configure the options for the breakpoint" + " name provided. " + "If you provide a breakpoint id, the options will be copied from " + "the breakpoint, otherwise only the options specified will be set " + "on the name.", + "breakpoint name configure " + ""), + m_bp_opts(), m_option_group() { + // Create the first variant for the first (and only) argument for this + // command. + CommandArgumentEntry arg1; + CommandArgumentData id_arg; + id_arg.arg_type = eArgTypeBreakpointName; + id_arg.arg_repetition = eArgRepeatOptional; + arg1.push_back(id_arg); + m_arguments.push_back(arg1); + + m_option_group.Append(&m_bp_opts, + LLDB_OPT_SET_ALL, + LLDB_OPT_SET_1); + m_option_group.Append(&m_access_options, + LLDB_OPT_SET_ALL, + LLDB_OPT_SET_ALL); + m_option_group.Append(&m_bp_id, LLDB_OPT_SET_2, LLDB_OPT_SET_2); + m_option_group.Finalize(); + } + + ~CommandObjectBreakpointNameConfigure() override = default; + + Options *GetOptions() override { return &m_option_group; } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + + const size_t argc = command.GetArgumentCount(); + if (argc == 0) { + result.AppendError("No names provided."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + Target *target = + GetSelectedOrDummyTarget(false); + + if (target == nullptr) { + result.AppendError("Invalid target. No existing target or breakpoints."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + std::unique_lock lock; + target->GetBreakpointList().GetListMutex(lock); + + // Make a pass through first to see that all the names are legal. + for (auto &entry : command.entries()) { + Status error; + if (!BreakpointID::StringIsBreakpointName(entry.ref, error)) + { + result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s", + entry.c_str(), error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + // Now configure them, we already pre-checked the names so we don't need + // to check the error: + BreakpointSP bp_sp; + if (m_bp_id.m_breakpoint.OptionWasSet()) + { + lldb::break_id_t bp_id = m_bp_id.m_breakpoint.GetUInt64Value(); + bp_sp = target->GetBreakpointByID(bp_id); + if (!bp_sp) + { + result.AppendErrorWithFormatv("Could not find specified breakpoint {0}", + bp_id); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + + Status error; + for (auto &entry : command.entries()) { + ConstString name(entry.c_str()); + BreakpointName *bp_name = target->FindBreakpointName(name, true, error); + if (!bp_name) + continue; + if (bp_sp) + target->ConfigureBreakpointName(*bp_name, + *bp_sp->GetOptions(), + m_access_options.GetPermissions()); + else + target->ConfigureBreakpointName(*bp_name, + m_bp_opts.GetBreakpointOptions(), + m_access_options.GetPermissions()); + } + return true; + } + +private: + BreakpointNameOptionGroup m_bp_id; // Only using the id part of this. + BreakpointOptionGroup m_bp_opts; + BreakpointAccessOptionGroup m_access_options; + OptionGroupOptions m_option_group; +}; + class CommandObjectBreakpointNameAdd : public CommandObjectParsed { public: CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter) @@ -1904,7 +1986,8 @@ protected: // Particular breakpoint selected; disable that breakpoint. BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( - command, target, result, &valid_bp_ids); + command, target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::listPerm); if (result.Succeeded()) { if (valid_bp_ids.GetSize() == 0) { @@ -1913,13 +1996,14 @@ protected: return false; } size_t num_valid_ids = valid_bp_ids.GetSize(); + const char *bp_name = m_name_options.m_name.GetCurrentValue(); + Status error; // This error reports illegal names, but we've already + // checked that, so we don't need to check it again here. 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); - Status 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); + target->AddNameToBreakpoint(bp_sp, bp_name, error); } } @@ -1987,7 +2071,8 @@ protected: // Particular breakpoint selected; disable that breakpoint. BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( - command, target, result, &valid_bp_ids); + command, target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::deletePerm); if (result.Succeeded()) { if (valid_bp_ids.GetSize() == 0) { @@ -1995,12 +2080,13 @@ protected: result.SetStatus(eReturnStatusFailed); return false; } + ConstString bp_name(m_name_options.m_name.GetCurrentValue()); 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()); + target->RemoveNameFromBreakpoint(bp_sp, bp_name); } } @@ -2016,11 +2102,12 @@ 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.", + "List either the names for a breakpoint or info " + "about a given name. With no arguments, lists all " + "names", "breakpoint name list "), m_name_options(), m_option_group() { - m_option_group.Append(&m_name_options); + m_option_group.Append(&m_name_options, LLDB_OPT_SET_3, LLDB_OPT_SET_ALL); m_option_group.Finalize(); } @@ -2038,42 +2125,57 @@ protected: result.SetStatus(eReturnStatusFailed); return false; } - - if (m_name_options.m_name.OptionWasSet()) { - const char *name = m_name_options.m_name.GetCurrentValue(); - std::unique_lock lock; - target->GetBreakpointList().GetListMutex(lock); - - BreakpointList &breakpoints = target->GetBreakpointList(); - for (BreakpointSP bp_sp : breakpoints.Breakpoints()) { - if (bp_sp->MatchesName(name)) { + + + std::vector name_list; + if (command.empty()) { + target->GetBreakpointNames(name_list); + } else { + for (const Args::ArgEntry &arg : command) + { + name_list.push_back(arg.c_str()); + } + } + + if (name_list.empty()) { + result.AppendMessage("No breakpoint names found."); + } else { + for (const std::string &name_str : name_list) { + const char *name = name_str.c_str(); + // First print out the options for the name: + Status error; + BreakpointName *bp_name = target->FindBreakpointName(ConstString(name), + false, + error); + if (bp_name) + { StreamString s; - bp_sp->GetDescription(&s, eDescriptionLevelBrief); - s.EOL(); - result.AppendMessage(s.GetString()); + result.AppendMessageWithFormat("Name: %s\n", name); + if (bp_name->GetDescription(&s, eDescriptionLevelFull)) + { + result.AppendMessage(s.GetString()); + } + + std::unique_lock lock; + target->GetBreakpointList().GetListMutex(lock); + + BreakpointList &breakpoints = target->GetBreakpointList(); + bool any_set = false; + for (BreakpointSP bp_sp : breakpoints.Breakpoints()) { + if (bp_sp->MatchesName(name)) { + StreamString s; + any_set = true; + bp_sp->GetDescription(&s, eDescriptionLevelBrief); + s.EOL(); + result.AppendMessage(s.GetString()); + } + } + if (!any_set) + result.AppendMessage("No breakpoints using this name."); + } else { + result.AppendMessageWithFormat("Name: %s not found.\n", name); } } - - } 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 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; } @@ -2098,10 +2200,13 @@ public: new CommandObjectBreakpointNameDelete(interpreter)); CommandObjectSP list_command_object( new CommandObjectBreakpointNameList(interpreter)); + CommandObjectSP configure_command_object( + new CommandObjectBreakpointNameConfigure(interpreter)); LoadSubCommand("add", add_command_object); LoadSubCommand("delete", delete_command_object); LoadSubCommand("list", list_command_object); + LoadSubCommand("configure", configure_command_object); } ~CommandObjectBreakpointName() override = default; @@ -2327,7 +2432,8 @@ protected: BreakpointIDList valid_bp_ids; if (!command.empty()) { CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( - command, target, result, &valid_bp_ids); + command, target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::listPerm); if (!result.Succeeded()) { result.SetStatus(eReturnStatusFailed); @@ -2412,7 +2518,10 @@ CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default; void CommandObjectMultiwordBreakpoint::VerifyIDs(Args &args, Target *target, bool allow_locations, CommandReturnObject &result, - BreakpointIDList *valid_ids) { + BreakpointIDList *valid_ids, + BreakpointName::Permissions + ::PermissionKinds + purpose) { // args can be strings representing 1). integers (for breakpoint ids) // 2). the full breakpoint & location // canonical representation @@ -2446,8 +2555,8 @@ void CommandObjectMultiwordBreakpoint::VerifyIDs(Args &args, Target *target, // all the breakpoint ids in the range, and shove all of those breakpoint id // strings into TEMP_ARGS. - BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations, - result, temp_args); + BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations, + purpose, 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 6e14b8f876a0..5e1026a6b7ea 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.h +++ b/lldb/source/Commands/CommandObjectBreakpoint.h @@ -18,11 +18,14 @@ // Other libraries and framework includes // Project includes +#include "lldb/lldb-private.h" +#include "lldb/Breakpoint/BreakpointName.h" #include "lldb/Core/Address.h" #include "lldb/Core/STLUtils.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/Options.h" + namespace lldb_private { //------------------------------------------------------------------------- @@ -37,20 +40,26 @@ public: static void VerifyBreakpointOrLocationIDs(Args &args, Target *target, CommandReturnObject &result, - BreakpointIDList *valid_ids) { - VerifyIDs(args, target, true, result, valid_ids); + BreakpointIDList *valid_ids, + BreakpointName::Permissions + ::PermissionKinds purpose) { + VerifyIDs(args, target, true, result, valid_ids, purpose); } static void VerifyBreakpointIDs(Args &args, Target *target, CommandReturnObject &result, - BreakpointIDList *valid_ids) { - VerifyIDs(args, target, false, result, valid_ids); + BreakpointIDList *valid_ids, + BreakpointName::Permissions::PermissionKinds + purpose) { + VerifyIDs(args, target, false, result, valid_ids, purpose); } private: static void VerifyIDs(Args &args, Target *target, bool allow_locations, CommandReturnObject &result, - BreakpointIDList *valid_ids); + BreakpointIDList *valid_ids, + BreakpointName::Permissions::PermissionKinds + purpose); }; } // namespace lldb_private diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index ecb00f9a339d..170cb8513116 100644 --- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -390,7 +390,8 @@ protected: BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( - command, target, result, &valid_bp_ids); + command, target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::listPerm); m_bp_options_vec.clear(); @@ -571,7 +572,8 @@ protected: BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( - command, target, result, &valid_bp_ids); + command, target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::listPerm); if (result.Succeeded()) { const size_t count = valid_bp_ids.GetSize(); @@ -662,7 +664,8 @@ protected: BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( - command, target, result, &valid_bp_ids); + command, target, result, &valid_bp_ids, + BreakpointName::Permissions::PermissionKinds::listPerm); if (result.Succeeded()) { const size_t count = valid_bp_ids.GetSize(); diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp index 96c245cb8bb5..b1937d8b17b4 100644 --- a/lldb/source/Interpreter/CommandObject.cpp +++ b/lldb/source/Interpreter/CommandObject.cpp @@ -1113,7 +1113,8 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = { { eArgTypeWatchpointID, "watchpt-id", CommandCompletions::eNoCompletion, { nullptr, false }, "Watchpoint IDs are positive integers." }, { eArgTypeWatchpointIDRange, "watchpt-id-list", CommandCompletions::eNoCompletion, { nullptr, false }, "For example, '1-3' or '1 to 3'." }, { eArgTypeWatchType, "watch-type", CommandCompletions::eNoCompletion, { nullptr, false }, "Specify the type for a watchpoint." }, - { eArgRawInput, "raw-input", CommandCompletions::eNoCompletion, { nullptr, false }, "Free-form text passed to a command without prior interpretation, allowing spaces without requiring quotes. To pass arguments and free form text put two dashes ' -- ' between the last argument and any raw input." } + { eArgRawInput, "raw-input", CommandCompletions::eNoCompletion, { nullptr, false }, "Free-form text passed to a command without prior interpretation, allowing spaces without requiring quotes. To pass arguments and free form text put two dashes ' -- ' between the last argument and any raw input." }, + { eArgTypeCommand, "command", CommandCompletions::eNoCompletion, { nullptr, false }, "An LLDB Command line command." } // clang-format on }; diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp index 7e46afcccdab..ad1083be0285 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -3615,13 +3615,15 @@ RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) { } BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name)); - BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint( + Target &target = GetProcess()->GetTarget(); + BreakpointSP bp = target.CreateBreakpoint( m_filtersp, resolver_sp, false, false, false); // Give RS breakpoints a specific name, so the user can manipulate them as a // group. Status err; - if (!bp->AddName("RenderScriptKernel", err)) + target.AddNameToBreakpoint(bp, "RenderScriptKernel", err); + if (err.Fail() && log) if (log) log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, err.AsCString()); @@ -3643,14 +3645,15 @@ RenderScriptRuntime::CreateReductionBreakpoint(const ConstString &name, BreakpointResolverSP resolver_sp(new RSReduceBreakpointResolver( nullptr, name, &m_rsmodules, kernel_types)); - BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint( + Target &target = GetProcess()->GetTarget(); + BreakpointSP bp = target.CreateBreakpoint( m_filtersp, resolver_sp, false, false, false); // Give RS breakpoints a specific name, so the user can manipulate them as a // group. Status err; - if (!bp->AddName("RenderScriptReduction", err)) - if (log) + target.AddNameToBreakpoint(bp, "RenderScriptReduction", err); + if (err.Fail() && log) log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, err.AsCString()); @@ -3885,15 +3888,16 @@ RenderScriptRuntime::CreateScriptGroupBreakpoint(const ConstString &name, BreakpointResolverSP resolver_sp(new RSScriptGroupBreakpointResolver( nullptr, name, m_scriptGroups, stop_on_all)); - BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint( + Target &target = GetProcess()->GetTarget(); + BreakpointSP bp = target.CreateBreakpoint( m_filtersp, resolver_sp, false, false, false); // Give RS breakpoints a specific name, so the user can manipulate them as a // group. Status err; - if (!bp->AddName(name.AsCString(), err)) - if (log) - log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, - err.AsCString()); + target.AddNameToBreakpoint(bp, name.GetCString(), err); + if (err.Fail() && log) + log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, + err.AsCString()); // ask the breakpoint to resolve itself bp->ResolveBreakpoint(); return bp; diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index d97f651ca08b..08546d57c2aa 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -123,6 +123,13 @@ void Target::PrimeFromDummyTarget(Target *target) { BreakpointSP new_bp(new Breakpoint(*this, *breakpoint_sp.get())); AddBreakpoint(new_bp, false); } + + for (auto bp_name_entry : target->m_breakpoint_names) + { + + BreakpointName *new_bp_name = new BreakpointName(*bp_name_entry.second); + AddBreakpointName(new_bp_name); + } } void Target::Dump(Stream *s, lldb::DescriptionLevel description_level) { @@ -601,6 +608,112 @@ void Target::AddBreakpoint(lldb::BreakpointSP bp_sp, bool internal) { } } +void Target::AddNameToBreakpoint(BreakpointID &id, + const char *name, + Status &error) + { + BreakpointSP bp_sp + = m_breakpoint_list.FindBreakpointByID(id.GetBreakpointID()); + if (!bp_sp) + { + StreamString s; + id.GetDescription(&s, eDescriptionLevelBrief); + error.SetErrorStringWithFormat("Could not find breakpoint %s", + s.GetData()); + return; + } + AddNameToBreakpoint(bp_sp, name, error); + } + +void Target::AddNameToBreakpoint(BreakpointSP &bp_sp, + const char *name, + Status &error) + { + if (!bp_sp) + return; + + BreakpointName *bp_name = FindBreakpointName(ConstString(name), true, error); + if (!bp_name) + return; + + bp_name->ConfigureBreakpoint(bp_sp); + bp_sp->AddName(name); + } + +void Target::AddBreakpointName(BreakpointName *bp_name) { + m_breakpoint_names.insert(std::make_pair(bp_name->GetName(), bp_name)); +} + +BreakpointName *Target::FindBreakpointName(const ConstString &name, + bool can_create, + Status &error) +{ + BreakpointID::StringIsBreakpointName(name.GetStringRef(), error); + if (!error.Success()) + return nullptr; + + BreakpointNameList::iterator iter = m_breakpoint_names.find(name); + if (iter == m_breakpoint_names.end()) { + if (!can_create) + { + error.SetErrorStringWithFormat("Breakpoint name \"%s\" doesn't exist and " + "can_create is false.", name.AsCString()); + return nullptr; + } + + iter = m_breakpoint_names.insert(std::make_pair(name, + new BreakpointName(name))) + .first; + } + return (iter->second); +} + +void +Target::DeleteBreakpointName(const ConstString &name) +{ + BreakpointNameList::iterator iter = m_breakpoint_names.find(name); + + if (iter != m_breakpoint_names.end()) { + const char *name_cstr = name.AsCString(); + m_breakpoint_names.erase(iter); + for (auto bp_sp : m_breakpoint_list.Breakpoints()) + bp_sp->RemoveName(name_cstr); + } +} + +void Target::RemoveNameFromBreakpoint(lldb::BreakpointSP &bp_sp, + const ConstString &name) +{ + bp_sp->RemoveName(name.AsCString()); +} + +void Target::ConfigureBreakpointName(BreakpointName &bp_name, + const BreakpointOptions &new_options, + const BreakpointName::Permissions &new_permissions) +{ + bp_name.GetOptions().CopyOverSetOptions(new_options); + bp_name.GetPermissions().MergeInto(new_permissions); + ApplyNameToBreakpoints(bp_name); +} + +void Target::ApplyNameToBreakpoints(BreakpointName &bp_name) { + BreakpointList bkpts_with_name(false); + m_breakpoint_list.FindBreakpointsByName(bp_name.GetName().AsCString(), + bkpts_with_name); + + for (auto bp_sp : bkpts_with_name.Breakpoints()) + bp_name.ConfigureBreakpoint(bp_sp); +} + +void Target::GetBreakpointNames(std::vector &names) +{ + names.clear(); + for (auto bp_name : m_breakpoint_names) { + names.push_back(bp_name.first.AsCString()); + } + std::sort(names.begin(), names.end()); +} + bool Target::ProcessIsValid() { return (m_process_sp && m_process_sp->IsAlive()); } @@ -703,6 +816,17 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size, return wp_sp; } +void Target::RemoveAllowedBreakpoints () +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("Target::%s \n", __FUNCTION__); + + m_breakpoint_list.RemoveAllowed(true); + + m_last_created_breakpoint.reset(); +} + void Target::RemoveAllBreakpoints(bool internal_also) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); if (log) @@ -727,6 +851,14 @@ void Target::DisableAllBreakpoints(bool internal_also) { m_internal_breakpoint_list.SetEnabledAll(false); } +void Target::DisableAllowedBreakpoints() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("Target::%s", __FUNCTION__); + + m_breakpoint_list.SetEnabledAllowed(false); +} + void Target::EnableAllBreakpoints(bool internal_also) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); if (log) @@ -738,6 +870,14 @@ void Target::EnableAllBreakpoints(bool internal_also) { m_internal_breakpoint_list.SetEnabledAll(true); } +void Target::EnableAllowedBreakpoints() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("Target::%s", __FUNCTION__); + + m_breakpoint_list.SetEnabledAllowed(true); +} + bool Target::RemoveBreakpointByID(break_id_t break_id) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); if (log)