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/Process.h"
21 #include "lldb/Target/Target.h"
22 
23 #include "llvm/Support/Path.h"
24 
25 #include "DYLDRendezvous.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 
30 /// Locates the address of the rendezvous structure.  Returns the address on
31 /// success and LLDB_INVALID_ADDRESS on failure.
32 static addr_t
33 ResolveRendezvousAddress(Process *process)
34 {
35     Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
36     addr_t info_location;
37     addr_t info_addr;
38     Error error;
39 
40     if (!process)
41     {
42         if (log)
43             log->Printf ("%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 = process->GetImageInfoAddress();
50     if (log)
51         log->Printf ("%s info_location = 0x%" PRIx64, __FUNCTION__, info_location);
52 
53     // If the process fails to return an address, fall back to seeing if the local object file can help us find it.
54     if (info_location == LLDB_INVALID_ADDRESS)
55     {
56         Target *target = &process->GetTarget();
57         if (target)
58         {
59             ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
60             Address addr = obj_file->GetImageInfoAddress(target);
61 
62             if (addr.IsValid())
63             {
64                 info_location = addr.GetLoadAddress(target);
65                 if (log)
66                     log->Printf ("%s resolved via direct object file approach to 0x%" PRIx64, __FUNCTION__, info_location);
67             }
68             else
69             {
70                 if (log)
71                     log->Printf ("%s FAILED - direct object file approach did not yield a valid address", __FUNCTION__);
72             }
73         }
74     }
75 
76     if (info_location == LLDB_INVALID_ADDRESS)
77     {
78         if (log)
79             log->Printf ("%s FAILED - invalid info address", __FUNCTION__);
80         return LLDB_INVALID_ADDRESS;
81     }
82 
83     if (log)
84         log->Printf ("%s reading pointer (%" PRIu32 " bytes) from 0x%" PRIx64, __FUNCTION__, process->GetAddressByteSize(), info_location);
85 
86     info_addr = process->ReadPointerFromMemory(info_location, error);
87     if (error.Fail())
88     {
89         if (log)
90             log->Printf ("%s FAILED - could not read from the info location: %s", __FUNCTION__, error.AsCString ());
91         return LLDB_INVALID_ADDRESS;
92     }
93 
94     if (info_addr == 0)
95     {
96         if (log)
97             log->Printf ("%s FAILED - the rendezvous address contained at 0x%" PRIx64 " returned a null value", __FUNCTION__, info_location);
98         return LLDB_INVALID_ADDRESS;
99     }
100 
101     return info_addr;
102 }
103 
104 DYLDRendezvous::DYLDRendezvous(Process *process)
105     : m_process(process),
106       m_rendezvous_addr(LLDB_INVALID_ADDRESS),
107       m_current(),
108       m_previous(),
109       m_soentries(),
110       m_added_soentries(),
111       m_removed_soentries()
112 {
113     Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
114 
115     m_thread_info.valid = false;
116 
117     // Cache a copy of the executable path
118     if (m_process)
119     {
120         Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
121         if (exe_mod)
122         {
123             m_exe_file_spec = exe_mod->GetPlatformFileSpec();
124             if (log)
125                 log->Printf ("DYLDRendezvous::%s exe module executable path set: '%s'",
126                         __FUNCTION__, m_exe_file_spec.GetCString());
127         }
128         else
129         {
130             if (log)
131                 log->Printf ("DYLDRendezvous::%s cannot cache exe module path: null executable module pointer", __FUNCTION__);
132         }
133     }
134 }
135 
136 bool
137 DYLDRendezvous::Resolve()
138 {
139     Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
140 
141     const size_t word_size = 4;
142     Rendezvous info;
143     size_t address_size;
144     size_t padding;
145     addr_t info_addr;
146     addr_t cursor;
147 
148     address_size = m_process->GetAddressByteSize();
149     padding = address_size - word_size;
150     if (log)
151         log->Printf ("DYLDRendezvous::%s address size: %" PRIu64 ", padding %" PRIu64, __FUNCTION__, uint64_t(address_size), uint64_t(padding));
152 
153     if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
154         cursor = info_addr = ResolveRendezvousAddress(m_process);
155     else
156         cursor = info_addr = m_rendezvous_addr;
157     if (log)
158         log->Printf ("DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__, cursor);
159 
160     if (cursor == LLDB_INVALID_ADDRESS)
161         return false;
162 
163     if (!(cursor = ReadWord(cursor, &info.version, word_size)))
164         return false;
165 
166     if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
167         return false;
168 
169     if (!(cursor = ReadPointer(cursor, &info.brk)))
170         return false;
171 
172     if (!(cursor = ReadWord(cursor, &info.state, word_size)))
173         return false;
174 
175     if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
176         return false;
177 
178     // The rendezvous was successfully read.  Update our internal state.
179     m_rendezvous_addr = info_addr;
180     m_previous = m_current;
181     m_current = info;
182 
183     return UpdateSOEntries();
184 }
185 
186 bool
187 DYLDRendezvous::IsValid()
188 {
189     return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
190 }
191 
192 bool
193 DYLDRendezvous::UpdateSOEntries()
194 {
195     SOEntry entry;
196 
197     if (m_current.map_addr == 0)
198         return false;
199 
200     // When the previous and current states are consistent this is the first
201     // time we have been asked to update.  Just take a snapshot of the currently
202     // loaded modules.
203     if (m_previous.state == eConsistent && m_current.state == eConsistent)
204         return TakeSnapshot(m_soentries);
205 
206     // If we are about to add or remove a shared object clear out the current
207     // state and take a snapshot of the currently loaded images.
208     if (m_current.state == eAdd || m_current.state == eDelete)
209     {
210         // Some versions of the android dynamic linker might send two
211         // notifications with state == eAdd back to back. Ignore them
212         // until we get an eConsistent notification.
213         if (!(m_previous.state == eConsistent || (m_previous.state == eAdd && m_current.state == eDelete)))
214             return false;
215 
216         m_soentries.clear();
217         m_added_soentries.clear();
218         m_removed_soentries.clear();
219         return TakeSnapshot(m_soentries);
220     }
221     assert(m_current.state == eConsistent);
222 
223     // Otherwise check the previous state to determine what to expect and update
224     // accordingly.
225     if (m_previous.state == eAdd)
226         return UpdateSOEntriesForAddition();
227     else if (m_previous.state == eDelete)
228         return UpdateSOEntriesForDeletion();
229 
230     return false;
231 }
232 
233 bool
234 DYLDRendezvous::UpdateSOEntriesForAddition()
235 {
236     SOEntry entry;
237     iterator pos;
238 
239     assert(m_previous.state == eAdd);
240 
241     if (m_current.map_addr == 0)
242         return false;
243 
244     for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
245     {
246         if (!ReadSOEntryFromMemory(cursor, entry))
247             return false;
248 
249         // Only add shared libraries and not the executable.
250         if (SOEntryIsMainExecutable(entry))
251             continue;
252 
253         pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
254         if (pos == m_soentries.end())
255         {
256             m_soentries.push_back(entry);
257             m_added_soentries.push_back(entry);
258         }
259     }
260 
261     return true;
262 }
263 
264 bool
265 DYLDRendezvous::UpdateSOEntriesForDeletion()
266 {
267     SOEntryList entry_list;
268     iterator pos;
269 
270     assert(m_previous.state == eDelete);
271 
272     if (!TakeSnapshot(entry_list))
273         return false;
274 
275     for (iterator I = begin(); I != end(); ++I)
276     {
277         pos = std::find(entry_list.begin(), entry_list.end(), *I);
278         if (pos == entry_list.end())
279             m_removed_soentries.push_back(*I);
280     }
281 
282     m_soentries = entry_list;
283     return true;
284 }
285 
286 bool
287 DYLDRendezvous::SOEntryIsMainExecutable(const SOEntry &entry)
288 {
289     // On Linux the executable is indicated by an empty path in the entry. On
290     // FreeBSD and on Android it is the full path to the executable.
291 
292     auto triple = m_process->GetTarget().GetArchitecture().GetTriple();
293     auto os_type = triple.getOS();
294     auto env_type = triple.getEnvironment();
295 
296     switch (os_type) {
297         case llvm::Triple::FreeBSD:
298             return entry.file_spec == m_exe_file_spec;
299         case llvm::Triple::Linux:
300             switch (env_type) {
301                 case llvm::Triple::Android:
302                     return entry.file_spec == m_exe_file_spec;
303                 default:
304                     return !entry.file_spec;
305             }
306         default:
307             return false;
308     }
309 }
310 
311 bool
312 DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list)
313 {
314     SOEntry entry;
315 
316     if (m_current.map_addr == 0)
317         return false;
318 
319     // Clear previous entries since we are about to obtain an up to date list.
320     entry_list.clear();
321 
322     for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
323     {
324         if (!ReadSOEntryFromMemory(cursor, entry))
325             return false;
326 
327         // Only add shared libraries and not the executable.
328         if (SOEntryIsMainExecutable(entry))
329             continue;
330 
331         entry_list.push_back(entry);
332     }
333 
334     return true;
335 }
336 
337 addr_t
338 DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size)
339 {
340     Error error;
341 
342     *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
343     if (error.Fail())
344         return 0;
345 
346     return addr + size;
347 }
348 
349 addr_t
350 DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst)
351 {
352     Error error;
353 
354     *dst = m_process->ReadPointerFromMemory(addr, error);
355     if (error.Fail())
356         return 0;
357 
358     return addr + m_process->GetAddressByteSize();
359 }
360 
361 std::string
362 DYLDRendezvous::ReadStringFromMemory(addr_t addr)
363 {
364     std::string str;
365     Error error;
366 
367     if (addr == LLDB_INVALID_ADDRESS)
368         return std::string();
369 
370     m_process->ReadCStringFromMemory(addr, str, error);
371 
372     return str;
373 }
374 
375 bool
376 DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
377 {
378     entry.clear();
379 
380     entry.link_addr = addr;
381 
382     if (!(addr = ReadPointer(addr, &entry.base_addr)))
383         return false;
384 
385     // mips adds an extra load offset field to the link map struct on
386     // FreeBSD and NetBSD (need to validate other OSes).
387     // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57
388     const ArchSpec &arch = m_process->GetTarget().GetArchitecture();
389     if ((arch.GetTriple().getOS() == llvm::Triple::FreeBSD
390         || arch.GetTriple().getOS() == llvm::Triple::NetBSD) &&
391         (arch.GetMachine() == llvm::Triple::mips || arch.GetMachine() == llvm::Triple::mipsel
392         || arch.GetMachine() == llvm::Triple::mips64 || arch.GetMachine() == llvm::Triple::mips64el))
393     {
394         addr_t mips_l_offs;
395         if (!(addr = ReadPointer(addr, &mips_l_offs)))
396             return false;
397         if (mips_l_offs != 0 && mips_l_offs != entry.base_addr)
398             return false;
399     }
400 
401     if (!(addr = ReadPointer(addr, &entry.path_addr)))
402         return false;
403 
404     if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
405         return false;
406 
407     if (!(addr = ReadPointer(addr, &entry.next)))
408         return false;
409 
410     if (!(addr = ReadPointer(addr, &entry.prev)))
411         return false;
412 
413     std::string file_path = ReadStringFromMemory(entry.path_addr);
414     entry.file_spec.SetFile(file_path, false);
415 
416     // On Android L (5.0, 5.1) the load address of the "/system/bin/linker" isn't filled in
417     // correctly. To get the correct load address we fetch the load address of the file from the
418     // proc file system.
419     if (arch.GetTriple().getEnvironment() == llvm::Triple::Android && entry.base_addr == 0 &&
420         (file_path == "/system/bin/linker" || file_path == "/system/bin/linker64"))
421     {
422         lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
423         bool is_loaded = false;
424         Error error = m_process->GetFileLoadAddress(entry.file_spec, is_loaded, load_addr);
425         if (error.Success() && is_loaded)
426             entry.base_addr = load_addr;
427     }
428 
429     return true;
430 }
431 
432 
433 bool
434 DYLDRendezvous::FindMetadata(const char *name, PThreadField field, uint32_t& value)
435 {
436     Target& target = m_process->GetTarget();
437 
438     SymbolContextList list;
439     if (!target.GetImages().FindSymbolsWithNameAndType (ConstString(name), eSymbolTypeAny, list))
440         return false;
441 
442     Address address = list[0].symbol->GetAddress();
443     addr_t addr = address.GetLoadAddress (&target);
444     if (addr == LLDB_INVALID_ADDRESS)
445         return false;
446 
447     Error error;
448     value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(addr + field*sizeof(uint32_t), sizeof(uint32_t), 0, error);
449     if (error.Fail())
450         return false;
451 
452     if (field == eSize)
453         value /= 8; // convert bits to bytes
454 
455     return true;
456 }
457 
458 const DYLDRendezvous::ThreadInfo&
459 DYLDRendezvous::GetThreadInfo()
460 {
461     if (!m_thread_info.valid)
462     {
463         bool ok = true;
464 
465         ok &= FindMetadata ("_thread_db_pthread_dtvp", eOffset, m_thread_info.dtv_offset);
466         ok &= FindMetadata ("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
467         ok &= FindMetadata ("_thread_db_link_map_l_tls_modid", eOffset, m_thread_info.modid_offset);
468         ok &= FindMetadata ("_thread_db_dtv_t_pointer_val", eOffset, m_thread_info.tls_offset);
469 
470         if (ok)
471             m_thread_info.valid = true;
472     }
473 
474     return m_thread_info;
475 }
476 
477 void
478 DYLDRendezvous::DumpToLog(Log *log) const
479 {
480     int state = GetState();
481 
482     if (!log)
483         return;
484 
485     log->PutCString("DYLDRendezvous:");
486     log->Printf("   Address: %" PRIx64, GetRendezvousAddress());
487     log->Printf("   Version: %" PRIu64, GetVersion());
488     log->Printf("   Link   : %" PRIx64, GetLinkMapAddress());
489     log->Printf("   Break  : %" PRIx64, GetBreakAddress());
490     log->Printf("   LDBase : %" PRIx64, GetLDBase());
491     log->Printf("   State  : %s",
492                 (state == eConsistent) ? "consistent" :
493                 (state == eAdd)        ? "add"        :
494                 (state == eDelete)     ? "delete"     : "unknown");
495 
496     iterator I = begin();
497     iterator E = end();
498 
499     if (I != E)
500         log->PutCString("DYLDRendezvous SOEntries:");
501 
502     for (int i = 1; I != E; ++I, ++i)
503     {
504         log->Printf("\n   SOEntry [%d] %s", i, I->file_spec.GetCString());
505         log->Printf("      Base : %" PRIx64, I->base_addr);
506         log->Printf("      Path : %" PRIx64, I->path_addr);
507         log->Printf("      Dyn  : %" PRIx64, I->dyn_addr);
508         log->Printf("      Next : %" PRIx64, I->next);
509         log->Printf("      Prev : %" PRIx64, I->prev);
510     }
511 }
512