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