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