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 pthread_size; // size of struct pthread
137 uint32_t dtv_offset; // offset of DTV pointer within pthread
138 uint32_t dtv_slot_size; // size of one DTV slot
139 uint32_t modid_offset; // offset of module ID within link_map
140 uint32_t tls_offset; // offset of TLS pointer within DTV slot
141 };
142
144
145 /// Update the cached executable path.
147
148 /// Update the internal snapshot of runtime linker rendezvous and recompute
149 /// the currently loaded modules.
150 ///
151 /// This method should be called once one start up, then once each time the
152 /// runtime linker enters the function given by GetBreakAddress().
153 ///
154 /// \returns true on success and false on failure.
155 ///
156 /// \see GetBreakAddress().
157 bool Resolve();
158
159 /// \returns true if this rendezvous has been located in the inferiors
160 /// address space and false otherwise.
161 bool IsValid();
162
163 /// \returns the address of the rendezvous structure in the inferiors
164 /// address space.
166
167 /// \returns the version of the rendezvous protocol being used.
168 uint64_t GetVersion() const { return m_current.version; }
169
170 /// \returns address in the inferiors address space containing the linked
171 /// list of shared object descriptors.
172 lldb::addr_t GetLinkMapAddress() const { return m_current.map_addr; }
173
174 /// A breakpoint should be set at this address and Resolve called on each
175 /// hit.
176 ///
177 /// \returns the address of a function called by the runtime linker each
178 /// time a module is loaded/unloaded, or about to be loaded/unloaded.
179 ///
180 /// \see Resolve()
181 lldb::addr_t GetBreakAddress() const { return m_current.brk; }
182
183 /// Returns the current state of the rendezvous structure.
184 uint64_t GetState() const { return m_current.state; }
185
186 /// \returns the base address of the runtime linker in the inferiors address
187 /// space.
188 lldb::addr_t GetLDBase() const { return m_current.ldbase; }
189
190 /// \returns the thread layout metadata from the inferiors thread library.
191 const ThreadInfo &GetThreadInfo();
192
193 /// \returns true if modules have been loaded into the inferior since the
194 /// last call to Resolve().
195 bool ModulesDidLoad() const { return !m_added_soentries.empty(); }
196
197 /// \returns true if modules have been unloaded from the inferior since the
198 /// last call to Resolve().
199 bool ModulesDidUnload() const { return !m_removed_soentries.empty(); }
200
201 void DumpToLog(lldb_private::Log *log) const;
202
203 /// Constants describing the state of the rendezvous.
204 ///
205 /// These values are defined to match the r_debug.r_state enum from the
206 /// actual dynamic loader sources.
207 ///
208 /// \see GetState().
210 eConsistent, // RT_CONSISTENT
211 eAdd, // RT_ADD
212 eDelete // RT_DELETE
213 };
214
215 /// Structure representing the shared objects currently loaded into the
216 /// inferior process.
217 ///
218 /// This object is a rough analogue to the struct link_map object which
219 /// actually lives in the inferiors memory.
220 struct SOEntry {
221 lldb::addr_t link_addr; ///< Address of this link_map.
222 lldb::addr_t base_addr; ///< Base address of the loaded object.
223 lldb::addr_t path_addr; ///< String naming the shared object.
224 lldb::addr_t dyn_addr; ///< Dynamic section of shared object.
225 lldb::addr_t next; ///< Address of next so_entry.
226 lldb::addr_t prev; ///< Address of previous so_entry.
227 lldb_private::FileSpec file_spec; ///< File spec of shared object.
228
229 SOEntry() { clear(); }
230
231 bool operator==(const SOEntry &entry) {
232 return file_spec == entry.file_spec;
233 }
234
235 void clear() {
236 link_addr = 0;
237 base_addr = 0;
238 path_addr = 0;
239 dyn_addr = 0;
240 next = 0;
241 prev = 0;
242 file_spec.Clear();
243 }
244 };
245
246protected:
247 typedef std::list<SOEntry> SOEntryList;
248
249public:
250 typedef SOEntryList::const_iterator iterator;
251
252 /// Iterators over all currently loaded modules.
253 iterator begin() const { return m_soentries.begin(); }
254 iterator end() const { return m_soentries.end(); }
255
256 /// Iterators over all modules loaded into the inferior since the last call
257 /// to Resolve().
258 iterator loaded_begin() const { return m_added_soentries.begin(); }
259 iterator loaded_end() const { return m_added_soentries.end(); }
260
261 /// Iterators over all modules unloaded from the inferior since the last
262 /// call to Resolve().
263 iterator unloaded_begin() const { return m_removed_soentries.begin(); }
264 iterator unloaded_end() const { return m_removed_soentries.end(); }
265
266protected:
268
269 // Cached copy of executable file spec
271
272 /// Location of the r_debug structure in the inferiors address space.
274
275 // True if the main program is the dynamic linker/loader/program interpreter.
277
278 /// Current and previous snapshots of the rendezvous structure.
281
282 /// List of currently loaded SO modules
284
285 /// List of SOEntry objects corresponding to the current link map state.
287
288 /// List of SOEntry's added to the link map since the last call to
289 /// Resolve().
291
292 /// List of SOEntry's removed from the link map since the last call to
293 /// Resolve().
295
296 /// Threading metadata read from the inferior.
298
299 /// Reads an unsigned integer of \p size bytes from the inferior's address
300 /// space starting at \p addr.
301 ///
302 /// \returns addr + size if the read was successful and false otherwise.
303 lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size);
304
305 /// Reads an address from the inferior's address space starting at \p addr.
306 ///
307 /// \returns addr + target address size if the read was successful and
308 /// 0 otherwise.
310
311 /// Reads a null-terminated C string from the memory location starting at @p
312 /// addr.
313 std::string ReadStringFromMemory(lldb::addr_t addr);
314
315 /// Reads an SOEntry starting at \p addr.
316 bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
317
318 /// Updates the current set of SOEntries, the set of added entries, and the
319 /// set of removed entries.
320 bool UpdateSOEntries();
321
322 /// Same as UpdateSOEntries but it gets the list of loaded modules from the
323 /// remote debug server (faster when supported).
325
327 LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry);
328
329 bool SaveSOEntriesFromRemote(const LoadedModuleInfoList &module_list);
330
331 bool AddSOEntriesFromRemote(const LoadedModuleInfoList &module_list);
332
333 bool RemoveSOEntriesFromRemote(const LoadedModuleInfoList &module_list);
334
335 bool AddSOEntries();
336
337 bool RemoveSOEntries();
338
339 void UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path);
340
342
343 bool SOEntryIsMainExecutable(const SOEntry &entry);
344
345 /// Reads the current list of shared objects according to the link map
346 /// supplied by the runtime linker.
347 bool TakeSnapshot(SOEntryList &entry_list);
348
349 /// For the definitions of the metadata entries, see
350 /// <glibc>/nptl_db/(db_info.c, structs.def, thread_dbP.h).
352 eSize, // Size of an element of a field as defined by DESC, bits
353 eNElem, // Number of elements in the field
354 eOffset, // Offset of the field
355 eStructSize // Size of a type as defined by DB_STRUCT, bytes
356 };
357
358 bool FindMetadata(const char *name, PThreadField field, uint32_t &value);
359
360 bool IsCoreFile() const;
361
368
369 static const char *StateToCStr(RendezvousState state);
370 static const char *ActionToCStr(RendezvousAction action);
371
372 /// Returns the current action to be taken given the current and previous
373 /// state
375};
376
377#endif
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
DYLDRendezvous(lldb_private::Process *process)
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)
PThreadField
For the definitions of the metadata entries, see <glibc>/nptl_db/(db_info.c, structs....
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:57
A plug-in interface definition class for debugging a process.
Definition Process.h:354
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.