]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / llvm / tools / lldb / 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 // 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/Symbol.h"
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Target.h"
20
21 #include "DYLDRendezvous.h"
22
23 using namespace lldb;
24 using namespace lldb_private;
25
26 /// Locates the address of the rendezvous structure.  Returns the address on
27 /// success and LLDB_INVALID_ADDRESS on failure.
28 static addr_t
29 ResolveRendezvousAddress(Process *process)
30 {
31     addr_t info_location;
32     addr_t info_addr;
33     Error error;
34
35     info_location = process->GetImageInfoAddress();
36
37     if (info_location == LLDB_INVALID_ADDRESS)
38         return LLDB_INVALID_ADDRESS;
39
40     info_addr = process->ReadPointerFromMemory(info_location, error);
41     if (error.Fail())
42         return LLDB_INVALID_ADDRESS;
43
44     if (info_addr == 0)
45         return LLDB_INVALID_ADDRESS;
46
47     return info_addr;
48 }
49
50 DYLDRendezvous::DYLDRendezvous(Process *process)
51     : m_process(process),
52       m_rendezvous_addr(LLDB_INVALID_ADDRESS),
53       m_current(),
54       m_previous(),
55       m_soentries(),
56       m_added_soentries(),
57       m_removed_soentries()
58 {
59     m_thread_info.valid = false;
60
61     // Cache a copy of the executable path
62     if (m_process)
63     {
64         Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
65         if (exe_mod)
66             exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
67     }
68 }
69
70 bool
71 DYLDRendezvous::Resolve()
72 {
73     const size_t word_size = 4;
74     Rendezvous info;
75     size_t address_size;
76     size_t padding;
77     addr_t info_addr;
78     addr_t cursor;
79
80     address_size = m_process->GetAddressByteSize();
81     padding = address_size - word_size;
82
83     if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
84         cursor = info_addr = ResolveRendezvousAddress(m_process);
85     else
86         cursor = info_addr = m_rendezvous_addr;
87     
88     if (cursor == LLDB_INVALID_ADDRESS)
89         return false;
90
91     if (!(cursor = ReadWord(cursor, &info.version, word_size)))
92         return false;
93
94     if (!(cursor = ReadPointer(cursor + padding, &info.map_addr)))
95         return false;
96
97     if (!(cursor = ReadPointer(cursor, &info.brk)))
98         return false;
99
100     if (!(cursor = ReadWord(cursor, &info.state, word_size)))
101         return false;
102
103     if (!(cursor = ReadPointer(cursor + padding, &info.ldbase)))
104         return false;
105
106     // The rendezvous was successfully read.  Update our internal state.
107     m_rendezvous_addr = info_addr;
108     m_previous = m_current;
109     m_current = info;
110
111     return UpdateSOEntries();
112 }
113
114 bool
115 DYLDRendezvous::IsValid()
116 {
117     return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
118 }
119
120 bool
121 DYLDRendezvous::UpdateSOEntries()
122 {
123     SOEntry entry;
124
125     if (m_current.map_addr == 0)
126         return false;
127
128     // When the previous and current states are consistent this is the first
129     // time we have been asked to update.  Just take a snapshot of the currently
130     // loaded modules.
131     if (m_previous.state == eConsistent && m_current.state == eConsistent) 
132         return TakeSnapshot(m_soentries);
133
134     // If we are about to add or remove a shared object clear out the current
135     // state and take a snapshot of the currently loaded images.
136     if (m_current.state == eAdd || m_current.state == eDelete)
137     {
138         assert(m_previous.state == eConsistent);
139         m_soentries.clear();
140         m_added_soentries.clear();
141         m_removed_soentries.clear();
142         return TakeSnapshot(m_soentries);
143     }
144     assert(m_current.state == eConsistent);
145
146     // Otherwise check the previous state to determine what to expect and update
147     // accordingly.
148     if (m_previous.state == eAdd)
149         return UpdateSOEntriesForAddition();
150     else if (m_previous.state == eDelete)
151         return UpdateSOEntriesForDeletion();
152
153     return false;
154 }
155  
156 bool
157 DYLDRendezvous::UpdateSOEntriesForAddition()
158 {
159     SOEntry entry;
160     iterator pos;
161
162     assert(m_previous.state == eAdd);
163
164     if (m_current.map_addr == 0)
165         return false;
166
167     for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
168     {
169         if (!ReadSOEntryFromMemory(cursor, entry))
170             return false;
171
172         // Only add shared libraries and not the executable.
173         // On Linux this is indicated by an empty path in the entry.
174         // On FreeBSD it is the name of the executable.
175         if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
176             continue;
177
178         pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
179         if (pos == m_soentries.end())
180         {
181             m_soentries.push_back(entry);
182             m_added_soentries.push_back(entry);
183         }
184     }
185
186     return true;
187 }
188
189 bool
190 DYLDRendezvous::UpdateSOEntriesForDeletion()
191 {
192     SOEntryList entry_list;
193     iterator pos;
194
195     assert(m_previous.state == eDelete);
196
197     if (!TakeSnapshot(entry_list))
198         return false;
199
200     for (iterator I = begin(); I != end(); ++I)
201     {
202         pos = std::find(entry_list.begin(), entry_list.end(), *I);
203         if (pos == entry_list.end())
204             m_removed_soentries.push_back(*I);
205     }
206
207     m_soentries = entry_list;
208     return true;
209 }
210
211 bool
212 DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list)
213 {
214     SOEntry entry;
215
216     if (m_current.map_addr == 0)
217         return false;
218
219     for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
220     {
221         if (!ReadSOEntryFromMemory(cursor, entry))
222             return false;
223
224         // Only add shared libraries and not the executable.
225         // On Linux this is indicated by an empty path in the entry.
226         // On FreeBSD it is the name of the executable.
227         if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
228             continue;
229
230         entry_list.push_back(entry);
231     }
232
233     return true;
234 }
235
236 addr_t
237 DYLDRendezvous::ReadWord(addr_t addr, uint64_t *dst, size_t size)
238 {
239     Error error;
240
241     *dst = m_process->ReadUnsignedIntegerFromMemory(addr, size, 0, error);
242     if (error.Fail())
243         return 0;
244
245     return addr + size;
246 }
247
248 addr_t
249 DYLDRendezvous::ReadPointer(addr_t addr, addr_t *dst)
250 {
251     Error error;
252  
253     *dst = m_process->ReadPointerFromMemory(addr, error);
254     if (error.Fail())
255         return 0;
256
257     return addr + m_process->GetAddressByteSize();
258 }
259
260 std::string
261 DYLDRendezvous::ReadStringFromMemory(addr_t addr)
262 {
263     std::string str;
264     Error error;
265     size_t size;
266     char c;
267
268     if (addr == LLDB_INVALID_ADDRESS)
269         return std::string();
270
271     for (;;) {
272         size = m_process->DoReadMemory(addr, &c, 1, error);
273         if (size != 1 || error.Fail())
274             return std::string();
275         if (c == 0)
276             break;
277         else {
278             str.push_back(c);
279             addr++;
280         }
281     }
282
283     return str;
284 }
285
286 bool
287 DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
288 {
289     entry.clear();
290
291     entry.link_addr = addr;
292     
293     if (!(addr = ReadPointer(addr, &entry.base_addr)))
294         return false;
295
296     // mips adds an extra load offset field to the link map struct on
297     // FreeBSD and NetBSD (need to validate other OSes).
298     // http://svnweb.freebsd.org/base/head/sys/sys/link_elf.h?revision=217153&view=markup#l57
299     const ArchSpec &arch = m_process->GetTarget().GetArchitecture();
300     if (arch.GetCore() == ArchSpec::eCore_mips64)
301     {
302         assert (arch.GetTriple().getOS() == llvm::Triple::FreeBSD ||
303                 arch.GetTriple().getOS() == llvm::Triple::NetBSD);
304         addr_t mips_l_offs;
305         if (!(addr = ReadPointer(addr, &mips_l_offs)))
306             return false;
307         if (mips_l_offs != 0 && mips_l_offs != entry.base_addr)
308             return false;
309     }
310     
311     if (!(addr = ReadPointer(addr, &entry.path_addr)))
312         return false;
313     
314     if (!(addr = ReadPointer(addr, &entry.dyn_addr)))
315         return false;
316     
317     if (!(addr = ReadPointer(addr, &entry.next)))
318         return false;
319     
320     if (!(addr = ReadPointer(addr, &entry.prev)))
321         return false;
322     
323     entry.path = ReadStringFromMemory(entry.path_addr);
324     
325     return true;
326 }
327
328
329 bool
330 DYLDRendezvous::FindMetadata(const char *name, PThreadField field, uint32_t& value)
331 {
332     Target& target = m_process->GetTarget();
333
334     SymbolContextList list;
335     if (!target.GetImages().FindSymbolsWithNameAndType (ConstString(name), eSymbolTypeAny, list))
336         return false;
337
338     Address address = list[0].symbol->GetAddress();
339     addr_t addr = address.GetLoadAddress (&target);
340     if (addr == LLDB_INVALID_ADDRESS)
341         return false;
342
343     Error error;
344     value = (uint32_t)m_process->ReadUnsignedIntegerFromMemory(addr + field*sizeof(uint32_t), sizeof(uint32_t), 0, error);
345     if (error.Fail())
346         return false;
347
348     if (field == eSize)
349         value /= 8; // convert bits to bytes
350
351     return true;
352 }
353
354 const DYLDRendezvous::ThreadInfo&
355 DYLDRendezvous::GetThreadInfo()
356 {
357     if (!m_thread_info.valid)
358     {
359         bool ok = true;
360
361         ok &= FindMetadata ("_thread_db_pthread_dtvp", eOffset, m_thread_info.dtv_offset);
362         ok &= FindMetadata ("_thread_db_dtv_dtv", eSize, m_thread_info.dtv_slot_size);
363         ok &= FindMetadata ("_thread_db_link_map_l_tls_modid", eOffset, m_thread_info.modid_offset);
364         ok &= FindMetadata ("_thread_db_dtv_t_pointer_val", eOffset, m_thread_info.tls_offset);
365
366         if (ok)
367             m_thread_info.valid = true;
368     }
369
370     return m_thread_info;
371 }
372
373 void
374 DYLDRendezvous::DumpToLog(Log *log) const
375 {
376     int state = GetState();
377
378     if (!log)
379         return;
380
381     log->PutCString("DYLDRendezvous:");
382     log->Printf("   Address: %" PRIx64, GetRendezvousAddress());
383     log->Printf("   Version: %" PRIu64, GetVersion());
384     log->Printf("   Link   : %" PRIx64, GetLinkMapAddress());
385     log->Printf("   Break  : %" PRIx64, GetBreakAddress());
386     log->Printf("   LDBase : %" PRIx64, GetLDBase());
387     log->Printf("   State  : %s", 
388                 (state == eConsistent) ? "consistent" :
389                 (state == eAdd)        ? "add"        :
390                 (state == eDelete)     ? "delete"     : "unknown");
391     
392     iterator I = begin();
393     iterator E = end();
394
395     if (I != E) 
396         log->PutCString("DYLDRendezvous SOEntries:");
397     
398     for (int i = 1; I != E; ++I, ++i) 
399     {
400         log->Printf("\n   SOEntry [%d] %s", i, I->path.c_str());
401         log->Printf("      Base : %" PRIx64, I->base_addr);
402         log->Printf("      Path : %" PRIx64, I->path_addr);
403         log->Printf("      Dyn  : %" PRIx64, I->dyn_addr);
404         log->Printf("      Next : %" PRIx64, I->next);
405         log->Printf("      Prev : %" PRIx64, I->prev);
406     }
407 }