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