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/POSIX-DYLD/DYLDRendezvous.cpp
39653 views
1
//===-- DYLDRendezvous.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/ObjectFile.h"
11
#include "lldb/Symbol/Symbol.h"
12
#include "lldb/Symbol/SymbolContext.h"
13
#include "lldb/Target/Platform.h"
14
#include "lldb/Target/Process.h"
15
#include "lldb/Target/Target.h"
16
#include "lldb/Utility/ArchSpec.h"
17
#include "lldb/Utility/LLDBLog.h"
18
#include "lldb/Utility/Log.h"
19
#include "lldb/Utility/Status.h"
20
21
#include "llvm/Support/Path.h"
22
23
#include "DYLDRendezvous.h"
24
25
using namespace lldb;
26
using namespace lldb_private;
27
28
const char *DYLDRendezvous::StateToCStr(RendezvousState state) {
29
switch (state) {
30
case DYLDRendezvous::eConsistent:
31
return "eConsistent";
32
case DYLDRendezvous::eAdd:
33
return "eAdd";
34
case DYLDRendezvous::eDelete:
35
return "eDelete";
36
}
37
return "<invalid RendezvousState>";
38
}
39
40
const char *DYLDRendezvous::ActionToCStr(RendezvousAction action) {
41
switch (action) {
42
case DYLDRendezvous::RendezvousAction::eTakeSnapshot:
43
return "eTakeSnapshot";
44
case DYLDRendezvous::RendezvousAction::eAddModules:
45
return "eAddModules";
46
case DYLDRendezvous::RendezvousAction::eRemoveModules:
47
return "eRemoveModules";
48
case DYLDRendezvous::RendezvousAction::eNoAction:
49
return "eNoAction";
50
}
51
return "<invalid RendezvousAction>";
52
}
53
54
DYLDRendezvous::DYLDRendezvous(Process *process)
55
: m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS),
56
m_executable_interpreter(false), m_current(), m_previous(),
57
m_loaded_modules(), m_soentries(), m_added_soentries(),
58
m_removed_soentries() {
59
m_thread_info.valid = false;
60
UpdateExecutablePath();
61
}
62
63
addr_t DYLDRendezvous::ResolveRendezvousAddress() {
64
Log *log = GetLog(LLDBLog::DynamicLoader);
65
addr_t info_location;
66
addr_t info_addr;
67
Status error;
68
69
if (!m_process) {
70
LLDB_LOGF(log, "%s null process provided", __FUNCTION__);
71
return LLDB_INVALID_ADDRESS;
72
}
73
74
// Try to get it from our process. This might be a remote process and might
75
// grab it via some remote-specific mechanism.
76
info_location = m_process->GetImageInfoAddress();
77
LLDB_LOGF(log, "%s info_location = 0x%" PRIx64, __FUNCTION__, info_location);
78
79
// If the process fails to return an address, fall back to seeing if the
80
// local object file can help us find it.
81
if (info_location == LLDB_INVALID_ADDRESS) {
82
Target *target = &m_process->GetTarget();
83
if (target) {
84
ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
85
Address addr = obj_file->GetImageInfoAddress(target);
86
87
if (addr.IsValid()) {
88
info_location = addr.GetLoadAddress(target);
89
LLDB_LOGF(log,
90
"%s resolved via direct object file approach to 0x%" PRIx64,
91
__FUNCTION__, info_location);
92
} else {
93
const Symbol *_r_debug =
94
target->GetExecutableModule()->FindFirstSymbolWithNameAndType(
95
ConstString("_r_debug"));
96
if (_r_debug) {
97
info_addr = _r_debug->GetAddress().GetLoadAddress(target);
98
if (info_addr != LLDB_INVALID_ADDRESS) {
99
LLDB_LOGF(log,
100
"%s resolved by finding symbol '_r_debug' whose value is "
101
"0x%" PRIx64,
102
__FUNCTION__, info_addr);
103
m_executable_interpreter = true;
104
return info_addr;
105
}
106
}
107
LLDB_LOGF(log,
108
"%s FAILED - direct object file approach did not yield a "
109
"valid address",
110
__FUNCTION__);
111
}
112
}
113
}
114
115
if (info_location == LLDB_INVALID_ADDRESS) {
116
LLDB_LOGF(log, "%s FAILED - invalid info address", __FUNCTION__);
117
return LLDB_INVALID_ADDRESS;
118
}
119
120
LLDB_LOGF(log, "%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64,
121
__FUNCTION__, m_process->GetAddressByteSize(), info_location);
122
123
info_addr = m_process->ReadPointerFromMemory(info_location, error);
124
if (error.Fail()) {
125
LLDB_LOGF(log, "%s FAILED - could not read from the info location: %s",
126
__FUNCTION__, error.AsCString());
127
return LLDB_INVALID_ADDRESS;
128
}
129
130
if (info_addr == 0) {
131
LLDB_LOGF(log,
132
"%s FAILED - the rendezvous address contained at 0x%" PRIx64
133
" returned a null value",
134
__FUNCTION__, info_location);
135
return LLDB_INVALID_ADDRESS;
136
}
137
138
return info_addr;
139
}
140
141
void DYLDRendezvous::UpdateExecutablePath() {
142
if (m_process) {
143
Log *log = GetLog(LLDBLog::DynamicLoader);
144
Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
145
if (exe_mod) {
146
m_exe_file_spec = exe_mod->GetPlatformFileSpec();
147
LLDB_LOGF(log, "DYLDRendezvous::%s exe module executable path set: '%s'",
148
__FUNCTION__, m_exe_file_spec.GetPath().c_str());
149
} else {
150
LLDB_LOGF(log,
151
"DYLDRendezvous::%s cannot cache exe module path: null "
152
"executable module pointer",
153
__FUNCTION__);
154
}
155
}
156
}
157
158
void DYLDRendezvous::Rendezvous::DumpToLog(Log *log, const char *label) {
159
LLDB_LOGF(log, "%s Rendezvous: version = %" PRIu64 ", map_addr = 0x%16.16"
160
PRIx64 ", brk = 0x%16.16" PRIx64 ", state = %" PRIu64
161
" (%s), ldbase = 0x%16.16" PRIx64, label ? label : "", version,
162
map_addr, brk, state, StateToCStr((RendezvousState)state), ldbase);
163
}
164
165
bool DYLDRendezvous::Resolve() {
166
Log *log = GetLog(LLDBLog::DynamicLoader);
167
168
const size_t word_size = 4;
169
Rendezvous info;
170
size_t address_size;
171
size_t padding;
172
addr_t info_addr;
173
addr_t cursor;
174
175
address_size = m_process->GetAddressByteSize();
176
padding = address_size - word_size;
177
LLDB_LOGF(log,
178
"DYLDRendezvous::%s address size: %" PRIu64 ", padding %" PRIu64,
179
__FUNCTION__, uint64_t(address_size), uint64_t(padding));
180
181
if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
182
cursor = info_addr =
183
ResolveRendezvousAddress();
184
else
185
cursor = info_addr = m_rendezvous_addr;
186
LLDB_LOGF(log, "DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__,
187
cursor);
188
189
if (cursor == LLDB_INVALID_ADDRESS)
190
return false;
191
192
if (!(cursor = ReadWord(cursor, &info.version, word_size)))
193
return false;
194
195
if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
196
return false;
197
198
if (!(cursor = ReadPointer(cursor, &info.brk)))
199
return false;
200
201
if (!(cursor = ReadWord(cursor, &info.state, word_size)))
202
return false;
203
204
if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
205
return false;
206
207
// The rendezvous was successfully read. Update our internal state.
208
m_rendezvous_addr = info_addr;
209
m_previous = m_current;
210
m_current = info;
211
212
m_previous.DumpToLog(log, "m_previous");
213
m_current.DumpToLog(log, "m_current ");
214
215
if (m_current.map_addr == 0)
216
return false;
217
218
if (UpdateSOEntriesFromRemote())
219
return true;
220
221
return UpdateSOEntries();
222
}
223
224
bool DYLDRendezvous::IsValid() {
225
return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
226
}
227
228
DYLDRendezvous::RendezvousAction DYLDRendezvous::GetAction() const {
229
// If we have a core file, we will read the current rendezvous state
230
// from the core file's memory into m_current which can be in an inconsistent
231
// state, so we can't rely on its state to determine what we should do. We
232
// always need it to load all of the shared libraries one time when we attach
233
// to a core file.
234
if (IsCoreFile())
235
return eTakeSnapshot;
236
237
switch (m_current.state) {
238
239
case eConsistent:
240
switch (m_previous.state) {
241
// When the previous and current states are consistent this is the first
242
// time we have been asked to update. Just take a snapshot of the
243
// currently loaded modules.
244
case eConsistent:
245
return eTakeSnapshot;
246
// If we are about to add or remove a shared object clear out the current
247
// state and take a snapshot of the currently loaded images.
248
case eAdd:
249
return eAddModules;
250
case eDelete:
251
return eRemoveModules;
252
}
253
break;
254
255
case eAdd:
256
// If the main executable or a shared library defines a publicly visible
257
// symbol named "_r_debug", then it will cause problems once the executable
258
// that contains the symbol is loaded into the process. The correct
259
// "_r_debug" structure is currently found by LLDB by looking through
260
// the .dynamic section in the main executable and finding the DT_DEBUG tag
261
// entry.
262
//
263
// An issue comes up if someone defines another publicly visible "_r_debug"
264
// struct in their program. Sample code looks like:
265
//
266
// #include <link.h>
267
// r_debug _r_debug;
268
//
269
// If code like this is in an executable or shared library, this creates a
270
// new "_r_debug" structure and it causes problems once the executable is
271
// loaded due to the way symbol lookups happen in linux: the shared library
272
// list from _r_debug.r_map will be searched for a symbol named "_r_debug"
273
// and the first match will be the new version that is used. The dynamic
274
// loader is always last in this list. So at some point the dynamic loader
275
// will start updating the copy of "_r_debug" that gets found first. The
276
// issue is that LLDB will only look at the copy that is pointed to by the
277
// DT_DEBUG entry, or the initial version from the ld.so binary.
278
//
279
// Steps that show the problem are:
280
//
281
// - LLDB finds the "_r_debug" structure via the DT_DEBUG entry in the
282
// .dynamic section and this points to the "_r_debug" in ld.so
283
// - ld.so uodates its copy of "_r_debug" with "state = eAdd" before it
284
// loads the dependent shared libraries for the main executable and
285
// any dependencies of all shared libraries from the executable's list
286
// and ld.so code calls the debugger notification function
287
// that LLDB has set a breakpoint on.
288
// - LLDB hits the breakpoint and the breakpoint has a callback function
289
// where we read the _r_debug.state (eAdd) state and we do nothing as the
290
// "eAdd" state indicates that the shared libraries are about to be added.
291
// - ld.so finishes loading the main executable and any dependent shared
292
// libraries and it will update the "_r_debug.state" member with a
293
// "eConsistent", but it now updates the "_r_debug" in the a.out program
294
// and it calls the debugger notification function.
295
// - lldb hits the notification breakpoint and checks the ld.so copy of
296
// "_r_debug.state" which still has a state of "eAdd", but LLDB needs to see a
297
// "eConsistent" state to trigger the shared libraries to get loaded into
298
// the debug session, but LLDB the ld.so _r_debug.state which still
299
// contains "eAdd" and doesn't do anyhing and library load is missed.
300
// The "_r_debug" in a.out has the state set correctly to "eConsistent"
301
// but LLDB is still looking at the "_r_debug" from ld.so.
302
//
303
// So if we detect two "eAdd" states in a row, we assume this is the issue
304
// and we now load shared libraries correctly and will emit a log message
305
// in the "log enable lldb dyld" log channel which states there might be
306
// multiple "_r_debug" structs causing problems.
307
//
308
// The correct solution is that no one should be adding a duplicate
309
// publicly visible "_r_debug" symbols to their binaries, but we have
310
// programs that are doing this already and since it can be done, we should
311
// be able to work with this and keep debug sessions working as expected.
312
//
313
// If a user includes the <link.h> file, they can just use the existing
314
// "_r_debug" structure as it is defined in this header file as "extern
315
// struct r_debug _r_debug;" and no local copies need to be made.
316
if (m_previous.state == eAdd) {
317
Log *log = GetLog(LLDBLog::DynamicLoader);
318
LLDB_LOG(log, "DYLDRendezvous::GetAction() found two eAdd states in a "
319
"row, check process for multiple \"_r_debug\" symbols. "
320
"Returning eAddModules to ensure shared libraries get loaded "
321
"correctly");
322
return eAddModules;
323
}
324
return eNoAction;
325
case eDelete:
326
return eNoAction;
327
}
328
329
return eNoAction;
330
}
331
332
bool DYLDRendezvous::UpdateSOEntriesFromRemote() {
333
const auto action = GetAction();
334
Log *log = GetLog(LLDBLog::DynamicLoader);
335
LLDB_LOG(log, "{0} action = {1}", LLVM_PRETTY_FUNCTION, ActionToCStr(action));
336
337
if (action == eNoAction)
338
return false;
339
340
m_added_soentries.clear();
341
m_removed_soentries.clear();
342
if (action == eTakeSnapshot) {
343
// We already have the loaded list from the previous update so no need to
344
// find all the modules again.
345
if (!m_loaded_modules.m_list.empty())
346
return true;
347
}
348
349
llvm::Expected<LoadedModuleInfoList> module_list =
350
m_process->GetLoadedModuleList();
351
if (!module_list) {
352
llvm::consumeError(module_list.takeError());
353
return false;
354
}
355
356
switch (action) {
357
case eTakeSnapshot:
358
m_soentries.clear();
359
return SaveSOEntriesFromRemote(*module_list);
360
case eAddModules:
361
return AddSOEntriesFromRemote(*module_list);
362
case eRemoveModules:
363
return RemoveSOEntriesFromRemote(*module_list);
364
case eNoAction:
365
return false;
366
}
367
llvm_unreachable("Fully covered switch above!");
368
}
369
370
bool DYLDRendezvous::UpdateSOEntries() {
371
m_added_soentries.clear();
372
m_removed_soentries.clear();
373
const auto action = GetAction();
374
Log *log = GetLog(LLDBLog::DynamicLoader);
375
LLDB_LOG(log, "{0} action = {1}", LLVM_PRETTY_FUNCTION, ActionToCStr(action));
376
switch (action) {
377
case eTakeSnapshot:
378
m_soentries.clear();
379
return TakeSnapshot(m_soentries);
380
case eAddModules:
381
return AddSOEntries();
382
case eRemoveModules:
383
return RemoveSOEntries();
384
case eNoAction:
385
return false;
386
}
387
llvm_unreachable("Fully covered switch above!");
388
}
389
390
bool DYLDRendezvous::FillSOEntryFromModuleInfo(
391
LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry) {
392
addr_t link_map_addr;
393
addr_t base_addr;
394
addr_t dyn_addr;
395
std::string name;
396
397
if (!modInfo.get_link_map(link_map_addr) || !modInfo.get_base(base_addr) ||
398
!modInfo.get_dynamic(dyn_addr) || !modInfo.get_name(name))
399
return false;
400
401
entry.link_addr = link_map_addr;
402
entry.base_addr = base_addr;
403
entry.dyn_addr = dyn_addr;
404
405
entry.file_spec.SetFile(name, FileSpec::Style::native);
406
407
UpdateBaseAddrIfNecessary(entry, name);
408
409
// not needed if we're using ModuleInfos
410
entry.next = 0;
411
entry.prev = 0;
412
entry.path_addr = 0;
413
414
return true;
415
}
416
417
bool DYLDRendezvous::SaveSOEntriesFromRemote(
418
const LoadedModuleInfoList &module_list) {
419
for (auto const &modInfo : module_list.m_list) {
420
SOEntry entry;
421
if (!FillSOEntryFromModuleInfo(modInfo, entry))
422
return false;
423
424
// Only add shared libraries and not the executable.
425
if (!SOEntryIsMainExecutable(entry)) {
426
UpdateFileSpecIfNecessary(entry);
427
m_soentries.push_back(entry);
428
}
429
}
430
431
m_loaded_modules = module_list;
432
return true;
433
}
434
435
bool DYLDRendezvous::AddSOEntriesFromRemote(
436
const LoadedModuleInfoList &module_list) {
437
for (auto const &modInfo : module_list.m_list) {
438
bool found = false;
439
for (auto const &existing : m_loaded_modules.m_list) {
440
if (modInfo == existing) {
441
found = true;
442
break;
443
}
444
}
445
446
if (found)
447
continue;
448
449
SOEntry entry;
450
if (!FillSOEntryFromModuleInfo(modInfo, entry))
451
return false;
452
453
// Only add shared libraries and not the executable.
454
if (!SOEntryIsMainExecutable(entry)) {
455
UpdateFileSpecIfNecessary(entry);
456
m_soentries.push_back(entry);
457
m_added_soentries.push_back(entry);
458
}
459
}
460
461
m_loaded_modules = module_list;
462
return true;
463
}
464
465
bool DYLDRendezvous::RemoveSOEntriesFromRemote(
466
const LoadedModuleInfoList &module_list) {
467
for (auto const &existing : m_loaded_modules.m_list) {
468
bool found = false;
469
for (auto const &modInfo : module_list.m_list) {
470
if (modInfo == existing) {
471
found = true;
472
break;
473
}
474
}
475
476
if (found)
477
continue;
478
479
SOEntry entry;
480
if (!FillSOEntryFromModuleInfo(existing, entry))
481
return false;
482
483
// Only add shared libraries and not the executable.
484
if (!SOEntryIsMainExecutable(entry)) {
485
auto pos = llvm::find(m_soentries, entry);
486
if (pos == m_soentries.end())
487
return false;
488
489
m_soentries.erase(pos);
490
m_removed_soentries.push_back(entry);
491
}
492
}
493
494
m_loaded_modules = module_list;
495
return true;
496
}
497
498
bool DYLDRendezvous::AddSOEntries() {
499
SOEntry entry;
500
iterator pos;
501
502
assert(m_previous.state == eAdd);
503
504
if (m_current.map_addr == 0)
505
return false;
506
507
for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
508
if (!ReadSOEntryFromMemory(cursor, entry))
509
return false;
510
511
// Only add shared libraries and not the executable.
512
if (SOEntryIsMainExecutable(entry))
513
continue;
514
515
UpdateFileSpecIfNecessary(entry);
516
517
if (!llvm::is_contained(m_soentries, entry)) {
518
m_soentries.push_back(entry);
519
m_added_soentries.push_back(entry);
520
}
521
}
522
523
return true;
524
}
525
526
bool DYLDRendezvous::RemoveSOEntries() {
527
SOEntryList entry_list;
528
iterator pos;
529
530
assert(m_previous.state == eDelete);
531
532
if (!TakeSnapshot(entry_list))
533
return false;
534
535
for (iterator I = begin(); I != end(); ++I) {
536
if (!llvm::is_contained(entry_list, *I))
537
m_removed_soentries.push_back(*I);
538
}
539
540
m_soentries = entry_list;
541
return true;
542
}
543
544
bool DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) {
545
// On some systes the executable is indicated by an empty path in the entry.
546
// On others it is the full path to the executable.
547
548
auto triple = m_process->GetTarget().GetArchitecture().GetTriple();
549
switch (triple.getOS()) {
550
case llvm::Triple::FreeBSD:
551
case llvm::Triple::NetBSD:
552
case llvm::Triple::OpenBSD:
553
return entry.file_spec == m_exe_file_spec;
554
case llvm::Triple::Linux:
555
if (triple.isAndroid())
556
return entry.file_spec == m_exe_file_spec;
557
// If we are debugging ld.so, then all SOEntries should be treated as
558
// libraries, including the "main" one (denoted by an empty string).
559
if (!entry.file_spec && m_executable_interpreter)
560
return false;
561
return !entry.file_spec;
562
default:
563
return false;
564
}
565
}
566
567
bool DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
568
SOEntry entry;
569
570
if (m_current.map_addr == 0)
571
return false;
572
573
// Clear previous entries since we are about to obtain an up to date list.
574
entry_list.clear();
575
576
for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
577
if (!ReadSOEntryFromMemory(cursor, entry))
578
return false;
579
580
// Only add shared libraries and not the executable.
581
if (SOEntryIsMainExecutable(entry))
582
continue;
583
584
UpdateFileSpecIfNecessary(entry);
585
586
entry_list.push_back(entry);
587
}
588
589
return true;
590
}
591
592
addr_t DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) {
593
Status error;
594
595
*dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
596
if (error.Fail())
597
return 0;
598
599
return addr + size;
600
}
601
602
addr_t DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
603
Status error;
604
605
*dst = m_process->ReadPointerFromMemory(addr, error);
606
if (error.Fail())
607
return 0;
608
609
return addr + m_process->GetAddressByteSize();
610
}
611
612
std::string DYLDRendezvous::ReadStringFromMemory(addr_t addr) {
613
std::string str;
614
Status error;
615
616
if (addr == LLDB_INVALID_ADDRESS)
617
return std::string();
618
619
m_process->ReadCStringFromMemory(addr, str, error);
620
621
return str;
622
}
623
624
// Returns true if the load bias reported by the linker is incorrect for the
625
// given entry. This function is used to handle cases where we want to work
626
// around a bug in the system linker.
627
static bool isLoadBiasIncorrect(Target &target, const std::string &file_path) {
628
// On Android L (API 21, 22) the load address of the "/system/bin/linker"
629
// isn't filled in correctly.
630
unsigned os_major = target.GetPlatform()->GetOSVersion().getMajor();
631
return target.GetArchitecture().GetTriple().isAndroid() &&
632
(os_major == 21 || os_major == 22) &&
633
(file_path == "/system/bin/linker" ||
634
file_path == "/system/bin/linker64");
635
}
636
637
void DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry,
638
std::string const &file_path) {
639
// If the load bias reported by the linker is incorrect then fetch the load
640
// address of the file from the proc file system.
641
if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) {
642
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
643
bool is_loaded = false;
644
Status error =
645
m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr);
646
if (error.Success() && is_loaded)
647
entry.base_addr = load_addr;
648
}
649
}
650
651
void DYLDRendezvous::UpdateFileSpecIfNecessary(SOEntry &entry) {
652
// Updates filename if empty. It is useful while debugging ld.so,
653
// when the link map returns empty string for the main executable.
654
if (!entry.file_spec) {
655
MemoryRegionInfo region;
656
Status region_status =
657
m_process->GetMemoryRegionInfo(entry.dyn_addr, region);
658
if (!region.GetName().IsEmpty())
659
entry.file_spec.SetFile(region.GetName().AsCString(),
660
FileSpec::Style::native);
661
}
662
}
663
664
bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) {
665
entry.clear();
666
667
entry.link_addr = addr;
668
669
if (!(addr = ReadPointer(addr, &entry.base_addr)))
670
return false;
671
672
// mips adds an extra load offset field to the link map struct on FreeBSD and
673
// NetBSD (need to validate other OSes).
674
// http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57
675
const ArchSpec &arch = m_process->GetTarget().GetArchitecture();
676
if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD ||
677
arch.GetTriple().getOS() == llvm::Triple::NetBSD) &&
678
arch.IsMIPS()) {
679
addr_t mips_l_offs;
680
if (!(addr = ReadPointer(addr, &mips_l_offs)))
681
return false;
682
if (mips_l_offs != 0 && mips_l_offs != entry.base_addr)
683
return false;
684
}
685
686
if (!(addr = ReadPointer(addr, &entry.path_addr)))
687
return false;
688
689
if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
690
return false;
691
692
if (!(addr = ReadPointer(addr, &entry.next)))
693
return false;
694
695
if (!(addr = ReadPointer(addr, &entry.prev)))
696
return false;
697
698
std::string file_path = ReadStringFromMemory(entry.path_addr);
699
entry.file_spec.SetFile(file_path, FileSpec::Style::native);
700
701
UpdateBaseAddrIfNecessary(entry, file_path);
702
703
return true;
704
}
705
706
bool DYLDRendezvous::FindMetadata(const char *name, PThreadField field,
707
uint32_t &value) {
708
Target &target = m_process->GetTarget();
709
710
SymbolContextList list;
711
target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
712
eSymbolTypeAny, list);
713
if (list.IsEmpty())
714
return false;
715
716
Address address = list[0].symbol->GetAddress();
717
address.SetOffset(address.GetOffset() + field * sizeof(uint32_t));
718
719
// Read from target memory as this allows us to try process memory and
720
// fallback to reading from read only sections from the object files. Here we
721
// are reading read only data from libpthread.so to find data in the thread
722
// specific area for the data we want and this won't be saved into process
723
// memory due to it being read only.
724
Status error;
725
value =
726
target.ReadUnsignedIntegerFromMemory(address, sizeof(uint32_t), 0, error);
727
if (error.Fail())
728
return false;
729
730
if (field == eSize)
731
value /= 8; // convert bits to bytes
732
733
return true;
734
}
735
736
const DYLDRendezvous::ThreadInfo &DYLDRendezvous::GetThreadInfo() {
737
if (!m_thread_info.valid) {
738
bool ok = true;
739
740
ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,
741
m_thread_info.dtv_offset);
742
ok &=
743
FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
744
ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,
745
m_thread_info.modid_offset);
746
ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,
747
m_thread_info.tls_offset);
748
749
if (ok)
750
m_thread_info.valid = true;
751
}
752
753
return m_thread_info;
754
}
755
756
void DYLDRendezvous::DumpToLog(Log *log) const {
757
int state = GetState();
758
759
if (!log)
760
return;
761
762
log->PutCString("DYLDRendezvous:");
763
LLDB_LOGF(log, " Address: %" PRIx64, GetRendezvousAddress());
764
LLDB_LOGF(log, " Version: %" PRIu64, GetVersion());
765
LLDB_LOGF(log, " Link : %" PRIx64, GetLinkMapAddress());
766
LLDB_LOGF(log, " Break : %" PRIx64, GetBreakAddress());
767
LLDB_LOGF(log, " LDBase : %" PRIx64, GetLDBase());
768
LLDB_LOGF(log, " State : %s",
769
(state == eConsistent)
770
? "consistent"
771
: (state == eAdd) ? "add"
772
: (state == eDelete) ? "delete" : "unknown");
773
774
iterator I = begin();
775
iterator E = end();
776
777
if (I != E)
778
log->PutCString("DYLDRendezvous SOEntries:");
779
780
for (int i = 1; I != E; ++I, ++i) {
781
LLDB_LOGF(log, "\n SOEntry [%d] %s", i, I->file_spec.GetPath().c_str());
782
LLDB_LOGF(log, " Base : %" PRIx64, I->base_addr);
783
LLDB_LOGF(log, " Path : %" PRIx64, I->path_addr);
784
LLDB_LOGF(log, " Dyn : %" PRIx64, I->dyn_addr);
785
LLDB_LOGF(log, " Next : %" PRIx64, I->next);
786
LLDB_LOGF(log, " Prev : %" PRIx64, I->prev);
787
}
788
}
789
790
bool DYLDRendezvous::IsCoreFile() const {
791
return !m_process->IsLiveDebugSession();
792
}
793
794