1 //===-- HexagonDYLDRendezvous.cpp -----------------------------------------===//
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 #include "lldb/Core/Module.h"
10 #include "lldb/Symbol/Symbol.h"
11 #include "lldb/Symbol/SymbolContext.h"
12 #include "lldb/Target/Process.h"
13 #include "lldb/Target/Target.h"
14 #include "lldb/Utility/Log.h"
15 #include "lldb/Utility/Status.h"
16
17 #include "lldb/Symbol/ObjectFile.h"
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Target.h"
20
21 #include "HexagonDYLDRendezvous.h"
22
23 using namespace lldb;
24 using namespace lldb_private;
25
26 /// Locates the address of the rendezvous structure. Returns the address on
27 /// success and LLDB_INVALID_ADDRESS on failure.
ResolveRendezvousAddress(Process * process)28 static addr_t ResolveRendezvousAddress(Process *process) {
29 addr_t info_location;
30 addr_t info_addr;
31 Status error;
32
33 info_location = process->GetImageInfoAddress();
34
35 if (info_location == LLDB_INVALID_ADDRESS)
36 return LLDB_INVALID_ADDRESS;
37
38 info_addr = process->ReadPointerFromMemory(info_location, error);
39 if (error.Fail())
40 return LLDB_INVALID_ADDRESS;
41
42 if (info_addr == 0)
43 return LLDB_INVALID_ADDRESS;
44
45 return info_addr;
46 }
47
HexagonDYLDRendezvous(Process * process)48 HexagonDYLDRendezvous::HexagonDYLDRendezvous(Process *process)
49 : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(),
50 m_previous(), m_soentries(), m_added_soentries(), m_removed_soentries() {
51 m_thread_info.valid = false;
52 m_thread_info.dtv_offset = 0;
53 m_thread_info.dtv_slot_size = 0;
54 m_thread_info.modid_offset = 0;
55 m_thread_info.tls_offset = 0;
56
57 // Cache a copy of the executable path
58 if (m_process) {
59 Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
60 if (exe_mod)
61 exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
62 }
63 }
64
Resolve()65 bool HexagonDYLDRendezvous::Resolve() {
66 const size_t word_size = 4;
67 Rendezvous info;
68 size_t address_size;
69 size_t padding;
70 addr_t info_addr;
71 addr_t cursor;
72
73 address_size = m_process->GetAddressByteSize();
74 padding = address_size - word_size;
75
76 if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
77 cursor = info_addr = ResolveRendezvousAddress(m_process);
78 else
79 cursor = info_addr = m_rendezvous_addr;
80
81 if (cursor == LLDB_INVALID_ADDRESS)
82 return false;
83
84 if (!(cursor = ReadWord(cursor, &info.version, word_size)))
85 return false;
86
87 if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
88 return false;
89
90 if (!(cursor = ReadPointer(cursor, &info.brk)))
91 return false;
92
93 if (!(cursor = ReadWord(cursor, &info.state, word_size)))
94 return false;
95
96 if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
97 return false;
98
99 // The rendezvous was successfully read. Update our internal state.
100 m_rendezvous_addr = info_addr;
101 m_previous = m_current;
102 m_current = info;
103
104 return UpdateSOEntries();
105 }
106
SetRendezvousAddress(lldb::addr_t addr)107 void HexagonDYLDRendezvous::SetRendezvousAddress(lldb::addr_t addr) {
108 m_rendezvous_addr = addr;
109 }
110
IsValid()111 bool HexagonDYLDRendezvous::IsValid() {
112 return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
113 }
114
UpdateSOEntries()115 bool HexagonDYLDRendezvous::UpdateSOEntries() {
116 SOEntry entry;
117
118 if (m_current.map_addr == 0)
119 return false;
120
121 // When the previous and current states are consistent this is the first time
122 // we have been asked to update. Just take a snapshot of the currently
123 // loaded modules.
124 if (m_previous.state == eConsistent && m_current.state == eConsistent)
125 return TakeSnapshot(m_soentries);
126
127 // If we are about to add or remove a shared object clear out the current
128 // state and take a snapshot of the currently loaded images.
129 if (m_current.state == eAdd || m_current.state == eDelete) {
130 // this is a fudge so that we can clear the assert below.
131 m_previous.state = eConsistent;
132 // We hit this assert on the 2nd run of this function after running the
133 // calc example
134 assert(m_previous.state == eConsistent);
135 m_soentries.clear();
136 m_added_soentries.clear();
137 m_removed_soentries.clear();
138 return TakeSnapshot(m_soentries);
139 }
140 assert(m_current.state == eConsistent);
141
142 // Otherwise check the previous state to determine what to expect and update
143 // accordingly.
144 if (m_previous.state == eAdd)
145 return UpdateSOEntriesForAddition();
146 else if (m_previous.state == eDelete)
147 return UpdateSOEntriesForDeletion();
148
149 return false;
150 }
151
UpdateSOEntriesForAddition()152 bool HexagonDYLDRendezvous::UpdateSOEntriesForAddition() {
153 SOEntry entry;
154 iterator pos;
155
156 assert(m_previous.state == eAdd);
157
158 if (m_current.map_addr == 0)
159 return false;
160
161 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
162 if (!ReadSOEntryFromMemory(cursor, entry))
163 return false;
164
165 // Only add shared libraries and not the executable. On Linux this is
166 // indicated by an empty path in the entry. On FreeBSD it is the name of
167 // the executable.
168 if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
169 continue;
170
171 pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
172 if (pos == m_soentries.end()) {
173 m_soentries.push_back(entry);
174 m_added_soentries.push_back(entry);
175 }
176 }
177
178 return true;
179 }
180
UpdateSOEntriesForDeletion()181 bool HexagonDYLDRendezvous::UpdateSOEntriesForDeletion() {
182 SOEntryList entry_list;
183 iterator pos;
184
185 assert(m_previous.state == eDelete);
186
187 if (!TakeSnapshot(entry_list))
188 return false;
189
190 for (iterator I = begin(); I != end(); ++I) {
191 pos = std::find(entry_list.begin(), entry_list.end(), *I);
192 if (pos == entry_list.end())
193 m_removed_soentries.push_back(*I);
194 }
195
196 m_soentries = entry_list;
197 return true;
198 }
199
TakeSnapshot(SOEntryList & entry_list)200 bool HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
201 SOEntry entry;
202
203 if (m_current.map_addr == 0)
204 return false;
205
206 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
207 if (!ReadSOEntryFromMemory(cursor, entry))
208 return false;
209
210 // Only add shared libraries and not the executable. On Linux this is
211 // indicated by an empty path in the entry. On FreeBSD it is the name of
212 // the executable.
213 if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
214 continue;
215
216 entry_list.push_back(entry);
217 }
218
219 return true;
220 }
221
ReadWord(addr_t addr,uint64_t * dst,size_t size)222 addr_t HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst,
223 size_t size) {
224 Status error;
225
226 *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
227 if (error.Fail())
228 return 0;
229
230 return addr + size;
231 }
232
ReadPointer(addr_t addr,addr_t * dst)233 addr_t HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
234 Status error;
235
236 *dst = m_process->ReadPointerFromMemory(addr, error);
237 if (error.Fail())
238 return 0;
239
240 return addr + m_process->GetAddressByteSize();
241 }
242
ReadStringFromMemory(addr_t addr)243 std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) {
244 std::string str;
245 Status error;
246 size_t size;
247 char c;
248
249 if (addr == LLDB_INVALID_ADDRESS)
250 return std::string();
251
252 for (;;) {
253 size = m_process->ReadMemory(addr, &c, 1, error);
254 if (size != 1 || error.Fail())
255 return std::string();
256 if (c == 0)
257 break;
258 else {
259 str.push_back(c);
260 addr++;
261 }
262 }
263
264 return str;
265 }
266
ReadSOEntryFromMemory(lldb::addr_t addr,SOEntry & entry)267 bool HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr,
268 SOEntry &entry) {
269 entry.clear();
270 entry.link_addr = addr;
271
272 if (!(addr = ReadPointer(addr, &entry.base_addr)))
273 return false;
274
275 if (!(addr = ReadPointer(addr, &entry.path_addr)))
276 return false;
277
278 if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
279 return false;
280
281 if (!(addr = ReadPointer(addr, &entry.next)))
282 return false;
283
284 if (!(addr = ReadPointer(addr, &entry.prev)))
285 return false;
286
287 entry.path = ReadStringFromMemory(entry.path_addr);
288
289 return true;
290 }
291
FindMetadata(const char * name,PThreadField field,uint32_t & value)292 bool HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field,
293 uint32_t &value) {
294 Target &target = m_process->GetTarget();
295
296 SymbolContextList list;
297 target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
298 eSymbolTypeAny, list);
299 if (list.IsEmpty())
300 return false;
301
302 Address address = list[0].symbol->GetAddress();
303 addr_t addr = address.GetLoadAddress(&target);
304 if (addr == LLDB_INVALID_ADDRESS)
305 return false;
306
307 Status error;
308 value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
309 addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
310 if (error.Fail())
311 return false;
312
313 if (field == eSize)
314 value /= 8; // convert bits to bytes
315
316 return true;
317 }
318
319 const HexagonDYLDRendezvous::ThreadInfo &
GetThreadInfo()320 HexagonDYLDRendezvous::GetThreadInfo() {
321 if (!m_thread_info.valid) {
322 bool ok = true;
323
324 ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,
325 m_thread_info.dtv_offset);
326 ok &=
327 FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
328 ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,
329 m_thread_info.modid_offset);
330 ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,
331 m_thread_info.tls_offset);
332
333 if (ok)
334 m_thread_info.valid = true;
335 }
336
337 return m_thread_info;
338 }
339
DumpToLog(Log * log) const340 void HexagonDYLDRendezvous::DumpToLog(Log *log) const {
341 int state = GetState();
342
343 if (!log)
344 return;
345
346 log->PutCString("HexagonDYLDRendezvous:");
347 LLDB_LOGF(log, " Address: %" PRIx64, GetRendezvousAddress());
348 LLDB_LOGF(log, " Version: %" PRIu64, GetVersion());
349 LLDB_LOGF(log, " Link : %" PRIx64, GetLinkMapAddress());
350 LLDB_LOGF(log, " Break : %" PRIx64, GetBreakAddress());
351 LLDB_LOGF(log, " LDBase : %" PRIx64, GetLDBase());
352 LLDB_LOGF(log, " State : %s",
353 (state == eConsistent)
354 ? "consistent"
355 : (state == eAdd) ? "add"
356 : (state == eDelete) ? "delete" : "unknown");
357
358 iterator I = begin();
359 iterator E = end();
360
361 if (I != E)
362 log->PutCString("HexagonDYLDRendezvous SOEntries:");
363
364 for (int i = 1; I != E; ++I, ++i) {
365 LLDB_LOGF(log, "\n SOEntry [%d] %s", i, I->path.c_str());
366 LLDB_LOGF(log, " Base : %" PRIx64, I->base_addr);
367 LLDB_LOGF(log, " Path : %" PRIx64, I->path_addr);
368 LLDB_LOGF(log, " Dyn : %" PRIx64, I->dyn_addr);
369 LLDB_LOGF(log, " Next : %" PRIx64, I->next);
370 LLDB_LOGF(log, " Prev : %" PRIx64, I->prev);
371 }
372 }
373