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/Log.h"
18 #include "lldb/Utility/Status.h"
19
20 #include "llvm/Support/Path.h"
21
22 #include "DYLDRendezvous.h"
23
24 using namespace lldb;
25 using namespace lldb_private;
26
27 /// Locates the address of the rendezvous structure. Returns the address on
28 /// success and LLDB_INVALID_ADDRESS on failure.
ResolveRendezvousAddress(Process * process)29 static addr_t ResolveRendezvousAddress(Process *process) {
30 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
31 addr_t info_location;
32 addr_t info_addr;
33 Status error;
34
35 if (!process) {
36 LLDB_LOGF(log, "%s null process provided", __FUNCTION__);
37 return LLDB_INVALID_ADDRESS;
38 }
39
40 // Try to get it from our process. This might be a remote process and might
41 // grab it via some remote-specific mechanism.
42 info_location = process->GetImageInfoAddress();
43 LLDB_LOGF(log, "%s info_location = 0x%" PRIx64, __FUNCTION__, info_location);
44
45 // If the process fails to return an address, fall back to seeing if the
46 // local object file can help us find it.
47 if (info_location == LLDB_INVALID_ADDRESS) {
48 Target *target = &process->GetTarget();
49 if (target) {
50 ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
51 Address addr = obj_file->GetImageInfoAddress(target);
52
53 if (addr.IsValid()) {
54 info_location = addr.GetLoadAddress(target);
55 LLDB_LOGF(log,
56 "%s resolved via direct object file approach to 0x%" PRIx64,
57 __FUNCTION__, info_location);
58 } else {
59 LLDB_LOGF(log,
60 "%s FAILED - direct object file approach did not yield a "
61 "valid address",
62 __FUNCTION__);
63 }
64 }
65 }
66
67 if (info_location == LLDB_INVALID_ADDRESS) {
68 LLDB_LOGF(log, "%s FAILED - invalid info address", __FUNCTION__);
69 return LLDB_INVALID_ADDRESS;
70 }
71
72 LLDB_LOGF(log, "%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64,
73 __FUNCTION__, process->GetAddressByteSize(), info_location);
74
75 info_addr = process->ReadPointerFromMemory(info_location, error);
76 if (error.Fail()) {
77 LLDB_LOGF(log, "%s FAILED - could not read from the info location: %s",
78 __FUNCTION__, error.AsCString());
79 return LLDB_INVALID_ADDRESS;
80 }
81
82 if (info_addr == 0) {
83 LLDB_LOGF(log,
84 "%s FAILED - the rendezvous address contained at 0x%" PRIx64
85 " returned a null value",
86 __FUNCTION__, info_location);
87 return LLDB_INVALID_ADDRESS;
88 }
89
90 return info_addr;
91 }
92
DYLDRendezvous(Process * process)93 DYLDRendezvous::DYLDRendezvous(Process *process)
94 : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(),
95 m_previous(), m_loaded_modules(), m_soentries(), m_added_soentries(),
96 m_removed_soentries() {
97 m_thread_info.valid = false;
98 UpdateExecutablePath();
99 }
100
UpdateExecutablePath()101 void DYLDRendezvous::UpdateExecutablePath() {
102 if (m_process) {
103 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
104 Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
105 if (exe_mod) {
106 m_exe_file_spec = exe_mod->GetPlatformFileSpec();
107 LLDB_LOGF(log, "DYLDRendezvous::%s exe module executable path set: '%s'",
108 __FUNCTION__, m_exe_file_spec.GetCString());
109 } else {
110 LLDB_LOGF(log,
111 "DYLDRendezvous::%s cannot cache exe module path: null "
112 "executable module pointer",
113 __FUNCTION__);
114 }
115 }
116 }
117
Resolve()118 bool DYLDRendezvous::Resolve() {
119 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
120
121 const size_t word_size = 4;
122 Rendezvous info;
123 size_t address_size;
124 size_t padding;
125 addr_t info_addr;
126 addr_t cursor;
127
128 address_size = m_process->GetAddressByteSize();
129 padding = address_size - word_size;
130 LLDB_LOGF(log,
131 "DYLDRendezvous::%s address size: %" PRIu64 ", padding %" PRIu64,
132 __FUNCTION__, uint64_t(address_size), uint64_t(padding));
133
134 if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
135 cursor = info_addr = ResolveRendezvousAddress(m_process);
136 else
137 cursor = info_addr = m_rendezvous_addr;
138 LLDB_LOGF(log, "DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__,
139 cursor);
140
141 if (cursor == LLDB_INVALID_ADDRESS)
142 return false;
143
144 if (!(cursor = ReadWord(cursor, &info.version, word_size)))
145 return false;
146
147 if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
148 return false;
149
150 if (!(cursor = ReadPointer(cursor, &info.brk)))
151 return false;
152
153 if (!(cursor = ReadWord(cursor, &info.state, word_size)))
154 return false;
155
156 if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
157 return false;
158
159 // The rendezvous was successfully read. Update our internal state.
160 m_rendezvous_addr = info_addr;
161 m_previous = m_current;
162 m_current = info;
163
164 if (m_current.map_addr == 0)
165 return false;
166
167 if (UpdateSOEntriesFromRemote())
168 return true;
169
170 return UpdateSOEntries();
171 }
172
IsValid()173 bool DYLDRendezvous::IsValid() {
174 return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
175 }
176
GetAction() const177 DYLDRendezvous::RendezvousAction DYLDRendezvous::GetAction() const {
178 switch (m_current.state) {
179
180 case eConsistent:
181 switch (m_previous.state) {
182 // When the previous and current states are consistent this is the first
183 // time we have been asked to update. Just take a snapshot of the
184 // currently loaded modules.
185 case eConsistent:
186 return eTakeSnapshot;
187 // If we are about to add or remove a shared object clear out the current
188 // state and take a snapshot of the currently loaded images.
189 case eAdd:
190 return eAddModules;
191 case eDelete:
192 return eRemoveModules;
193 }
194 break;
195
196 case eAdd:
197 case eDelete:
198 // Some versions of the android dynamic linker might send two
199 // notifications with state == eAdd back to back. Ignore them until we
200 // get an eConsistent notification.
201 if (!(m_previous.state == eConsistent ||
202 (m_previous.state == eAdd && m_current.state == eDelete)))
203 return eNoAction;
204
205 return eTakeSnapshot;
206 }
207
208 return eNoAction;
209 }
210
UpdateSOEntriesFromRemote()211 bool DYLDRendezvous::UpdateSOEntriesFromRemote() {
212 auto action = GetAction();
213
214 if (action == eNoAction)
215 return false;
216
217 if (action == eTakeSnapshot) {
218 m_added_soentries.clear();
219 m_removed_soentries.clear();
220 // We already have the loaded list from the previous update so no need to
221 // find all the modules again.
222 if (!m_loaded_modules.m_list.empty())
223 return true;
224 }
225
226 llvm::Expected<LoadedModuleInfoList> module_list =
227 m_process->GetLoadedModuleList();
228 if (!module_list) {
229 llvm::consumeError(module_list.takeError());
230 return false;
231 }
232
233 switch (action) {
234 case eTakeSnapshot:
235 m_soentries.clear();
236 return SaveSOEntriesFromRemote(*module_list);
237 case eAddModules:
238 return AddSOEntriesFromRemote(*module_list);
239 case eRemoveModules:
240 return RemoveSOEntriesFromRemote(*module_list);
241 case eNoAction:
242 return false;
243 }
244 llvm_unreachable("Fully covered switch above!");
245 }
246
UpdateSOEntries()247 bool DYLDRendezvous::UpdateSOEntries() {
248 switch (GetAction()) {
249 case eTakeSnapshot:
250 m_soentries.clear();
251 m_added_soentries.clear();
252 m_removed_soentries.clear();
253 return TakeSnapshot(m_soentries);
254 case eAddModules:
255 return AddSOEntries();
256 case eRemoveModules:
257 return RemoveSOEntries();
258 case eNoAction:
259 return false;
260 }
261 llvm_unreachable("Fully covered switch above!");
262 }
263
FillSOEntryFromModuleInfo(LoadedModuleInfoList::LoadedModuleInfo const & modInfo,SOEntry & entry)264 bool DYLDRendezvous::FillSOEntryFromModuleInfo(
265 LoadedModuleInfoList::LoadedModuleInfo const &modInfo, SOEntry &entry) {
266 addr_t link_map_addr;
267 addr_t base_addr;
268 addr_t dyn_addr;
269 std::string name;
270
271 if (!modInfo.get_link_map(link_map_addr) || !modInfo.get_base(base_addr) ||
272 !modInfo.get_dynamic(dyn_addr) || !modInfo.get_name(name))
273 return false;
274
275 entry.link_addr = link_map_addr;
276 entry.base_addr = base_addr;
277 entry.dyn_addr = dyn_addr;
278
279 entry.file_spec.SetFile(name, FileSpec::Style::native);
280
281 UpdateBaseAddrIfNecessary(entry, name);
282
283 // not needed if we're using ModuleInfos
284 entry.next = 0;
285 entry.prev = 0;
286 entry.path_addr = 0;
287
288 return true;
289 }
290
SaveSOEntriesFromRemote(const LoadedModuleInfoList & module_list)291 bool DYLDRendezvous::SaveSOEntriesFromRemote(
292 const LoadedModuleInfoList &module_list) {
293 for (auto const &modInfo : module_list.m_list) {
294 SOEntry entry;
295 if (!FillSOEntryFromModuleInfo(modInfo, entry))
296 return false;
297
298 // Only add shared libraries and not the executable.
299 if (!SOEntryIsMainExecutable(entry))
300 m_soentries.push_back(entry);
301 }
302
303 m_loaded_modules = module_list;
304 return true;
305 }
306
AddSOEntriesFromRemote(const LoadedModuleInfoList & module_list)307 bool DYLDRendezvous::AddSOEntriesFromRemote(
308 const LoadedModuleInfoList &module_list) {
309 for (auto const &modInfo : module_list.m_list) {
310 bool found = false;
311 for (auto const &existing : m_loaded_modules.m_list) {
312 if (modInfo == existing) {
313 found = true;
314 break;
315 }
316 }
317
318 if (found)
319 continue;
320
321 SOEntry entry;
322 if (!FillSOEntryFromModuleInfo(modInfo, entry))
323 return false;
324
325 // Only add shared libraries and not the executable.
326 if (!SOEntryIsMainExecutable(entry)) {
327 m_soentries.push_back(entry);
328 m_added_soentries.push_back(entry);
329 }
330 }
331
332 m_loaded_modules = module_list;
333 return true;
334 }
335
RemoveSOEntriesFromRemote(const LoadedModuleInfoList & module_list)336 bool DYLDRendezvous::RemoveSOEntriesFromRemote(
337 const LoadedModuleInfoList &module_list) {
338 for (auto const &existing : m_loaded_modules.m_list) {
339 bool found = false;
340 for (auto const &modInfo : module_list.m_list) {
341 if (modInfo == existing) {
342 found = true;
343 break;
344 }
345 }
346
347 if (found)
348 continue;
349
350 SOEntry entry;
351 if (!FillSOEntryFromModuleInfo(existing, entry))
352 return false;
353
354 // Only add shared libraries and not the executable.
355 if (!SOEntryIsMainExecutable(entry)) {
356 auto pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
357 if (pos == m_soentries.end())
358 return false;
359
360 m_soentries.erase(pos);
361 m_removed_soentries.push_back(entry);
362 }
363 }
364
365 m_loaded_modules = module_list;
366 return true;
367 }
368
AddSOEntries()369 bool DYLDRendezvous::AddSOEntries() {
370 SOEntry entry;
371 iterator pos;
372
373 assert(m_previous.state == eAdd);
374
375 if (m_current.map_addr == 0)
376 return false;
377
378 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
379 if (!ReadSOEntryFromMemory(cursor, entry))
380 return false;
381
382 // Only add shared libraries and not the executable.
383 if (SOEntryIsMainExecutable(entry))
384 continue;
385
386 pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
387 if (pos == m_soentries.end()) {
388 m_soentries.push_back(entry);
389 m_added_soentries.push_back(entry);
390 }
391 }
392
393 return true;
394 }
395
RemoveSOEntries()396 bool DYLDRendezvous::RemoveSOEntries() {
397 SOEntryList entry_list;
398 iterator pos;
399
400 assert(m_previous.state == eDelete);
401
402 if (!TakeSnapshot(entry_list))
403 return false;
404
405 for (iterator I = begin(); I != end(); ++I) {
406 pos = std::find(entry_list.begin(), entry_list.end(), *I);
407 if (pos == entry_list.end())
408 m_removed_soentries.push_back(*I);
409 }
410
411 m_soentries = entry_list;
412 return true;
413 }
414
SOEntryIsMainExecutable(const SOEntry & entry)415 bool DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry) {
416 // On some systes the executable is indicated by an empty path in the entry.
417 // On others it is the full path to the executable.
418
419 auto triple = m_process->GetTarget().GetArchitecture().GetTriple();
420 switch (triple.getOS()) {
421 case llvm::Triple::FreeBSD:
422 case llvm::Triple::NetBSD:
423 return entry.file_spec == m_exe_file_spec;
424 case llvm::Triple::Linux:
425 if (triple.isAndroid())
426 return entry.file_spec == m_exe_file_spec;
427 return !entry.file_spec;
428 default:
429 return false;
430 }
431 }
432
TakeSnapshot(SOEntryList & entry_list)433 bool DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) {
434 SOEntry entry;
435
436 if (m_current.map_addr == 0)
437 return false;
438
439 // Clear previous entries since we are about to obtain an up to date list.
440 entry_list.clear();
441
442 for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) {
443 if (!ReadSOEntryFromMemory(cursor, entry))
444 return false;
445
446 // Only add shared libraries and not the executable.
447 if (SOEntryIsMainExecutable(entry))
448 continue;
449
450 entry_list.push_back(entry);
451 }
452
453 return true;
454 }
455
ReadWord(addr_t addr,uint64_t * dst,size_t size)456 addr_t DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size) {
457 Status error;
458
459 *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
460 if (error.Fail())
461 return 0;
462
463 return addr + size;
464 }
465
ReadPointer(addr_t addr,addr_t * dst)466 addr_t DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst) {
467 Status error;
468
469 *dst = m_process->ReadPointerFromMemory(addr, error);
470 if (error.Fail())
471 return 0;
472
473 return addr + m_process->GetAddressByteSize();
474 }
475
ReadStringFromMemory(addr_t addr)476 std::string DYLDRendezvous::ReadStringFromMemory(addr_t addr) {
477 std::string str;
478 Status error;
479
480 if (addr == LLDB_INVALID_ADDRESS)
481 return std::string();
482
483 m_process->ReadCStringFromMemory(addr, str, error);
484
485 return str;
486 }
487
488 // Returns true if the load bias reported by the linker is incorrect for the
489 // given entry. This function is used to handle cases where we want to work
490 // around a bug in the system linker.
isLoadBiasIncorrect(Target & target,const std::string & file_path)491 static bool isLoadBiasIncorrect(Target &target, const std::string &file_path) {
492 // On Android L (API 21, 22) the load address of the "/system/bin/linker"
493 // isn't filled in correctly.
494 unsigned os_major = target.GetPlatform()->GetOSVersion().getMajor();
495 return target.GetArchitecture().GetTriple().isAndroid() &&
496 (os_major == 21 || os_major == 22) &&
497 (file_path == "/system/bin/linker" ||
498 file_path == "/system/bin/linker64");
499 }
500
UpdateBaseAddrIfNecessary(SOEntry & entry,std::string const & file_path)501 void DYLDRendezvous::UpdateBaseAddrIfNecessary(SOEntry &entry,
502 std::string const &file_path) {
503 // If the load bias reported by the linker is incorrect then fetch the load
504 // address of the file from the proc file system.
505 if (isLoadBiasIncorrect(m_process->GetTarget(), file_path)) {
506 lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
507 bool is_loaded = false;
508 Status error =
509 m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr);
510 if (error.Success() && is_loaded)
511 entry.base_addr = load_addr;
512 }
513 }
514
ReadSOEntryFromMemory(lldb::addr_t addr,SOEntry & entry)515 bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) {
516 entry.clear();
517
518 entry.link_addr = addr;
519
520 if (!(addr = ReadPointer(addr, &entry.base_addr)))
521 return false;
522
523 // mips adds an extra load offset field to the link map struct on FreeBSD and
524 // NetBSD (need to validate other OSes).
525 // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57
526 const ArchSpec &arch = m_process->GetTarget().GetArchitecture();
527 if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD ||
528 arch.GetTriple().getOS() == llvm::Triple::NetBSD) &&
529 arch.IsMIPS()) {
530 addr_t mips_l_offs;
531 if (!(addr = ReadPointer(addr, &mips_l_offs)))
532 return false;
533 if (mips_l_offs != 0 && mips_l_offs != entry.base_addr)
534 return false;
535 }
536
537 if (!(addr = ReadPointer(addr, &entry.path_addr)))
538 return false;
539
540 if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
541 return false;
542
543 if (!(addr = ReadPointer(addr, &entry.next)))
544 return false;
545
546 if (!(addr = ReadPointer(addr, &entry.prev)))
547 return false;
548
549 std::string file_path = ReadStringFromMemory(entry.path_addr);
550 entry.file_spec.SetFile(file_path, FileSpec::Style::native);
551
552 UpdateBaseAddrIfNecessary(entry, file_path);
553
554 return true;
555 }
556
FindMetadata(const char * name,PThreadField field,uint32_t & value)557 bool DYLDRendezvous::FindMetadata(const char *name, PThreadField field,
558 uint32_t &value) {
559 Target &target = m_process->GetTarget();
560
561 SymbolContextList list;
562 target.GetImages().FindSymbolsWithNameAndType(ConstString(name),
563 eSymbolTypeAny, list);
564 if (list.IsEmpty())
565 return false;
566
567 Address address = list[0].symbol->GetAddress();
568 addr_t addr = address.GetLoadAddress(&target);
569 if (addr == LLDB_INVALID_ADDRESS)
570 return false;
571
572 Status error;
573 value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(
574 addr + field * sizeof(uint32_t), sizeof(uint32_t), 0, error);
575 if (error.Fail())
576 return false;
577
578 if (field == eSize)
579 value /= 8; // convert bits to bytes
580
581 return true;
582 }
583
GetThreadInfo()584 const DYLDRendezvous::ThreadInfo &DYLDRendezvous::GetThreadInfo() {
585 if (!m_thread_info.valid) {
586 bool ok = true;
587
588 ok &= FindMetadata("_thread_db_pthread_dtvp", eOffset,
589 m_thread_info.dtv_offset);
590 ok &=
591 FindMetadata("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
592 ok &= FindMetadata("_thread_db_link_map_l_tls_modid", eOffset,
593 m_thread_info.modid_offset);
594 ok &= FindMetadata("_thread_db_dtv_t_pointer_val", eOffset,
595 m_thread_info.tls_offset);
596
597 if (ok)
598 m_thread_info.valid = true;
599 }
600
601 return m_thread_info;
602 }
603
DumpToLog(Log * log) const604 void DYLDRendezvous::DumpToLog(Log *log) const {
605 int state = GetState();
606
607 if (!log)
608 return;
609
610 log->PutCString("DYLDRendezvous:");
611 LLDB_LOGF(log, " Address: %" PRIx64, GetRendezvousAddress());
612 LLDB_LOGF(log, " Version: %" PRIu64, GetVersion());
613 LLDB_LOGF(log, " Link : %" PRIx64, GetLinkMapAddress());
614 LLDB_LOGF(log, " Break : %" PRIx64, GetBreakAddress());
615 LLDB_LOGF(log, " LDBase : %" PRIx64, GetLDBase());
616 LLDB_LOGF(log, " State : %s",
617 (state == eConsistent)
618 ? "consistent"
619 : (state == eAdd) ? "add"
620 : (state == eDelete) ? "delete" : "unknown");
621
622 iterator I = begin();
623 iterator E = end();
624
625 if (I != E)
626 log->PutCString("DYLDRendezvous SOEntries:");
627
628 for (int i = 1; I != E; ++I, ++i) {
629 LLDB_LOGF(log, "\n SOEntry [%d] %s", i, I->file_spec.GetCString());
630 LLDB_LOGF(log, " Base : %" PRIx64, I->base_addr);
631 LLDB_LOGF(log, " Path : %" PRIx64, I->path_addr);
632 LLDB_LOGF(log, " Dyn : %" PRIx64, I->dyn_addr);
633 LLDB_LOGF(log, " Next : %" PRIx64, I->next);
634 LLDB_LOGF(log, " Prev : %" PRIx64, I->prev);
635 }
636 }
637