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