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
21using lldb_private::LoadedModuleInfoList;
22
23namespace lldb_private {
24class Log;
25class 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///
107class 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
131public:
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
245protected:
246 typedef std::list<SOEntry> SOEntryList;
247
248public:
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
265protected:
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

source code of lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h