xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp (revision 32a95656b51ebefcdf3e0b02c110825f59abd26f)
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   m_thread_info.valid = false;
98   UpdateExecutablePath();
99 }
100 
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 
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 
173 bool DYLDRendezvous::IsValid() {
174   return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
175 }
176 
177 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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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.
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 
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 
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 
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 
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 
604 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