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 Process;
25 }
26 
27 /// \class DYLDRendezvous
28 /// Interface to the runtime linker.
29 ///
30 /// A structure is present in a processes memory space which is updated by the
31 /// runtime liker each time a module is loaded or unloaded.  This class
32 /// provides an interface to this structure and maintains a consistent
33 /// snapshot of the currently loaded modules.
34 class DYLDRendezvous {
35 
36   // This structure is used to hold the contents of the debug rendezvous
37   // information (struct r_debug) as found in the inferiors memory.  Note that
38   // the layout of this struct is not binary compatible, it is simply large
39   // enough to hold the information on both 32 and 64 bit platforms.
40   struct Rendezvous {
41     uint64_t version = 0;
42     lldb::addr_t map_addr = 0;
43     lldb::addr_t brk = 0;
44     uint64_t state = 0;
45     lldb::addr_t ldbase = 0;
46 
47     Rendezvous() = default;
48   };
49 
50   /// Locates the address of the rendezvous structure.  It updates
51   /// m_executable_interpreter if address is extracted from _r_debug.
52   ///
53   /// \returns address on success and LLDB_INVALID_ADDRESS on failure.
54   lldb::addr_t ResolveRendezvousAddress();
55 
56 public:
57   // Various metadata supplied by the inferior's threading library to describe
58   // the per-thread state.
59   struct ThreadInfo {
60     bool valid;             // whether we read valid metadata
61     uint32_t dtv_offset;    // offset of DTV pointer within pthread
62     uint32_t dtv_slot_size; // size of one DTV slot
63     uint32_t modid_offset;  // offset of module ID within link_map
64     uint32_t tls_offset;    // offset of TLS pointer within DTV slot
65   };
66 
67   DYLDRendezvous(lldb_private::Process *process);
68 
69   /// Update the cached executable path.
70   void UpdateExecutablePath();
71 
72   /// Update the internal snapshot of runtime linker rendezvous and recompute
73   /// the currently loaded modules.
74   ///
75   /// This method should be called once one start up, then once each time the
76   /// runtime linker enters the function given by GetBreakAddress().
77   ///
78   /// \returns true on success and false on failure.
79   ///
80   /// \see GetBreakAddress().
81   bool Resolve();
82 
83   /// \returns true if this rendezvous has been located in the inferiors
84   /// address space and false otherwise.
85   bool IsValid();
86 
87   /// \returns the address of the rendezvous structure in the inferiors
88   /// address space.
89   lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; }
90 
91   /// \returns the version of the rendezvous protocol being used.
92   uint64_t GetVersion() const { return m_current.version; }
93 
94   /// \returns address in the inferiors address space containing the linked
95   /// list of shared object descriptors.
96   lldb::addr_t GetLinkMapAddress() const { return m_current.map_addr; }
97 
98   /// A breakpoint should be set at this address and Resolve called on each
99   /// hit.
100   ///
101   /// \returns the address of a function called by the runtime linker each
102   /// time a module is loaded/unloaded, or about to be loaded/unloaded.
103   ///
104   /// \see Resolve()
105   lldb::addr_t GetBreakAddress() const { return m_current.brk; }
106 
107   /// Returns the current state of the rendezvous structure.
108   uint64_t GetState() const { return m_current.state; }
109 
110   /// \returns the base address of the runtime linker in the inferiors address
111   /// space.
112   lldb::addr_t GetLDBase() const { return m_current.ldbase; }
113 
114   /// \returns the thread layout metadata from the inferiors thread library.
115   const ThreadInfo &GetThreadInfo();
116 
117   /// \returns true if modules have been loaded into the inferior since the
118   /// last call to Resolve().
119   bool ModulesDidLoad() const { return !m_added_soentries.empty(); }
120 
121   /// \returns true if modules have been unloaded from the inferior since the
122   /// last call to Resolve().
123   bool ModulesDidUnload() const { return !m_removed_soentries.empty(); }
124 
125   void DumpToLog(lldb_private::Log *log) const;
126 
127   /// Constants describing the state of the rendezvous.
128   ///
129   /// \see GetState().
130   enum RendezvousState { eConsistent, eAdd, eDelete };
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     lldb_private::FileSpec file_spec; ///< File spec of shared object.
145 
146     SOEntry() { clear(); }
147 
148     bool operator==(const SOEntry &entry) {
149       return file_spec == entry.file_spec;
150     }
151 
152     void clear() {
153       link_addr = 0;
154       base_addr = 0;
155       path_addr = 0;
156       dyn_addr = 0;
157       next = 0;
158       prev = 0;
159       file_spec.Clear();
160     }
161   };
162 
163 protected:
164   typedef std::list<SOEntry> SOEntryList;
165 
166 public:
167   typedef SOEntryList::const_iterator iterator;
168 
169   /// Iterators over all currently loaded modules.
170   iterator begin() const { return m_soentries.begin(); }
171   iterator end() const { return m_soentries.end(); }
172 
173   /// Iterators over all modules loaded into the inferior since the last call
174   /// to Resolve().
175   iterator loaded_begin() const { return m_added_soentries.begin(); }
176   iterator loaded_end() const { return m_added_soentries.end(); }
177 
178   /// Iterators over all modules unloaded from the inferior since the last
179   /// call to Resolve().
180   iterator unloaded_begin() const { return m_removed_soentries.begin(); }
181   iterator unloaded_end() const { return m_removed_soentries.end(); }
182 
183 protected:
184   lldb_private::Process *m_process;
185 
186   // Cached copy of executable file spec
187   lldb_private::FileSpec m_exe_file_spec;
188 
189   /// Location of the r_debug structure in the inferiors address space.
190   lldb::addr_t m_rendezvous_addr;
191 
192   // True if the main program is the dynamic linker/loader/program interpreter.
193   bool m_executable_interpreter;
194 
195   /// Current and previous snapshots of the rendezvous structure.
196   Rendezvous m_current;
197   Rendezvous m_previous;
198 
199   /// List of currently loaded SO modules
200   LoadedModuleInfoList m_loaded_modules;
201 
202   /// List of SOEntry objects corresponding to the current link map state.
203   SOEntryList m_soentries;
204 
205   /// List of SOEntry's added to the link map since the last call to
206   /// Resolve().
207   SOEntryList m_added_soentries;
208 
209   /// List of SOEntry's removed from the link map since the last call to
210   /// Resolve().
211   SOEntryList m_removed_soentries;
212 
213   /// Threading metadata read from the inferior.
214   ThreadInfo m_thread_info;
215 
216   /// Reads an unsigned integer of \p size bytes from the inferior's address
217   /// space starting at \p addr.
218   ///
219   /// \returns addr + size if the read was successful and false otherwise.
220   lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size);
221 
222   /// Reads an address from the inferior's address space starting at \p addr.
223   ///
224   /// \returns addr + target address size if the read was successful and
225   /// 0 otherwise.
226   lldb::addr_t ReadPointer(lldb::addr_t addr, lldb::addr_t *dst);
227 
228   /// Reads a null-terminated C string from the memory location starting at @p
229   /// addr.
230   std::string ReadStringFromMemory(lldb::addr_t addr);
231 
232   /// Reads an SOEntry starting at \p addr.
233   bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
234 
235   /// Updates the current set of SOEntries, the set of added entries, and the
236   /// set of removed entries.
237   bool UpdateSOEntries();
238 
239   /// Same as UpdateSOEntries but it gets the list of loaded modules from the
240   /// remote debug server (faster when supported).
241   bool UpdateSOEntriesFromRemote();
242 
243   bool FillSOEntryFromModuleInfo(
244       LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry);
245 
246   bool SaveSOEntriesFromRemote(const LoadedModuleInfoList &module_list);
247 
248   bool AddSOEntriesFromRemote(const LoadedModuleInfoList &module_list);
249 
250   bool RemoveSOEntriesFromRemote(const LoadedModuleInfoList &module_list);
251 
252   bool AddSOEntries();
253 
254   bool RemoveSOEntries();
255 
256   void UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path);
257 
258   void UpdateFileSpecIfNecessary(SOEntry &entry);
259 
260   bool SOEntryIsMainExecutable(const SOEntry &entry);
261 
262   /// Reads the current list of shared objects according to the link map
263   /// supplied by the runtime linker.
264   bool TakeSnapshot(SOEntryList &entry_list);
265 
266   enum PThreadField { eSize, eNElem, eOffset };
267 
268   bool FindMetadata(const char *name, PThreadField field, uint32_t &value);
269 
270   enum RendezvousAction {
271     eNoAction,
272     eTakeSnapshot,
273     eAddModules,
274     eRemoveModules
275   };
276 
277   /// Returns the current action to be taken given the current and previous
278   /// state
279   RendezvousAction GetAction() const;
280 };
281 
282 #endif
283