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.
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 
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 
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 
172 bool DYLDRendezvous::IsValid() {
173   return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
174 }
175 
176 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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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.
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 
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 
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 
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 
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 
603 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