1 //===-- DYLDRendezvous.cpp --------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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/Log.h"
18 #include "lldb/Utility/Status.h"
20 #include "llvm/Support/Path.h"
22 #include "DYLDRendezvous.h"
25 using namespace lldb_private;
27 /// Locates the address of the rendezvous structure. Returns the address on
28 /// success and LLDB_INVALID_ADDRESS on failure.
29 static addr_t ResolveRendezvousAddress(Process *process) {
30 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
37 log->Printf("%s null process provided", __FUNCTION__);
38 return LLDB_INVALID_ADDRESS;
41 // Try to get it from our process. This might be a remote process and might
42 // grab it via some remote-specific mechanism.
43 info_location = process->GetImageInfoAddress();
45 log->Printf("%s info_location = 0x%" PRIx64, __FUNCTION__, info_location);
47 // If the process fails to return an address, fall back to seeing if the
48 // local object file can help us find it.
49 if (info_location == LLDB_INVALID_ADDRESS) {
50 Target *target = &process->GetTarget();
52 ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
53 Address addr = obj_file->GetImageInfoAddress(target);
56 info_location = addr.GetLoadAddress(target);
59 "%s resolved via direct object file approach to 0x%" PRIx64,
60 __FUNCTION__, info_location);
63 log->Printf("%s FAILED - direct object file approach did not yield a "
70 if (info_location == LLDB_INVALID_ADDRESS) {
72 log->Printf("%s FAILED - invalid info address", __FUNCTION__);
73 return LLDB_INVALID_ADDRESS;
77 log->Printf("%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64,
78 __FUNCTION__, process->GetAddressByteSize(), info_location);
80 info_addr = process->ReadPointerFromMemory(info_location, error);
83 log->Printf("%s FAILED - could not read from the info location: %s",
84 __FUNCTION__, error.AsCString());
85 return LLDB_INVALID_ADDRESS;
90 log->Printf("%s FAILED - the rendezvous address contained at 0x%" PRIx64
91 " returned a null value",
92 __FUNCTION__, info_location);
93 return LLDB_INVALID_ADDRESS;
99 DYLDRendezvous::DYLDRendezvous(Process *process)
100 : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(),
101 m_previous(), m_loaded_modules(), m_soentries(), m_added_soentries(),
102 m_removed_soentries() {
103 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
105 m_thread_info.valid = false;
107 // Cache a copy of the executable path
109 Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
111 m_exe_file_spec = exe_mod->GetPlatformFileSpec();
113 log->Printf("DYLDRendezvous::%s exe module executable path set: '%s'",
114 __FUNCTION__, m_exe_file_spec.GetCString());
117 log->Printf("DYLDRendezvous::%s cannot cache exe module path: null "
118 "executable module pointer",
124 bool DYLDRendezvous::Resolve() {
125 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
127 const size_t word_size = 4;
134 address_size = m_process->GetAddressByteSize();
135 padding = address_size - word_size;
137 log->Printf("DYLDRendezvous::%s address size: %" PRIu64
138 ", padding %" PRIu64,
139 __FUNCTION__, uint64_t(address_size), uint64_t(padding));
141 if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
142 cursor = info_addr = ResolveRendezvousAddress(m_process);
144 cursor = info_addr = m_rendezvous_addr;
146 log->Printf("DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__, cursor);
148 if (cursor == LLDB_INVALID_ADDRESS)
151 if (!(cursor = ReadWord(cursor, &info.version, word_size)))
154 if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
157 if (!(cursor = ReadPointer(cursor, &info.brk)))
160 if (!(cursor = ReadWord(cursor, &info.state, word_size)))
163 if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
166 // The rendezvous was successfully read. Update our internal state.
167 m_rendezvous_addr = info_addr;
168 m_previous = m_current;
171 if (UpdateSOEntries(true))
174 return UpdateSOEntries();
177 bool DYLDRendezvous::IsValid() {
178 return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
181 bool DYLDRendezvous::UpdateSOEntries(bool fromRemote) {
183 LoadedModuleInfoList module_list;
185 // If we can't get the SO info from the remote, return failure.
186 if (fromRemote && m_process->LoadModules(module_list) == 0)
189 if (!fromRemote && m_current.map_addr == 0)
192 // When the previous and current states are consistent this is the first time
193 // we have been asked to update. Just take a snapshot of the currently
195 if (m_previous.state == eConsistent && m_current.state == eConsistent)
196 return fromRemote ? SaveSOEntriesFromRemote(module_list)
197 : TakeSnapshot(m_soentries);
199 // If we are about to add or remove a shared object clear out the current
200 // state and take a snapshot of the currently loaded images.
201 if (m_current.state == eAdd || m_current.state == eDelete) {
202 // Some versions of the android dynamic linker might send two notifications
203 // with state == eAdd back to back. Ignore them until we get an eConsistent
205 if (!(m_previous.state == eConsistent ||
206 (m_previous.state == eAdd && m_current.state == eDelete)))
211 return SaveSOEntriesFromRemote(module_list);
213 m_added_soentries.clear();
214 m_removed_soentries.clear();
215 return TakeSnapshot(m_soentries);
217 assert(m_current.state == eConsistent);
219 // Otherwise check the previous state to determine what to expect and update
221 if (m_previous.state == eAdd)
222 return fromRemote ? AddSOEntriesFromRemote(module_list) : AddSOEntries();
223 else if (m_previous.state == eDelete)
224 return fromRemote ? RemoveSOEntriesFromRemote(module_list)
230 bool DYLDRendezvous::FillSOEntryFromModuleInfo(
231 LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry) {
232 addr_t link_map_addr;
237 if (!modInfo.get_link_map(link_map_addr) || !modInfo.get_base(base_addr) ||
238 !modInfo.get_dynamic(dyn_addr) || !modInfo.get_name(name))
241 entry.link_addr = link_map_addr;
242 entry.base_addr = base_addr;
243 entry.dyn_addr = dyn_addr;
245 entry.file_spec.SetFile(name, FileSpec::Style::native);
247 UpdateBaseAddrIfNecessary(entry, name);
249 // not needed if we're using ModuleInfos
257 bool DYLDRendezvous::SaveSOEntriesFromRemote(
258 LoadedModuleInfoList &module_list) {
259 for (auto const &modInfo : module_list.m_list) {
261 if (!FillSOEntryFromModuleInfo(modInfo, entry))
264 // Only add shared libraries and not the executable.
265 if (!SOEntryIsMainExecutable(entry))
266 m_soentries.push_back(entry);
269 m_loaded_modules = module_list;
273 bool DYLDRendezvous::AddSOEntriesFromRemote(LoadedModuleInfoList &module_list) {
274 for (auto const &modInfo : module_list.m_list) {
276 for (auto const &existing : m_loaded_modules.m_list) {
277 if (modInfo == existing) {
287 if (!FillSOEntryFromModuleInfo(modInfo, entry))
290 // Only add shared libraries and not the executable.
291 if (!SOEntryIsMainExecutable(entry))
292 m_soentries.push_back(entry);
295 m_loaded_modules = module_list;
299 bool DYLDRendezvous::RemoveSOEntriesFromRemote(
300 LoadedModuleInfoList &module_list) {
301 for (auto const &existing : m_loaded_modules.m_list) {
303 for (auto const &modInfo : module_list.m_list) {
304 if (modInfo == existing) {
314 if (!FillSOEntryFromModuleInfo(existing, entry))
317 // Only add shared libraries and not the executable.
318 if (!SOEntryIsMainExecutable(entry)) {
319 auto pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
320 if (pos == m_soentries.end())
323 m_soentries.erase(pos);
327 m_loaded_modules = module_list;
331 bool DYLDRendezvous::AddSOEntries() {
335 assert(m_previous.state == eAdd);
337 if (m_current.map_addr == 0)
340 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
341 if (!ReadSOEntryFromMemory(cursor, entry))
344 // Only add shared libraries and not the executable.
345 if (SOEntryIsMainExecutable(entry))
348 pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
349 if (pos == m_soentries.end()) {
350 m_soentries.push_back(entry);
351 m_added_soentries.push_back(entry);
358 bool DYLDRendezvous::RemoveSOEntries() {
359 SOEntryList entry_list;
362 assert(m_previous.state == eDelete);
364 if (!TakeSnapshot(entry_list))
367 for (iterator I = begin(); I != end(); ++I) {
368 pos = std::find(entry_list.begin(), entry_list.end(), *I);
369 if (pos == entry_list.end())
370 m_removed_soentries.push_back(*I);
373 m_soentries = entry_list;
377 bool DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) {
378 // On some systes the executable is indicated by an empty path in the entry.
379 // On others it is the full path to the executable.
381 auto triple = m_process->GetTarget().GetArchitecture().GetTriple();
382 switch (triple.getOS()) {
383 case llvm::Triple::FreeBSD:
384 case llvm::Triple::NetBSD:
385 return entry.file_spec == m_exe_file_spec;
386 case llvm::Triple::Linux:
387 if (triple.isAndroid())
388 return entry.file_spec == m_exe_file_spec;
389 return !entry.file_spec;
395 bool DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
398 if (m_current.map_addr == 0)
401 // Clear previous entries since we are about to obtain an up to date list.
404 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
405 if (!ReadSOEntryFromMemory(cursor, entry))
408 // Only add shared libraries and not the executable.
409 if (SOEntryIsMainExecutable(entry))
412 entry_list.push_back(entry);
418 addr_t DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) {
421 *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
428 addr_t DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
431 *dst = m_process->ReadPointerFromMemory(addr, error);
435 return addr + m_process->GetAddressByteSize();
438 std::string DYLDRendezvous::ReadStringFromMemory(addr_t addr) {
442 if (addr == LLDB_INVALID_ADDRESS)
443 return std::string();
445 m_process->ReadCStringFromMemory(addr, str, error);
450 // Returns true if the load bias reported by the linker is incorrect for the
451 // given entry. This function is used to handle cases where we want to work
452 // around a bug in the system linker.
453 static bool isLoadBiasIncorrect(Target &target, const std::string &file_path) {
454 // On Android L (API 21, 22) the load address of the "/system/bin/linker"
455 // isn't filled in correctly.
456 unsigned os_major = target.GetPlatform()->GetOSVersion().getMajor();
457 return target.GetArchitecture().GetTriple().isAndroid() &&
458 (os_major == 21 || os_major == 22) &&
459 (file_path == "/system/bin/linker" ||
460 file_path == "/system/bin/linker64");
463 void DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry,
464 std::string const &file_path) {
465 // If the load bias reported by the linker is incorrect then fetch the load
466 // address of the file from the proc file system.
467 if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) {
468 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
469 bool is_loaded = false;
471 m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr);
472 if (error.Success() && is_loaded)
473 entry.base_addr = load_addr;
477 bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) {
480 entry.link_addr = addr;
482 if (!(addr = ReadPointer(addr, &entry.base_addr)))
485 // mips adds an extra load offset field to the link map struct on FreeBSD and
486 // NetBSD (need to validate other OSes).
487 // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57
488 const ArchSpec &arch = m_process->GetTarget().GetArchitecture();
489 if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD ||
490 arch.GetTriple().getOS() == llvm::Triple::NetBSD) &&
493 if (!(addr = ReadPointer(addr, &mips_l_offs)))
495 if (mips_l_offs != 0 && mips_l_offs != entry.base_addr)
499 if (!(addr = ReadPointer(addr, &entry.path_addr)))
502 if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
505 if (!(addr = ReadPointer(addr, &entry.next)))
508 if (!(addr = ReadPointer(addr, &entry.prev)))
511 std::string file_path = ReadStringFromMemory(entry.path_addr);
512 entry.file_spec.SetFile(file_path, FileSpec::Style::native);
514 UpdateBaseAddrIfNecessary(entry, file_path);
519 bool DYLDRendezvous::FindMetadata(const char *name, PThreadField field,
521 Target &target = m_process->GetTarget();
523 SymbolContextList list;
524 if (!target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
525 eSymbolTypeAny, list))
528 Address address = list[0].symbol->GetAddress();
529 addr_t addr = address.GetLoadAddress(&target);
530 if (addr == LLDB_INVALID_ADDRESS)
534 value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
535 addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
540 value /= 8; // convert bits to bytes
545 const DYLDRendezvous::ThreadInfo &DYLDRendezvous::GetThreadInfo() {
546 if (!m_thread_info.valid) {
549 ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,
550 m_thread_info.dtv_offset);
552 FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
553 ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,
554 m_thread_info.modid_offset);
555 ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,
556 m_thread_info.tls_offset);
559 m_thread_info.valid = true;
562 return m_thread_info;
565 void DYLDRendezvous::DumpToLog(Log *log) const {
566 int state = GetState();
571 log->PutCString("DYLDRendezvous:");
572 log->Printf(" Address: %" PRIx64, GetRendezvousAddress());
573 log->Printf(" Version: %" PRIu64, GetVersion());
574 log->Printf(" Link : %" PRIx64, GetLinkMapAddress());
575 log->Printf(" Break : %" PRIx64, GetBreakAddress());
576 log->Printf(" LDBase : %" PRIx64, GetLDBase());
577 log->Printf(" State : %s",
578 (state == eConsistent)
580 : (state == eAdd) ? "add" : (state == eDelete) ? "delete"
583 iterator I = begin();
587 log->PutCString("DYLDRendezvous SOEntries:");
589 for (int i = 1; I != E; ++I, ++i) {
590 log->Printf("\n SOEntry [%d] %s", i, I->file_spec.GetCString());
591 log->Printf(" Base : %" PRIx64, I->base_addr);
592 log->Printf(" Path : %" PRIx64, I->path_addr);
593 log->Printf(" Dyn : %" PRIx64, I->dyn_addr);
594 log->Printf(" Next : %" PRIx64, I->next);
595 log->Printf(" Prev : %" PRIx64, I->prev);