Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp
39653 views
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.
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
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
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
107
void HexagonDYLDRendezvous::SetRendezvousAddress(lldb::addr_t addr) {
108
m_rendezvous_addr = addr;
109
}
110
111
bool HexagonDYLDRendezvous::IsValid() {
112
return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
113
}
114
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
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
if (!llvm::is_contained(m_soentries, entry)) {
172
m_soentries.push_back(entry);
173
m_added_soentries.push_back(entry);
174
}
175
}
176
177
return true;
178
}
179
180
bool HexagonDYLDRendezvous::UpdateSOEntriesForDeletion() {
181
SOEntryList entry_list;
182
iterator pos;
183
184
assert(m_previous.state == eDelete);
185
186
if (!TakeSnapshot(entry_list))
187
return false;
188
189
for (iterator I = begin(); I != end(); ++I) {
190
if (!llvm::is_contained(entry_list, *I))
191
m_removed_soentries.push_back(*I);
192
}
193
194
m_soentries = entry_list;
195
return true;
196
}
197
198
bool HexagonDYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
199
SOEntry entry;
200
201
if (m_current.map_addr == 0)
202
return false;
203
204
for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
205
if (!ReadSOEntryFromMemory(cursor, entry))
206
return false;
207
208
// Only add shared libraries and not the executable. On Linux this is
209
// indicated by an empty path in the entry. On FreeBSD it is the name of
210
// the executable.
211
if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
212
continue;
213
214
entry_list.push_back(entry);
215
}
216
217
return true;
218
}
219
220
addr_t HexagonDYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst,
221
size_t size) {
222
Status error;
223
224
*dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
225
if (error.Fail())
226
return 0;
227
228
return addr + size;
229
}
230
231
addr_t HexagonDYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
232
Status error;
233
234
*dst = m_process->ReadPointerFromMemory(addr, error);
235
if (error.Fail())
236
return 0;
237
238
return addr + m_process->GetAddressByteSize();
239
}
240
241
std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) {
242
std::string str;
243
Status error;
244
size_t size;
245
char c;
246
247
if (addr == LLDB_INVALID_ADDRESS)
248
return std::string();
249
250
for (;;) {
251
size = m_process->ReadMemory(addr, &c, 1, error);
252
if (size != 1 || error.Fail())
253
return std::string();
254
if (c == 0)
255
break;
256
else {
257
str.push_back(c);
258
addr++;
259
}
260
}
261
262
return str;
263
}
264
265
bool HexagonDYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr,
266
SOEntry &entry) {
267
entry.clear();
268
entry.link_addr = addr;
269
270
if (!(addr = ReadPointer(addr, &entry.base_addr)))
271
return false;
272
273
if (!(addr = ReadPointer(addr, &entry.path_addr)))
274
return false;
275
276
if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
277
return false;
278
279
if (!(addr = ReadPointer(addr, &entry.next)))
280
return false;
281
282
if (!(addr = ReadPointer(addr, &entry.prev)))
283
return false;
284
285
entry.path = ReadStringFromMemory(entry.path_addr);
286
287
return true;
288
}
289
290
bool HexagonDYLDRendezvous::FindMetadata(const char *name, PThreadField field,
291
uint32_t &value) {
292
Target &target = m_process->GetTarget();
293
294
SymbolContextList list;
295
target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
296
eSymbolTypeAny, list);
297
if (list.IsEmpty())
298
return false;
299
300
Address address = list[0].symbol->GetAddress();
301
addr_t addr = address.GetLoadAddress(&target);
302
if (addr == LLDB_INVALID_ADDRESS)
303
return false;
304
305
Status error;
306
value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
307
addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
308
if (error.Fail())
309
return false;
310
311
if (field == eSize)
312
value /= 8; // convert bits to bytes
313
314
return true;
315
}
316
317
const HexagonDYLDRendezvous::ThreadInfo &
318
HexagonDYLDRendezvous::GetThreadInfo() {
319
if (!m_thread_info.valid) {
320
bool ok = true;
321
322
ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,
323
m_thread_info.dtv_offset);
324
ok &=
325
FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
326
ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,
327
m_thread_info.modid_offset);
328
ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,
329
m_thread_info.tls_offset);
330
331
if (ok)
332
m_thread_info.valid = true;
333
}
334
335
return m_thread_info;
336
}
337
338
void HexagonDYLDRendezvous::DumpToLog(Log *log) const {
339
int state = GetState();
340
341
if (!log)
342
return;
343
344
log->PutCString("HexagonDYLDRendezvous:");
345
LLDB_LOGF(log, " Address: %" PRIx64, GetRendezvousAddress());
346
LLDB_LOGF(log, " Version: %" PRIu64, GetVersion());
347
LLDB_LOGF(log, " Link : %" PRIx64, GetLinkMapAddress());
348
LLDB_LOGF(log, " Break : %" PRIx64, GetBreakAddress());
349
LLDB_LOGF(log, " LDBase : %" PRIx64, GetLDBase());
350
LLDB_LOGF(log, " State : %s",
351
(state == eConsistent)
352
? "consistent"
353
: (state == eAdd) ? "add"
354
: (state == eDelete) ? "delete" : "unknown");
355
356
iterator I = begin();
357
iterator E = end();
358
359
if (I != E)
360
log->PutCString("HexagonDYLDRendezvous SOEntries:");
361
362
for (int i = 1; I != E; ++I, ++i) {
363
LLDB_LOGF(log, "\n SOEntry [%d] %s", i, I->path.c_str());
364
LLDB_LOGF(log, " Base : %" PRIx64, I->base_addr);
365
LLDB_LOGF(log, " Path : %" PRIx64, I->path_addr);
366
LLDB_LOGF(log, " Dyn : %" PRIx64, I->dyn_addr);
367
LLDB_LOGF(log, " Next : %" PRIx64, I->next);
368
LLDB_LOGF(log, " Prev : %" PRIx64, I->prev);
369
}
370
}
371
372