LLDB mainline
DYLDRendezvous.h
Go to the documentation of this file.
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
16#include "lldb/lldb-defines.h"
17#include "lldb/lldb-types.h"
18
20
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///
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;
117 uint64_t state = 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.
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
143
144 /// Update the cached executable path.
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.
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.
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()
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.
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().
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;
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:
267
268 // Cached copy of executable file spec
270
271 /// Location of the r_debug structure in the inferiors address space.
273
274 // True if the main program is the dynamic linker/loader/program interpreter.
276
277 /// Current and previous snapshots of the rendezvous structure.
280
281 /// List of currently loaded SO modules
283
284 /// List of SOEntry objects corresponding to the current link map state.
286
287 /// List of SOEntry's added to the link map since the last call to
288 /// Resolve().
290
291 /// List of SOEntry's removed from the link map since the last call to
292 /// Resolve().
294
295 /// Threading metadata read from the inferior.
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.
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).
324
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
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
349
350 bool FindMetadata(const char *name, PThreadField field, uint32_t &value);
351
352 bool IsCoreFile() const;
353
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
367};
368
369#endif
Interface to the runtime linker.
bool FindMetadata(const char *name, PThreadField field, uint32_t &value)
bool ModulesDidUnload() const
lldb::addr_t ReadPointer(lldb::addr_t addr, lldb::addr_t *dst)
Reads an address from the inferior's address space starting at addr.
static const char * ActionToCStr(RendezvousAction action)
std::string ReadStringFromMemory(lldb::addr_t addr)
Reads a null-terminated C string from the memory location starting at addr.
bool ModulesDidLoad() const
std::list< SOEntry > SOEntryList
bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
Reads an SOEntry starting at addr.
lldb::addr_t GetBreakAddress() const
A breakpoint should be set at this address and Resolve called on each hit.
lldb_private::Process * m_process
void UpdateExecutablePath()
Update the cached executable path.
bool UpdateSOEntries()
Updates the current set of SOEntries, the set of added entries, and the set of removed entries.
iterator loaded_begin() const
Iterators over all modules loaded into the inferior since the last call to Resolve().
bool m_executable_interpreter
uint64_t GetState() const
Returns the current state of the rendezvous structure.
lldb::addr_t GetLinkMapAddress() const
LoadedModuleInfoList m_loaded_modules
List of currently loaded SO modules.
bool UpdateSOEntriesFromRemote()
Same as UpdateSOEntries but it gets the list of loaded modules from the remote debug server (faster w...
bool IsCoreFile() const
static const char * StateToCStr(RendezvousState state)
bool Resolve()
Update the internal snapshot of runtime linker rendezvous and recompute the currently loaded modules.
iterator unloaded_begin() const
Iterators over all modules unloaded from the inferior since the last call to Resolve().
RendezvousAction GetAction() const
Returns the current action to be taken given the current and previous state.
bool AddSOEntriesFromRemote(const LoadedModuleInfoList &module_list)
SOEntryList m_added_soentries
List of SOEntry's added to the link map since the last call to Resolve().
lldb::addr_t ResolveRendezvousAddress()
Locates the address of the rendezvous structure.
bool FillSOEntryFromModuleInfo(LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry)
RendezvousState
Constants describing the state of the rendezvous.
lldb::addr_t m_rendezvous_addr
Location of the r_debug structure in the inferiors address space.
iterator begin() const
Iterators over all currently loaded modules.
iterator unloaded_end() const
SOEntryList m_soentries
List of SOEntry objects corresponding to the current link map state.
void DumpToLog(lldb_private::Log *log) const
uint64_t GetVersion() const
lldb_private::FileSpec m_exe_file_spec
const ThreadInfo & GetThreadInfo()
iterator loaded_end() const
void UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path)
Rendezvous m_previous
lldb::addr_t GetLDBase() const
bool TakeSnapshot(SOEntryList &entry_list)
Reads the current list of shared objects according to the link map supplied by the runtime linker.
void UpdateFileSpecIfNecessary(SOEntry &entry)
bool SOEntryIsMainExecutable(const SOEntry &entry)
lldb::addr_t GetRendezvousAddress() const
lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size)
Reads an unsigned integer of size bytes from the inferior's address space starting at addr.
Rendezvous m_current
Current and previous snapshots of the rendezvous structure.
bool RemoveSOEntriesFromRemote(const LoadedModuleInfoList &module_list)
SOEntryList m_removed_soentries
List of SOEntry's removed from the link map since the last call to Resolve().
bool SaveSOEntriesFromRemote(const LoadedModuleInfoList &module_list)
SOEntryList::const_iterator iterator
ThreadInfo m_thread_info
Threading metadata read from the inferior.
iterator end() const
A file utility class.
Definition: FileSpec.h:56
void Clear()
Clears the object state.
Definition: FileSpec.cpp:259
A plug-in interface definition class for debugging a process.
Definition: Process.h:343
A class that represents a running process on the host machine.
uint64_t addr_t
Definition: lldb-types.h:80
void DumpToLog(lldb_private::Log *log, const char *label)
Structure representing the shared objects currently loaded into the inferior process.
lldb::addr_t path_addr
String naming the shared object.
lldb::addr_t base_addr
Base address of the loaded object.
bool operator==(const SOEntry &entry)
lldb::addr_t link_addr
Address of this link_map.
lldb_private::FileSpec file_spec
File spec of shared object.
lldb::addr_t prev
Address of previous so_entry.
lldb::addr_t next
Address of next so_entry.
lldb::addr_t dyn_addr
Dynamic section of shared object.