1 //===-- DYLDRendezvous.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_POSIX_DYLD_DYLDRENDEZVOUS_H 10 #define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_POSIX_DYLD_DYLDRENDEZVOUS_H 11 12 #include <list> 13 #include <string> 14 15 #include "lldb/Utility/FileSpec.h" 16 #include "lldb/lldb-defines.h" 17 #include "lldb/lldb-types.h" 18 19 #include "lldb/Core/LoadedModuleInfoList.h" 20 21 using lldb_private::LoadedModuleInfoList; 22 23 namespace lldb_private { 24 class Log; 25 class Process; 26 } 27 28 /// \class DYLDRendezvous 29 /// Interface to the runtime linker. 30 /// 31 /// A structure is present in a processes memory space which is updated by the 32 /// dynamic linker each time a module is loaded or unloaded. This class 33 /// provides an interface to this structure and maintains a consistent 34 /// snapshot of the currently loaded modules. 35 /// 36 /// In the dynamic loader sources, this structure has a type of "r_debug" and 37 /// the name of the structure us "_r_debug". The structure looks like: 38 /// 39 /// struct r_debug { 40 /// // Version number for this protocol. 41 /// int r_version; 42 /// // Head of the chain of loaded objects. 43 /// struct link_map *r_map; 44 /// // The address the debugger should set a breakpoint at in order to get 45 /// // notified when shared libraries are added or removed 46 /// uintptr_t r_brk; 47 /// // This state value describes the mapping change taking place when the 48 /// // 'r_brk' address is called. 49 /// enum { 50 /// RT_CONSISTENT, // Mapping change is complete. 51 /// RT_ADD, // Beginning to add a new object. 52 /// RT_DELETE, // Beginning to remove an object mapping. 53 /// } r_state; 54 /// // Base address the linker is loaded at. 55 /// uintptr_t r_ldbase; 56 /// }; 57 /// 58 /// The dynamic linker then defines a global variable using this type named 59 /// "_r_debug": 60 /// 61 /// r_debug _r_debug; 62 /// 63 /// The DYLDRendezvous class defines a local version of this structure named 64 /// DYLDRendezvous::Rendezvous. See the definition inside the class definition 65 /// for DYLDRendezvous. 66 /// 67 /// This structure can be located by looking through the .dynamic section in 68 /// the main executable and finding the DT_DEBUG tag entry. This value starts 69 /// out with a value of zero when the program first is initially loaded, but 70 /// the address of the "_r_debug" structure from ld.so is filled in by the 71 /// dynamic loader during program initialization code in ld.so prior to loading 72 /// or unloading and shared libraries. 73 /// 74 /// The dynamic loader will update this structure as shared libraries are 75 /// loaded and will call a specific function that LLDB knows to set a 76 /// breakpoint on (from _r_debug.r_brk) so LLDB will find out when shared 77 /// libraries are loaded or unloaded. Each time this breakpoint is hit, LLDB 78 /// looks at the contents of this structure and the contents tell LLDB what 79 /// needs to be done. 80 /// 81 /// Currently we expect the "state" in this structure to change as things 82 /// happen. 83 /// 84 /// When any shared libraries are loaded the following happens: 85 /// - _r_debug.r_map is updated with the new shared libraries. This is a 86 /// doubly linked list of "link_map *" entries. 87 /// - _r_debug.r_state is set to RT_ADD and the debugger notification 88 /// function is called notifying the debugger that shared libraries are 89 /// about to be added, but are not yet ready for use. 90 /// - Once the the shared libraries are fully loaded, _r_debug.r_state is set 91 /// to RT_CONSISTENT and the debugger notification function is called again 92 /// notifying the debugger that shared libraries are ready for use. 93 /// DYLDRendezvous must remember that the previous state was RT_ADD when it 94 /// receives a RT_CONSISTENT in order to know to add libraries 95 /// 96 /// When any shared libraries are unloaded the following happens: 97 /// - _r_debug.r_map is updated and the unloaded libraries are removed. 98 /// - _r_debug.r_state is set to RT_DELETE and the debugger notification 99 /// function is called notifying the debugger that shared libraries are 100 /// about to be removed. 101 /// - Once the the shared libraries are removed _r_debug.r_state is set to 102 /// RT_CONSISTENT and the debugger notification function is called again 103 /// notifying the debugger that shared libraries have been removed. 104 /// DYLDRendezvous must remember that the previous state was RT_DELETE when 105 /// it receives a RT_CONSISTENT in order to know to remove libraries 106 /// 107 class DYLDRendezvous { 108 109 // This structure is used to hold the contents of the debug rendezvous 110 // information (struct r_debug) as found in the inferiors memory. Note that 111 // the layout of this struct is not binary compatible, it is simply large 112 // enough to hold the information on both 32 and 64 bit platforms. 113 struct Rendezvous { 114 uint64_t version = 0; 115 lldb::addr_t map_addr = 0; 116 lldb::addr_t brk = 0; 117 uint64_t state = 0; 118 lldb::addr_t ldbase = 0; 119 120 Rendezvous() = default; 121 122 void DumpToLog(lldb_private::Log *log, const char *label); 123 }; 124 125 /// Locates the address of the rendezvous structure. It updates 126 /// m_executable_interpreter if address is extracted from _r_debug. 127 /// 128 /// \returns address on success and LLDB_INVALID_ADDRESS on failure. 129 lldb::addr_t ResolveRendezvousAddress(); 130 131 public: 132 // Various metadata supplied by the inferior's threading library to describe 133 // the per-thread state. 134 struct ThreadInfo { 135 bool valid; // whether we read valid metadata 136 uint32_t dtv_offset; // offset of DTV pointer within pthread 137 uint32_t dtv_slot_size; // size of one DTV slot 138 uint32_t modid_offset; // offset of module ID within link_map 139 uint32_t tls_offset; // offset of TLS pointer within DTV slot 140 }; 141 142 DYLDRendezvous(lldb_private::Process *process); 143 144 /// Update the cached executable path. 145 void UpdateExecutablePath(); 146 147 /// Update the internal snapshot of runtime linker rendezvous and recompute 148 /// the currently loaded modules. 149 /// 150 /// This method should be called once one start up, then once each time the 151 /// runtime linker enters the function given by GetBreakAddress(). 152 /// 153 /// \returns true on success and false on failure. 154 /// 155 /// \see GetBreakAddress(). 156 bool Resolve(); 157 158 /// \returns true if this rendezvous has been located in the inferiors 159 /// address space and false otherwise. 160 bool IsValid(); 161 162 /// \returns the address of the rendezvous structure in the inferiors 163 /// address space. 164 lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; } 165 166 /// \returns the version of the rendezvous protocol being used. 167 uint64_t GetVersion() const { return m_current.version; } 168 169 /// \returns address in the inferiors address space containing the linked 170 /// list of shared object descriptors. 171 lldb::addr_t GetLinkMapAddress() const { return m_current.map_addr; } 172 173 /// A breakpoint should be set at this address and Resolve called on each 174 /// hit. 175 /// 176 /// \returns the address of a function called by the runtime linker each 177 /// time a module is loaded/unloaded, or about to be loaded/unloaded. 178 /// 179 /// \see Resolve() 180 lldb::addr_t GetBreakAddress() const { return m_current.brk; } 181 182 /// Returns the current state of the rendezvous structure. 183 uint64_t GetState() const { return m_current.state; } 184 185 /// \returns the base address of the runtime linker in the inferiors address 186 /// space. 187 lldb::addr_t GetLDBase() const { return m_current.ldbase; } 188 189 /// \returns the thread layout metadata from the inferiors thread library. 190 const ThreadInfo &GetThreadInfo(); 191 192 /// \returns true if modules have been loaded into the inferior since the 193 /// last call to Resolve(). 194 bool ModulesDidLoad() const { return !m_added_soentries.empty(); } 195 196 /// \returns true if modules have been unloaded from the inferior since the 197 /// last call to Resolve(). 198 bool ModulesDidUnload() const { return !m_removed_soentries.empty(); } 199 200 void DumpToLog(lldb_private::Log *log) const; 201 202 /// Constants describing the state of the rendezvous. 203 /// 204 /// These values are defined to match the r_debug.r_state enum from the 205 /// actual dynamic loader sources. 206 /// 207 /// \see GetState(). 208 enum RendezvousState { 209 eConsistent, // RT_CONSISTENT 210 eAdd, // RT_ADD 211 eDelete // RT_DELETE 212 }; 213 214 /// Structure representing the shared objects currently loaded into the 215 /// inferior process. 216 /// 217 /// This object is a rough analogue to the struct link_map object which 218 /// actually lives in the inferiors memory. 219 struct SOEntry { 220 lldb::addr_t link_addr; ///< Address of this link_map. 221 lldb::addr_t base_addr; ///< Base address of the loaded object. 222 lldb::addr_t path_addr; ///< String naming the shared object. 223 lldb::addr_t dyn_addr; ///< Dynamic section of shared object. 224 lldb::addr_t next; ///< Address of next so_entry. 225 lldb::addr_t prev; ///< Address of previous so_entry. 226 lldb_private::FileSpec file_spec; ///< File spec of shared object. 227 228 SOEntry() { clear(); } 229 230 bool operator==(const SOEntry &entry) { 231 return file_spec == entry.file_spec; 232 } 233 234 void clear() { 235 link_addr = 0; 236 base_addr = 0; 237 path_addr = 0; 238 dyn_addr = 0; 239 next = 0; 240 prev = 0; 241 file_spec.Clear(); 242 } 243 }; 244 245 protected: 246 typedef std::list<SOEntry> SOEntryList; 247 248 public: 249 typedef SOEntryList::const_iterator iterator; 250 251 /// Iterators over all currently loaded modules. 252 iterator begin() const { return m_soentries.begin(); } 253 iterator end() const { return m_soentries.end(); } 254 255 /// Iterators over all modules loaded into the inferior since the last call 256 /// to Resolve(). 257 iterator loaded_begin() const { return m_added_soentries.begin(); } 258 iterator loaded_end() const { return m_added_soentries.end(); } 259 260 /// Iterators over all modules unloaded from the inferior since the last 261 /// call to Resolve(). 262 iterator unloaded_begin() const { return m_removed_soentries.begin(); } 263 iterator unloaded_end() const { return m_removed_soentries.end(); } 264 265 protected: 266 lldb_private::Process *m_process; 267 268 // Cached copy of executable file spec 269 lldb_private::FileSpec m_exe_file_spec; 270 271 /// Location of the r_debug structure in the inferiors address space. 272 lldb::addr_t m_rendezvous_addr; 273 274 // True if the main program is the dynamic linker/loader/program interpreter. 275 bool m_executable_interpreter; 276 277 /// Current and previous snapshots of the rendezvous structure. 278 Rendezvous m_current; 279 Rendezvous m_previous; 280 281 /// List of currently loaded SO modules 282 LoadedModuleInfoList m_loaded_modules; 283 284 /// List of SOEntry objects corresponding to the current link map state. 285 SOEntryList m_soentries; 286 287 /// List of SOEntry's added to the link map since the last call to 288 /// Resolve(). 289 SOEntryList m_added_soentries; 290 291 /// List of SOEntry's removed from the link map since the last call to 292 /// Resolve(). 293 SOEntryList m_removed_soentries; 294 295 /// Threading metadata read from the inferior. 296 ThreadInfo m_thread_info; 297 298 /// Reads an unsigned integer of \p size bytes from the inferior's address 299 /// space starting at \p addr. 300 /// 301 /// \returns addr + size if the read was successful and false otherwise. 302 lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size); 303 304 /// Reads an address from the inferior's address space starting at \p addr. 305 /// 306 /// \returns addr + target address size if the read was successful and 307 /// 0 otherwise. 308 lldb::addr_t ReadPointer(lldb::addr_t addr, lldb::addr_t *dst); 309 310 /// Reads a null-terminated C string from the memory location starting at @p 311 /// addr. 312 std::string ReadStringFromMemory(lldb::addr_t addr); 313 314 /// Reads an SOEntry starting at \p addr. 315 bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry); 316 317 /// Updates the current set of SOEntries, the set of added entries, and the 318 /// set of removed entries. 319 bool UpdateSOEntries(); 320 321 /// Same as UpdateSOEntries but it gets the list of loaded modules from the 322 /// remote debug server (faster when supported). 323 bool UpdateSOEntriesFromRemote(); 324 325 bool FillSOEntryFromModuleInfo( 326 LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry); 327 328 bool SaveSOEntriesFromRemote(const LoadedModuleInfoList &module_list); 329 330 bool AddSOEntriesFromRemote(const LoadedModuleInfoList &module_list); 331 332 bool RemoveSOEntriesFromRemote(const LoadedModuleInfoList &module_list); 333 334 bool AddSOEntries(); 335 336 bool RemoveSOEntries(); 337 338 void UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path); 339 340 void UpdateFileSpecIfNecessary(SOEntry &entry); 341 342 bool SOEntryIsMainExecutable(const SOEntry &entry); 343 344 /// Reads the current list of shared objects according to the link map 345 /// supplied by the runtime linker. 346 bool TakeSnapshot(SOEntryList &entry_list); 347 348 enum PThreadField { eSize, eNElem, eOffset }; 349 350 bool FindMetadata(const char *name, PThreadField field, uint32_t &value); 351 352 bool IsCoreFile() const; 353 354 enum RendezvousAction { 355 eNoAction, 356 eTakeSnapshot, 357 eAddModules, 358 eRemoveModules 359 }; 360 361 static const char *StateToCStr(RendezvousState state); 362 static const char *ActionToCStr(RendezvousAction action); 363 364 /// Returns the current action to be taken given the current and previous 365 /// state 366 RendezvousAction GetAction() const; 367 }; 368 369 #endif 370