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