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