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 liblldb_Rendezvous_H_
10#define liblldb_Rendezvous_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 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.
34class 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
47    Rendezvous() : version(0), map_addr(0), brk(0), state(0), ldbase(0) {}
48  };
49
50public:
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.
80  lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; }
81
82  /// \returns the version of the rendezvous protocol being used.
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.
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()
96  lldb::addr_t GetBreakAddress() const { return m_current.brk; }
97
98  /// Returns the current state of the rendezvous structure.
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.
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().
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().
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
137    SOEntry() { clear(); }
138
139    bool operator==(const SOEntry &entry) {
140      return file_spec == entry.file_spec;
141    }
142
143    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
154protected:
155  typedef std::list<SOEntry> SOEntryList;
156
157public:
158  typedef SOEntryList::const_iterator iterator;
159
160  /// Iterators over all currently loaded modules.
161  iterator begin() const { return m_soentries.begin(); }
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().
166  iterator loaded_begin() const { return m_added_soentries.begin(); }
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().
171  iterator unloaded_begin() const { return m_removed_soentries.begin(); }
172  iterator unloaded_end() const { return m_removed_soentries.end(); }
173
174protected:
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