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.
GetRendezvousAddress()164   lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; }
165 
166   /// \returns the version of the rendezvous protocol being used.
GetVersion()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.
GetLinkMapAddress()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()
GetBreakAddress()180   lldb::addr_t GetBreakAddress() const { return m_current.brk; }
181 
182   /// Returns the current state of the rendezvous structure.
GetState()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.
GetLDBase()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().
ModulesDidLoad()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().
ModulesDidUnload()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 
SOEntrySOEntry228     SOEntry() { clear(); }
229 
230     bool operator==(const SOEntry &entry) {
231       return file_spec == entry.file_spec;
232     }
233 
clearSOEntry234     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.
begin()252   iterator begin() const { return m_soentries.begin(); }
end()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().
loaded_begin()257   iterator loaded_begin() const { return m_added_soentries.begin(); }
loaded_end()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().
unloaded_begin()262   iterator unloaded_begin() const { return m_removed_soentries.begin(); }
unloaded_end()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