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