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