| 1 | //===-- BreakpointResolver.h ------------------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef LLDB_BREAKPOINT_BREAKPOINTRESOLVER_H |
| 10 | #define LLDB_BREAKPOINT_BREAKPOINTRESOLVER_H |
| 11 | |
| 12 | #include "lldb/Breakpoint/Breakpoint.h" |
| 13 | #include "lldb/Core/Address.h" |
| 14 | #include "lldb/Core/SearchFilter.h" |
| 15 | #include "lldb/Utility/ConstString.h" |
| 16 | #include "lldb/Utility/FileSpec.h" |
| 17 | #include "lldb/Utility/RegularExpression.h" |
| 18 | #include "lldb/lldb-private.h" |
| 19 | #include <optional> |
| 20 | |
| 21 | namespace lldb_private { |
| 22 | |
| 23 | /// \class BreakpointResolver BreakpointResolver.h |
| 24 | /// "lldb/Breakpoint/BreakpointResolver.h" This class works with SearchFilter |
| 25 | /// to resolve logical breakpoints to their of concrete breakpoint locations. |
| 26 | |
| 27 | /// General Outline: |
| 28 | /// The BreakpointResolver is a Searcher. In that protocol, the SearchFilter |
| 29 | /// asks the question "At what depth of the symbol context descent do you want |
| 30 | /// your callback to get called?" of the filter. The resolver answers this |
| 31 | /// question (in the GetDepth method) and provides the resolution callback. |
| 32 | /// Each Breakpoint has a BreakpointResolver, and it calls either |
| 33 | /// ResolveBreakpoint or ResolveBreakpointInModules to tell it to look for new |
| 34 | /// breakpoint locations. |
| 35 | |
| 36 | class BreakpointResolver : public Searcher { |
| 37 | friend class Breakpoint; |
| 38 | |
| 39 | public: |
| 40 | /// The breakpoint resolver need to have a breakpoint for "ResolveBreakpoint |
| 41 | /// to make sense. It can be constructed without a breakpoint, but you have |
| 42 | /// to call SetBreakpoint before ResolveBreakpoint. |
| 43 | /// |
| 44 | /// \param[in] bkpt |
| 45 | /// The breakpoint that owns this resolver. |
| 46 | /// \param[in] resolverType |
| 47 | /// The concrete breakpoint resolver type for this breakpoint. |
| 48 | BreakpointResolver(const lldb::BreakpointSP &bkpt, |
| 49 | unsigned char resolverType, |
| 50 | lldb::addr_t offset = 0); |
| 51 | |
| 52 | /// The Destructor is virtual, all significant breakpoint resolvers derive |
| 53 | /// from this class. |
| 54 | ~BreakpointResolver() override; |
| 55 | |
| 56 | /// This sets the breakpoint for this resolver. |
| 57 | /// |
| 58 | /// \param[in] bkpt |
| 59 | /// The breakpoint that owns this resolver. |
| 60 | void SetBreakpoint(const lldb::BreakpointSP &bkpt); |
| 61 | |
| 62 | /// This gets the breakpoint for this resolver. |
| 63 | lldb::BreakpointSP GetBreakpoint() const { |
| 64 | auto breakpoint_sp = m_breakpoint.expired() ? lldb::BreakpointSP() : |
| 65 | m_breakpoint.lock(); |
| 66 | assert(breakpoint_sp); |
| 67 | return breakpoint_sp; |
| 68 | } |
| 69 | |
| 70 | /// This updates the offset for this breakpoint. All the locations |
| 71 | /// currently set for this breakpoint will have their offset adjusted when |
| 72 | /// this is called. |
| 73 | /// |
| 74 | /// \param[in] offset |
| 75 | /// The offset to add to all locations. |
| 76 | void SetOffset(lldb::addr_t offset); |
| 77 | |
| 78 | lldb::addr_t GetOffset() const { return m_offset; } |
| 79 | |
| 80 | /// In response to this method the resolver scans all the modules in the |
| 81 | /// breakpoint's target, and adds any new locations it finds. |
| 82 | /// |
| 83 | /// \param[in] filter |
| 84 | /// The filter that will manage the search for this resolver. |
| 85 | virtual void ResolveBreakpoint(SearchFilter &filter); |
| 86 | |
| 87 | /// In response to this method the resolver scans the modules in the module |
| 88 | /// list \a modules, and adds any new locations it finds. |
| 89 | /// |
| 90 | /// \param[in] filter |
| 91 | /// The filter that will manage the search for this resolver. |
| 92 | virtual void ResolveBreakpointInModules(SearchFilter &filter, |
| 93 | ModuleList &modules); |
| 94 | |
| 95 | /// Prints a canonical description for the breakpoint to the stream \a s. |
| 96 | /// |
| 97 | /// \param[in] s |
| 98 | /// Stream to which the output is copied. |
| 99 | void GetDescription(Stream *s) override = 0; |
| 100 | |
| 101 | /// Standard "Dump" method. At present it does nothing. |
| 102 | virtual void Dump(Stream *s) const = 0; |
| 103 | |
| 104 | /// This section handles serializing and deserializing from StructuredData |
| 105 | /// objects. |
| 106 | |
| 107 | static lldb::BreakpointResolverSP |
| 108 | CreateFromStructuredData(const StructuredData::Dictionary &resolver_dict, |
| 109 | Status &error); |
| 110 | |
| 111 | virtual StructuredData::ObjectSP SerializeToStructuredData() { |
| 112 | return StructuredData::ObjectSP(); |
| 113 | } |
| 114 | |
| 115 | static const char *GetSerializationKey() { return "BKPTResolver" ; } |
| 116 | |
| 117 | static const char *GetSerializationSubclassKey() { return "Type" ; } |
| 118 | |
| 119 | static const char *GetSerializationSubclassOptionsKey() { return "Options" ; } |
| 120 | |
| 121 | StructuredData::DictionarySP |
| 122 | WrapOptionsDict(StructuredData::DictionarySP options_dict_sp); |
| 123 | |
| 124 | /// An enumeration for keeping track of the concrete subclass that is |
| 125 | /// actually instantiated. Values of this enumeration are kept in the |
| 126 | /// BreakpointResolver's SubclassID field. They are used for concrete type |
| 127 | /// identification. |
| 128 | enum ResolverTy { |
| 129 | FileLineResolver = 0, // This is an instance of BreakpointResolverFileLine |
| 130 | AddressResolver, // This is an instance of BreakpointResolverAddress |
| 131 | NameResolver, // This is an instance of BreakpointResolverName |
| 132 | FileRegexResolver, |
| 133 | PythonResolver, |
| 134 | ExceptionResolver, |
| 135 | LastKnownResolverType = ExceptionResolver, |
| 136 | UnknownResolver |
| 137 | }; |
| 138 | |
| 139 | // Translate the Ty to name for serialization, the "+2" is one for size vrs. |
| 140 | // index, and one for UnknownResolver. |
| 141 | static const char *g_ty_to_name[LastKnownResolverType + 2]; |
| 142 | |
| 143 | /// getResolverID - Return an ID for the concrete type of this object. This |
| 144 | /// is used to implement the LLVM classof checks. This should not be used |
| 145 | /// for any other purpose, as the values may change as LLDB evolves. |
| 146 | unsigned getResolverID() const { return SubclassID; } |
| 147 | |
| 148 | enum ResolverTy GetResolverTy() { |
| 149 | if (SubclassID > ResolverTy::LastKnownResolverType) |
| 150 | return ResolverTy::UnknownResolver; |
| 151 | else |
| 152 | return (enum ResolverTy)SubclassID; |
| 153 | } |
| 154 | |
| 155 | const char *GetResolverName() { return ResolverTyToName(GetResolverTy()); } |
| 156 | |
| 157 | static const char *ResolverTyToName(enum ResolverTy); |
| 158 | |
| 159 | static ResolverTy NameToResolverTy(llvm::StringRef name); |
| 160 | |
| 161 | virtual lldb::BreakpointResolverSP |
| 162 | CopyForBreakpoint(lldb::BreakpointSP &breakpoint) = 0; |
| 163 | |
| 164 | protected: |
| 165 | // Used for serializing resolver options: |
| 166 | // The options in this enum and the strings in the g_option_names must be |
| 167 | // kept in sync. |
| 168 | enum class OptionNames : uint32_t { |
| 169 | AddressOffset = 0, |
| 170 | ExactMatch, |
| 171 | FileName, |
| 172 | Inlines, |
| 173 | LanguageName, |
| 174 | LineNumber, |
| 175 | Column, |
| 176 | ModuleName, |
| 177 | NameMaskArray, |
| 178 | Offset, |
| 179 | PythonClassName, |
| 180 | RegexString, |
| 181 | ScriptArgs, |
| 182 | SectionName, |
| 183 | SearchDepth, |
| 184 | SkipPrologue, |
| 185 | SymbolNameArray, |
| 186 | LastOptionName |
| 187 | }; |
| 188 | static const char |
| 189 | *g_option_names[static_cast<uint32_t>(OptionNames::LastOptionName)]; |
| 190 | |
| 191 | virtual void NotifyBreakpointSet() {}; |
| 192 | |
| 193 | public: |
| 194 | static const char *GetKey(OptionNames enum_value) { |
| 195 | return g_option_names[static_cast<uint32_t>(enum_value)]; |
| 196 | } |
| 197 | |
| 198 | protected: |
| 199 | /// Takes a symbol context list of matches which supposedly represent the |
| 200 | /// same file and line number in a CU, and find the nearest actual line |
| 201 | /// number that matches, and then filter down the matching addresses to |
| 202 | /// unique entries, and skip the prologue if asked to do so, and then set |
| 203 | /// breakpoint locations in this breakpoint for all the resultant addresses. |
| 204 | /// When \p column is nonzero the \p line and \p column args are used to |
| 205 | /// filter the results to find the first breakpoint >= (line, column). |
| 206 | void SetSCMatchesByLine(SearchFilter &filter, SymbolContextList &sc_list, |
| 207 | bool skip_prologue, llvm::StringRef log_ident, |
| 208 | uint32_t line = 0, |
| 209 | std::optional<uint16_t> column = std::nullopt); |
| 210 | void SetSCMatchesByLine(SearchFilter &, SymbolContextList &, bool, |
| 211 | const char *) = delete; |
| 212 | |
| 213 | lldb::BreakpointLocationSP AddLocation(Address loc_addr, |
| 214 | bool *new_location = nullptr); |
| 215 | |
| 216 | private: |
| 217 | /// Helper for \p SetSCMatchesByLine. |
| 218 | void AddLocation(SearchFilter &filter, const SymbolContext &sc, |
| 219 | bool skip_prologue, llvm::StringRef log_ident); |
| 220 | |
| 221 | lldb::BreakpointWP m_breakpoint; // This is the breakpoint we add locations to. |
| 222 | lldb::addr_t m_offset; // A random offset the user asked us to add to any |
| 223 | // breakpoints we set. |
| 224 | |
| 225 | // Subclass identifier (for llvm isa/dyn_cast) |
| 226 | const unsigned char SubclassID; |
| 227 | BreakpointResolver(const BreakpointResolver &) = delete; |
| 228 | const BreakpointResolver &operator=(const BreakpointResolver &) = delete; |
| 229 | }; |
| 230 | |
| 231 | } // namespace lldb_private |
| 232 | |
| 233 | #endif // LLDB_BREAKPOINT_BREAKPOINTRESOLVER_H |
| 234 | |