| 1 | //===-- HexagonDYLDRendezvous.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_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_HEXAGONDYLDRENDEZVOUS_H |
| 10 | #define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_HEXAGONDYLDRENDEZVOUS_H |
| 11 | |
| 12 | #include <limits.h> |
| 13 | #include <list> |
| 14 | #include <map> |
| 15 | #include <string> |
| 16 | |
| 17 | #include "lldb/lldb-defines.h" |
| 18 | #include "lldb/lldb-types.h" |
| 19 | |
| 20 | namespace lldb_private { |
| 21 | class Process; |
| 22 | } |
| 23 | |
| 24 | /// \class HexagonDYLDRendezvous |
| 25 | /// Interface to the runtime linker. |
| 26 | /// |
| 27 | /// A structure is present in a processes memory space which is updated by the |
| 28 | /// runtime liker each time a module is loaded or unloaded. This class |
| 29 | /// provides an interface to this structure and maintains a consistent |
| 30 | /// snapshot of the currently loaded modules. |
| 31 | class HexagonDYLDRendezvous { |
| 32 | |
| 33 | // This structure is used to hold the contents of the debug rendezvous |
| 34 | // information (struct r_debug) as found in the inferiors memory. Note that |
| 35 | // the layout of this struct is not binary compatible, it is simply large |
| 36 | // enough to hold the information on both 32 and 64 bit platforms. |
| 37 | struct Rendezvous { |
| 38 | uint64_t version = 0; |
| 39 | lldb::addr_t map_addr = LLDB_INVALID_ADDRESS; |
| 40 | lldb::addr_t brk = LLDB_INVALID_ADDRESS; |
| 41 | uint64_t state = 0; |
| 42 | lldb::addr_t ldbase = 0; |
| 43 | |
| 44 | Rendezvous() = default; |
| 45 | }; |
| 46 | |
| 47 | public: |
| 48 | // Various metadata supplied by the inferior's threading library to describe |
| 49 | // the per-thread state. |
| 50 | struct ThreadInfo { |
| 51 | bool valid; // whether we read valid metadata |
| 52 | uint32_t dtv_offset; // offset of DTV pointer within pthread |
| 53 | uint32_t dtv_slot_size; // size of one DTV slot |
| 54 | uint32_t modid_offset; // offset of module ID within link_map |
| 55 | uint32_t tls_offset; // offset of TLS pointer within DTV slot |
| 56 | }; |
| 57 | |
| 58 | HexagonDYLDRendezvous(lldb_private::Process *process); |
| 59 | |
| 60 | /// Update the internal snapshot of runtime linker rendezvous and recompute |
| 61 | /// the currently loaded modules. |
| 62 | /// |
| 63 | /// This method should be called once one start up, then once each time the |
| 64 | /// runtime linker enters the function given by GetBreakAddress(). |
| 65 | /// |
| 66 | /// \returns true on success and false on failure. |
| 67 | /// |
| 68 | /// \see GetBreakAddress(). |
| 69 | bool Resolve(); |
| 70 | |
| 71 | /// \returns true if this rendezvous has been located in the inferiors |
| 72 | /// address space and false otherwise. |
| 73 | bool IsValid(); |
| 74 | |
| 75 | /// \returns the address of the rendezvous structure in the inferiors |
| 76 | /// address space. |
| 77 | lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; } |
| 78 | |
| 79 | /// Provide the dyld structure address |
| 80 | void SetRendezvousAddress(lldb::addr_t); |
| 81 | |
| 82 | /// \returns the version of the rendezvous protocol being used. |
| 83 | uint64_t GetVersion() const { return m_current.version; } |
| 84 | |
| 85 | /// \returns address in the inferiors address space containing the linked |
| 86 | /// list of shared object descriptors. |
| 87 | lldb::addr_t GetLinkMapAddress() const { return m_current.map_addr; } |
| 88 | |
| 89 | /// A breakpoint should be set at this address and Resolve called on each |
| 90 | /// hit. |
| 91 | /// |
| 92 | /// \returns the address of a function called by the runtime linker each |
| 93 | /// time a module is loaded/unloaded, or about to be loaded/unloaded. |
| 94 | /// |
| 95 | /// \see Resolve() |
| 96 | lldb::addr_t GetBreakAddress() const { return m_current.brk; } |
| 97 | |
| 98 | /// In hexagon it is possible that we can know the dyld breakpoint without |
| 99 | /// having to find it from the rendezvous structure |
| 100 | /// |
| 101 | void SetBreakAddress(lldb::addr_t addr) { m_current.brk = addr; } |
| 102 | |
| 103 | /// Returns the current state of the rendezvous structure. |
| 104 | uint64_t GetState() const { return m_current.state; } |
| 105 | |
| 106 | /// \returns the base address of the runtime linker in the inferiors address |
| 107 | /// space. |
| 108 | lldb::addr_t GetLDBase() const { return m_current.ldbase; } |
| 109 | |
| 110 | /// \returns the thread layout metadata from the inferiors thread library. |
| 111 | const ThreadInfo &GetThreadInfo(); |
| 112 | |
| 113 | /// \returns true if modules have been loaded into the inferior since the |
| 114 | /// last call to Resolve(). |
| 115 | bool ModulesDidLoad() const { return !m_added_soentries.empty(); } |
| 116 | |
| 117 | /// \returns true if modules have been unloaded from the inferior since the |
| 118 | /// last call to Resolve(). |
| 119 | bool ModulesDidUnload() const { return !m_removed_soentries.empty(); } |
| 120 | |
| 121 | void DumpToLog(lldb_private::Log *log) const; |
| 122 | |
| 123 | /// Constants describing the state of the rendezvous. |
| 124 | /// |
| 125 | /// \see GetState(). |
| 126 | enum RendezvousState { |
| 127 | eConsistent = 0, |
| 128 | eAdd, |
| 129 | eDelete, |
| 130 | }; |
| 131 | |
| 132 | /// Structure representing the shared objects currently loaded into the |
| 133 | /// inferior process. |
| 134 | /// |
| 135 | /// This object is a rough analogue to the struct link_map object which |
| 136 | /// actually lives in the inferiors memory. |
| 137 | struct SOEntry { |
| 138 | lldb::addr_t link_addr; ///< Address of this link_map. |
| 139 | lldb::addr_t base_addr; ///< Base address of the loaded object. |
| 140 | lldb::addr_t path_addr; ///< String naming the shared object. |
| 141 | lldb::addr_t dyn_addr; ///< Dynamic section of shared object. |
| 142 | lldb::addr_t next; ///< Address of next so_entry. |
| 143 | lldb::addr_t prev; ///< Address of previous so_entry. |
| 144 | std::string path; ///< File name of shared object. |
| 145 | |
| 146 | SOEntry() { clear(); } |
| 147 | |
| 148 | bool operator==(const SOEntry &entry) { return this->path == entry.path; } |
| 149 | |
| 150 | void clear() { |
| 151 | link_addr = 0; |
| 152 | base_addr = 0; |
| 153 | path_addr = 0; |
| 154 | dyn_addr = 0; |
| 155 | next = 0; |
| 156 | prev = 0; |
| 157 | path.clear(); |
| 158 | } |
| 159 | }; |
| 160 | |
| 161 | protected: |
| 162 | typedef std::list<SOEntry> SOEntryList; |
| 163 | |
| 164 | public: |
| 165 | typedef SOEntryList::const_iterator iterator; |
| 166 | |
| 167 | /// Iterators over all currently loaded modules. |
| 168 | iterator begin() const { return m_soentries.begin(); } |
| 169 | iterator end() const { return m_soentries.end(); } |
| 170 | |
| 171 | /// Iterators over all modules loaded into the inferior since the last call |
| 172 | /// to Resolve(). |
| 173 | iterator loaded_begin() const { return m_added_soentries.begin(); } |
| 174 | iterator loaded_end() const { return m_added_soentries.end(); } |
| 175 | |
| 176 | /// Iterators over all modules unloaded from the inferior since the last |
| 177 | /// call to Resolve(). |
| 178 | iterator unloaded_begin() const { return m_removed_soentries.begin(); } |
| 179 | iterator unloaded_end() const { return m_removed_soentries.end(); } |
| 180 | |
| 181 | protected: |
| 182 | lldb_private::Process *m_process; |
| 183 | |
| 184 | // Cached copy of executable pathname |
| 185 | char m_exe_path[PATH_MAX]; |
| 186 | |
| 187 | /// Location of the r_debug structure in the inferiors address space. |
| 188 | lldb::addr_t m_rendezvous_addr; |
| 189 | |
| 190 | /// Current and previous snapshots of the rendezvous structure. |
| 191 | Rendezvous m_current; |
| 192 | Rendezvous m_previous; |
| 193 | |
| 194 | /// List of SOEntry objects corresponding to the current link map state. |
| 195 | SOEntryList m_soentries; |
| 196 | |
| 197 | /// List of SOEntry's added to the link map since the last call to |
| 198 | /// Resolve(). |
| 199 | SOEntryList m_added_soentries; |
| 200 | |
| 201 | /// List of SOEntry's removed from the link map since the last call to |
| 202 | /// Resolve(). |
| 203 | SOEntryList m_removed_soentries; |
| 204 | |
| 205 | /// Threading metadata read from the inferior. |
| 206 | ThreadInfo m_thread_info; |
| 207 | |
| 208 | /// Reads an unsigned integer of \p size bytes from the inferior's address |
| 209 | /// space starting at \p addr. |
| 210 | /// |
| 211 | /// \returns addr + size if the read was successful and false otherwise. |
| 212 | lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size); |
| 213 | |
| 214 | /// Reads an address from the inferior's address space starting at \p addr. |
| 215 | /// |
| 216 | /// \returns addr + target address size if the read was successful and |
| 217 | /// 0 otherwise. |
| 218 | lldb::addr_t ReadPointer(lldb::addr_t addr, lldb::addr_t *dst); |
| 219 | |
| 220 | /// Reads a null-terminated C string from the memory location starting at @p |
| 221 | /// addr. |
| 222 | std::string ReadStringFromMemory(lldb::addr_t addr); |
| 223 | |
| 224 | /// Reads an SOEntry starting at \p addr. |
| 225 | bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry); |
| 226 | |
| 227 | /// Updates the current set of SOEntries, the set of added entries, and the |
| 228 | /// set of removed entries. |
| 229 | bool UpdateSOEntries(); |
| 230 | |
| 231 | bool UpdateSOEntriesForAddition(); |
| 232 | |
| 233 | bool UpdateSOEntriesForDeletion(); |
| 234 | |
| 235 | /// Reads the current list of shared objects according to the link map |
| 236 | /// supplied by the runtime linker. |
| 237 | bool TakeSnapshot(SOEntryList &entry_list); |
| 238 | |
| 239 | enum PThreadField { eSize, eNElem, eOffset }; |
| 240 | |
| 241 | bool FindMetadata(const char *name, PThreadField field, uint32_t &value); |
| 242 | }; |
| 243 | |
| 244 | #endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_HEXAGONDYLDRENDEZVOUS_H |
| 245 | |