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