1//===-- HexagonDYLDRendezvous.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_HexagonDYLDRendezvous_H_
10#define liblldb_HexagonDYLDRendezvous_H_
11
12#include <limits.h>
13#include <list>
14#include <map>
15#include <string>
16
17#include "lldb/lldb-defines.h"
18#include "lldb/lldb-types.h"
19
20namespace lldb_private {
21class Process;
22}
23
24/// \class HexagonDYLDRendezvous
25/// Interface to the runtime linker.
26///
27/// A structure is present in a processes memory space which is updated by the
28/// runtime liker each time a module is loaded or unloaded.  This class
29/// provides an interface to this structure and maintains a consistent
30/// snapshot of the currently loaded modules.
31class HexagonDYLDRendezvous {
32
33  // This structure is used to hold the contents of the debug rendezvous
34  // information (struct r_debug) as found in the inferiors memory.  Note that
35  // the layout of this struct is not binary compatible, it is simply large
36  // enough to hold the information on both 32 and 64 bit platforms.
37  struct Rendezvous {
38    uint64_t version;
39    lldb::addr_t map_addr;
40    lldb::addr_t brk;
41    uint64_t state;
42    lldb::addr_t ldbase;
43
44    Rendezvous()
45        : version(0), map_addr(LLDB_INVALID_ADDRESS), brk(LLDB_INVALID_ADDRESS),
46          state(0), ldbase(0) {}
47  };
48
49public:
50  // Various metadata supplied by the inferior's threading library to describe
51  // the per-thread state.
52  struct ThreadInfo {
53    bool valid;             // whether we read valid metadata
54    uint32_t dtv_offset;    // offset of DTV pointer within pthread
55    uint32_t dtv_slot_size; // size of one DTV slot
56    uint32_t modid_offset;  // offset of module ID within link_map
57    uint32_t tls_offset;    // offset of TLS pointer within DTV slot
58  };
59
60  HexagonDYLDRendezvous(lldb_private::Process *process);
61
62  /// Update the internal snapshot of runtime linker rendezvous and recompute
63  /// the currently loaded modules.
64  ///
65  /// This method should be called once one start up, then once each time the
66  /// runtime linker enters the function given by GetBreakAddress().
67  ///
68  /// \returns true on success and false on failure.
69  ///
70  /// \see GetBreakAddress().
71  bool Resolve();
72
73  /// \returns true if this rendezvous has been located in the inferiors
74  /// address space and false otherwise.
75  bool IsValid();
76
77  /// \returns the address of the rendezvous structure in the inferiors
78  /// address space.
79  lldb::addr_t GetRendezvousAddress() const { return m_rendezvous_addr; }
80
81  /// Provide the dyld structure address
82  void SetRendezvousAddress(lldb::addr_t);
83
84  /// \returns the version of the rendezvous protocol being used.
85  uint64_t GetVersion() const { return m_current.version; }
86
87  /// \returns address in the inferiors address space containing the linked
88  /// list of shared object descriptors.
89  lldb::addr_t GetLinkMapAddress() const { return m_current.map_addr; }
90
91  /// A breakpoint should be set at this address and Resolve called on each
92  /// hit.
93  ///
94  /// \returns the address of a function called by the runtime linker each
95  /// time a module is loaded/unloaded, or about to be loaded/unloaded.
96  ///
97  /// \see Resolve()
98  lldb::addr_t GetBreakAddress() const { return m_current.brk; }
99
100  /// In hexagon it is possible that we can know the dyld breakpoint without
101  /// having to find it from the rendezvous structure
102  ///
103  void SetBreakAddress(lldb::addr_t addr) { m_current.brk = addr; }
104
105  /// Returns the current state of the rendezvous structure.
106  uint64_t GetState() const { return m_current.state; }
107
108  /// \returns the base address of the runtime linker in the inferiors address
109  /// space.
110  lldb::addr_t GetLDBase() const { return m_current.ldbase; }
111
112  /// \returns the thread layout metadata from the inferiors thread library.
113  const ThreadInfo &GetThreadInfo();
114
115  /// \returns true if modules have been loaded into the inferior since the
116  /// last call to Resolve().
117  bool ModulesDidLoad() const { return !m_added_soentries.empty(); }
118
119  /// \returns true if modules have been unloaded from the inferior since the
120  /// last call to Resolve().
121  bool ModulesDidUnload() const { return !m_removed_soentries.empty(); }
122
123  void DumpToLog(lldb_private::Log *log) const;
124
125  /// Constants describing the state of the rendezvous.
126  ///
127  /// \see GetState().
128  enum RendezvousState {
129    eConsistent = 0,
130    eAdd,
131    eDelete,
132  };
133
134  /// Structure representing the shared objects currently loaded into the
135  /// inferior process.
136  ///
137  /// This object is a rough analogue to the struct link_map object which
138  /// actually lives in the inferiors memory.
139  struct SOEntry {
140    lldb::addr_t link_addr; ///< Address of this link_map.
141    lldb::addr_t base_addr; ///< Base address of the loaded object.
142    lldb::addr_t path_addr; ///< String naming the shared object.
143    lldb::addr_t dyn_addr;  ///< Dynamic section of shared object.
144    lldb::addr_t next;      ///< Address of next so_entry.
145    lldb::addr_t prev;      ///< Address of previous so_entry.
146    std::string path;       ///< File name of shared object.
147
148    SOEntry() { clear(); }
149
150    bool operator==(const SOEntry &entry) { return this->path == entry.path; }
151
152    void clear() {
153      link_addr = 0;
154      base_addr = 0;
155      path_addr = 0;
156      dyn_addr = 0;
157      next = 0;
158      prev = 0;
159      path.clear();
160    }
161  };
162
163protected:
164  typedef std::list<SOEntry> SOEntryList;
165
166public:
167  typedef SOEntryList::const_iterator iterator;
168
169  /// Iterators over all currently loaded modules.
170  iterator begin() const { return m_soentries.begin(); }
171  iterator end() const { return m_soentries.end(); }
172
173  /// Iterators over all modules loaded into the inferior since the last call
174  /// to Resolve().
175  iterator loaded_begin() const { return m_added_soentries.begin(); }
176  iterator loaded_end() const { return m_added_soentries.end(); }
177
178  /// Iterators over all modules unloaded from the inferior since the last
179  /// call to Resolve().
180  iterator unloaded_begin() const { return m_removed_soentries.begin(); }
181  iterator unloaded_end() const { return m_removed_soentries.end(); }
182
183protected:
184  lldb_private::Process *m_process;
185
186  // Cached copy of executable pathname
187  char m_exe_path[PATH_MAX];
188
189  /// Location of the r_debug structure in the inferiors address space.
190  lldb::addr_t m_rendezvous_addr;
191
192  /// Current and previous snapshots of the rendezvous structure.
193  Rendezvous m_current;
194  Rendezvous m_previous;
195
196  /// List of SOEntry objects corresponding to the current link map state.
197  SOEntryList m_soentries;
198
199  /// List of SOEntry's added to the link map since the last call to
200  /// Resolve().
201  SOEntryList m_added_soentries;
202
203  /// List of SOEntry's removed from the link map since the last call to
204  /// Resolve().
205  SOEntryList m_removed_soentries;
206
207  /// Threading metadata read from the inferior.
208  ThreadInfo m_thread_info;
209
210  /// Reads an unsigned integer of \p size bytes from the inferior's address
211  /// space starting at \p addr.
212  ///
213  /// \returns addr + size if the read was successful and false otherwise.
214  lldb::addr_t ReadWord(lldb::addr_t addr, uint64_t *dst, size_t size);
215
216  /// Reads an address from the inferior's address space starting at \p addr.
217  ///
218  /// \returns addr + target address size if the read was successful and
219  /// 0 otherwise.
220  lldb::addr_t ReadPointer(lldb::addr_t addr, lldb::addr_t *dst);
221
222  /// Reads a null-terminated C string from the memory location starting at @p
223  /// addr.
224  std::string ReadStringFromMemory(lldb::addr_t addr);
225
226  /// Reads an SOEntry starting at \p addr.
227  bool ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
228
229  /// Updates the current set of SOEntries, the set of added entries, and the
230  /// set of removed entries.
231  bool UpdateSOEntries();
232
233  bool UpdateSOEntriesForAddition();
234
235  bool UpdateSOEntriesForDeletion();
236
237  /// Reads the current list of shared objects according to the link map
238  /// supplied by the runtime linker.
239  bool TakeSnapshot(SOEntryList &entry_list);
240
241  enum PThreadField { eSize, eNElem, eOffset };
242
243  bool FindMetadata(const char *name, PThreadField field, uint32_t &value);
244};
245
246#endif // liblldb_HexagonDYLDRendezvous_H_
247