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
25using namespace lldb;
26using namespace lldb_private;
27
28const 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
40const 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
54DYLDRendezvous::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
63addr_t DYLDRendezvous::ResolveRendezvousAddress() {
64 Log *log = GetLog(mask: 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 name: 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(vm_addr: 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
141void DYLDRendezvous::UpdateExecutablePath() {
142 if (m_process) {
143 Log *log = GetLog(mask: 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
158void 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
165bool DYLDRendezvous::Resolve() {
166 Log *log = GetLog(mask: 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(addr: cursor, dst: &info.version, size: word_size)))
193 return false;
194
195 if (!(cursor = ReadPointer(addr: cursor + padding, dst: &info.map_addr)))
196 return false;
197
198 if (!(cursor = ReadPointer(addr: cursor, dst: &info.brk)))
199 return false;
200
201 if (!(cursor = ReadWord(addr: cursor, dst: &info.state, size: word_size)))
202 return false;
203
204 if (!(cursor = ReadPointer(addr: cursor + padding, dst: &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, label: "m_previous");
213 m_current.DumpToLog(log, label: "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
224bool DYLDRendezvous::IsValid() {
225 return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
226}
227
228DYLDRendezvous::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(mask: 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
332bool DYLDRendezvous::UpdateSOEntriesFromRemote() {
333 const auto action = GetAction();
334 Log *log = GetLog(mask: 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(Err: module_list.takeError());
353 return false;
354 }
355
356 switch (action) {
357 case eTakeSnapshot:
358 m_soentries.clear();
359 return SaveSOEntriesFromRemote(module_list: *module_list);
360 case eAddModules:
361 return AddSOEntriesFromRemote(module_list: *module_list);
362 case eRemoveModules:
363 return RemoveSOEntriesFromRemote(module_list: *module_list);
364 case eNoAction:
365 return false;
366 }
367 llvm_unreachable("Fully covered switch above!");
368}
369
370bool DYLDRendezvous::UpdateSOEntries() {
371 m_added_soentries.clear();
372 m_removed_soentries.clear();
373 const auto action = GetAction();
374 Log *log = GetLog(mask: 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(entry_list&: 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
390bool 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(out&: link_map_addr) || !modInfo.get_base(out&: base_addr) ||
398 !modInfo.get_dynamic(out&: dyn_addr) || !modInfo.get_name(out&: 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(path: name, style: FileSpec::Style::native);
406
407 UpdateBaseAddrIfNecessary(entry, file_path: 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
417bool 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(x: entry);
428 }
429 }
430
431 m_loaded_modules = module_list;
432 return true;
433}
434
435bool 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(x: entry);
457 m_added_soentries.push_back(x: entry);
458 }
459 }
460
461 m_loaded_modules = module_list;
462 return true;
463}
464
465bool 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(modInfo: existing, entry))
481 return false;
482
483 // Only add shared libraries and not the executable.
484 if (!SOEntryIsMainExecutable(entry)) {
485 auto pos = llvm::find(Range&: m_soentries, Val: entry);
486 if (pos == m_soentries.end())
487 return false;
488
489 m_soentries.erase(position: pos);
490 m_removed_soentries.push_back(x: entry);
491 }
492 }
493
494 m_loaded_modules = module_list;
495 return true;
496}
497
498bool 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(addr: 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(Range&: m_soentries, Element: entry)) {
518 m_soentries.push_back(x: entry);
519 m_added_soentries.push_back(x: entry);
520 }
521 }
522
523 return true;
524}
525
526bool 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(Range&: entry_list, Element: *I))
537 m_removed_soentries.push_back(x: *I);
538 }
539
540 m_soentries = entry_list;
541 return true;
542}
543
544bool 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
567bool 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(addr: 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(x: entry);
587 }
588
589 return true;
590}
591
592addr_t DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) {
593 Status error;
594
595 *dst = m_process->ReadUnsignedIntegerFromMemory(load_addr: addr, byte_size: size, fail_value: 0, error);
596 if (error.Fail())
597 return 0;
598
599 return addr + size;
600}
601
602addr_t DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
603 Status error;
604
605 *dst = m_process->ReadPointerFromMemory(vm_addr: addr, error);
606 if (error.Fail())
607 return 0;
608
609 return addr + m_process->GetAddressByteSize();
610}
611
612std::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(vm_addr: addr, out_str&: 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.
627static 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
637void 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(target&: 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(file: entry.file_spec, is_loaded, load_addr);
646 if (error.Success() && is_loaded)
647 entry.base_addr = load_addr;
648 }
649}
650
651void 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(load_addr: entry.dyn_addr, range_info&: region);
658 if (!region.GetName().IsEmpty())
659 entry.file_spec.SetFile(path: region.GetName().AsCString(),
660 style: FileSpec::Style::native);
661 }
662}
663
664bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) {
665 entry.clear();
666
667 entry.link_addr = addr;
668
669 if (!(addr = ReadPointer(addr, dst: &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, dst: &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, dst: &entry.path_addr)))
687 return false;
688
689 if (!(addr = ReadPointer(addr, dst: &entry.dyn_addr)))
690 return false;
691
692 if (!(addr = ReadPointer(addr, dst: &entry.next)))
693 return false;
694
695 if (!(addr = ReadPointer(addr, dst: &entry.prev)))
696 return false;
697
698 std::string file_path = ReadStringFromMemory(addr: entry.path_addr);
699 entry.file_spec.SetFile(path: file_path, style: FileSpec::Style::native);
700
701 UpdateBaseAddrIfNecessary(entry, file_path);
702
703 return true;
704}
705
706bool 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(name: ConstString(name),
712 symbol_type: eSymbolTypeAny, sc_list&: 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(addr: address, integer_byte_size: sizeof(uint32_t), fail_value: 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
736const DYLDRendezvous::ThreadInfo &DYLDRendezvous::GetThreadInfo() {
737 if (!m_thread_info.valid) {
738 bool ok = true;
739
740 ok &= FindMetadata(name: "_thread_db_pthread_dtvp", field: eOffset,
741 value&: m_thread_info.dtv_offset);
742 ok &=
743 FindMetadata(name: "_thread_db_dtv_dtv", field: eSize, value&: m_thread_info.dtv_slot_size);
744 ok &= FindMetadata(name: "_thread_db_link_map_l_tls_modid", field: eOffset,
745 value&: m_thread_info.modid_offset);
746 ok &= FindMetadata(name: "_thread_db_dtv_t_pointer_val", field: eOffset,
747 value&: m_thread_info.tls_offset);
748
749 if (ok)
750 m_thread_info.valid = true;
751 }
752
753 return m_thread_info;
754}
755
756void DYLDRendezvous::DumpToLog(Log *log) const {
757 int state = GetState();
758
759 if (!log)
760 return;
761
762 log->PutCString(cstr: "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(cstr: "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
790bool DYLDRendezvous::IsCoreFile() const {
791 return !m_process->IsLiveDebugSession();
792}
793

source code of lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp