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