blob: 61f9b3d441ce402fede0013e4effbeabcafa93a9 [file] [log] [blame]
Deepak Panickalca238a72014-07-21 17:19:12 +00001//===-- 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"
Zachary Turner32abc6e2015-03-03 19:23:09 +000018#include "lldb/Symbol/SymbolContext.h"
Deepak Panickalca238a72014-07-21 17:19:12 +000019#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
28using namespace lldb;
29using namespace lldb_private;
30
31/// Locates the address of the rendezvous structure. Returns the address on
32/// success and LLDB_INVALID_ADDRESS on failure.
33static addr_t
34ResolveRendezvousAddress(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
55HexagonDYLDRendezvous::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
75bool
76HexagonDYLDRendezvous::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
119void
120HexagonDYLDRendezvous::SetRendezvousAddress( lldb::addr_t addr )
121{
122 m_rendezvous_addr = addr;
123}
124
125bool
126HexagonDYLDRendezvous::IsValid()
127{
128 return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
129}
130
131bool
132HexagonDYLDRendezvous::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
170bool
171HexagonDYLDRendezvous::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
203bool
204HexagonDYLDRendezvous::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
225bool
226HexagonDYLDRendezvous::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
250addr_t
251HexagonDYLDRendezvous::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
262addr_t
263HexagonDYLDRendezvous::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
274std::string
275HexagonDYLDRendezvous::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
300bool
301HexagonDYLDRendezvous::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
326bool
327HexagonDYLDRendezvous::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
Greg Clayton6f997132015-06-25 22:20:02 +0000335 Address address = list[0].symbol->GetAddress();
Deepak Panickalca238a72014-07-21 17:19:12 +0000336 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
351const HexagonDYLDRendezvous::ThreadInfo&
352HexagonDYLDRendezvous::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
370void
371HexagonDYLDRendezvous::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}