1 //===------------------------- AddressSpace.hpp ---------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //
9 // Abstracts accessing local vs remote address spaces.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef __ADDRESSSPACE_HPP__
14 #define __ADDRESSSPACE_HPP__
15
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #if !_LIBUNWIND_IS_BAREMETAL
22 #include <dlfcn.h>
23 #if defined(__ANDROID__) && !__LP64__
24 // dladdr only exits in API >= 8. Call to our my_dladdr in android/support for dynamic lookup
25 #if __ANDROID_API__ < 8
26 typedef struct {
27 const char *dli_fname; /* Pathname of shared object that contains address */
28 void *dli_fbase; /* Address at which shared object is loaded */
29 const char *dli_sname; /* Name of nearest symbol with address lower than addr */
30 void *dli_saddr; /* Exact address of symbol named in dli_sname */
31 } Dl_info;
32 #endif // __ANDROID_API__ >= 8
33 extern "C" int my_dladdr(const void* addr, Dl_info *info);
34 #define dladdr my_dladdr
35 #endif
36 #endif
37
38 #if __APPLE__
39 #include <mach-o/getsect.h>
40 namespace libunwind {
41 bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
42 }
43 #endif
44
45 #include "libunwind.h"
46 #include "config.h"
47 #include "dwarf2.h"
48 #include "Registers.hpp"
49
50 #if LIBCXXABI_ARM_EHABI
51 #if __LINUX__
52 // Emulate the BSD dl_unwind_find_exidx API when on a GNU libdl system.
53 typedef long unsigned int *_Unwind_Ptr;
54 extern "C" _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr targetAddr, int *length);
55 _Unwind_Ptr (*dl_unwind_find_exidx)(_Unwind_Ptr targetAddr, int *length) =
56 __gnu_Unwind_Find_exidx;
57 #else
58 #include <link.h>
59 #endif
60 #endif // LIBCXXABI_ARM_EHABI
61
62 #if LIBCXXABI_ARM_EHABI && _LIBUNWIND_IS_BAREMETAL
63 // When statically linked on bare-metal, the symbols for the EH table are looked
64 // up without going through the dynamic loader.
65 // TODO(jroelofs): since Newlib on arm-none-eabi doesn't
66 // have dl_unwind_find_exidx...
67 struct EHTEntry {
68 uint32_t functionOffset;
69 uint32_t unwindOpcodes;
70 };
71 extern EHTEntry __exidx_start;
72 extern EHTEntry __exidx_end;
73 #endif
74
75 namespace libunwind {
76
77 /// Used by findUnwindSections() to return info about needed sections.
78 struct UnwindInfoSections {
79 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
80 uintptr_t dso_base;
81 uintptr_t dwarf_section;
82 uintptr_t dwarf_section_length;
83 #endif
84 #if _LIBUNWIND_SUPPORT_DWARF_INDEX
85 uintptr_t dso_base;
86 uintptr_t dwarf_index_section;
87 uintptr_t dwarf_index_section_length;
88 #endif
89 #if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
90 uintptr_t dso_base;
91 uintptr_t compact_unwind_section;
92 uintptr_t compact_unwind_section_length;
93 #endif
94 #if LIBCXXABI_ARM_EHABI
95 // No dso_base for ARM EHABI.
96 uintptr_t arm_section;
97 uintptr_t arm_section_length;
98 #endif
99 };
100
101
102 /// LocalAddressSpace is used as a template parameter to UnwindCursor when
103 /// unwinding a thread in the same process. The wrappers compile away,
104 /// making local unwinds fast.
105 class __attribute__((visibility("hidden"))) LocalAddressSpace {
106 public:
107 #if __LP64__
108 typedef uint64_t pint_t;
109 typedef int64_t sint_t;
110 #else
111 typedef uint32_t pint_t;
112 typedef int32_t sint_t;
113 #endif
get8(pint_t addr)114 uint8_t get8(pint_t addr) {
115 uint8_t val;
116 memcpy(&val, (void *)addr, sizeof(val));
117 return val;
118 }
get16(pint_t addr)119 uint16_t get16(pint_t addr) {
120 uint16_t val;
121 memcpy(&val, (void *)addr, sizeof(val));
122 return val;
123 }
get32(pint_t addr)124 uint32_t get32(pint_t addr) {
125 uint32_t val;
126 memcpy(&val, (void *)addr, sizeof(val));
127 return val;
128 }
get64(pint_t addr)129 uint64_t get64(pint_t addr) {
130 uint64_t val;
131 memcpy(&val, (void *)addr, sizeof(val));
132 return val;
133 }
getDouble(pint_t addr)134 double getDouble(pint_t addr) {
135 double val;
136 memcpy(&val, (void *)addr, sizeof(val));
137 return val;
138 }
getVector(pint_t addr)139 v128 getVector(pint_t addr) {
140 v128 val;
141 memcpy(&val, (void *)addr, sizeof(val));
142 return val;
143 }
144 uintptr_t getP(pint_t addr);
145 static uint64_t getULEB128(pint_t &addr, pint_t end);
146 static int64_t getSLEB128(pint_t &addr, pint_t end);
147
148 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
149 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
150 unw_word_t *offset);
151 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
152 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
153
154 static LocalAddressSpace sThisAddressSpace;
155 };
156
getP(pint_t addr)157 inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
158 #if __LP64__
159 return get64(addr);
160 #else
161 return get32(addr);
162 #endif
163 }
164
165 /// Read a ULEB128 into a 64-bit word.
getULEB128(pint_t & addr,pint_t end)166 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
167 const uint8_t *p = (uint8_t *)addr;
168 const uint8_t *pend = (uint8_t *)end;
169 uint64_t result = 0;
170 int bit = 0;
171 do {
172 uint64_t b;
173
174 if (p == pend)
175 _LIBUNWIND_ABORT("truncated uleb128 expression");
176
177 b = *p & 0x7f;
178
179 if (bit >= 64 || b << bit >> bit != b) {
180 _LIBUNWIND_ABORT("malformed uleb128 expression");
181 } else {
182 result |= b << bit;
183 bit += 7;
184 }
185 } while (*p++ >= 0x80);
186 addr = (pint_t) p;
187 return result;
188 }
189
190 /// Read a SLEB128 into a 64-bit word.
getSLEB128(pint_t & addr,pint_t end)191 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
192 const uint8_t *p = (uint8_t *)addr;
193 const uint8_t *pend = (uint8_t *)end;
194 int64_t result = 0;
195 int bit = 0;
196 uint8_t byte;
197 do {
198 if (p == pend)
199 _LIBUNWIND_ABORT("truncated sleb128 expression");
200 byte = *p++;
201 result |= ((byte & 0x7f) << bit);
202 bit += 7;
203 } while (byte & 0x80);
204 // sign extend negative numbers
205 if ((byte & 0x40) != 0)
206 result |= (-1LL) << bit;
207 addr = (pint_t) p;
208 return result;
209 }
210
getEncodedP(pint_t & addr,pint_t end,uint8_t encoding)211 inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr,
212 pint_t end,
213 uint8_t encoding) {
214 pint_t startAddr = addr;
215 const uint8_t *p = (uint8_t *)addr;
216 pint_t result;
217
218 // first get value
219 switch (encoding & 0x0F) {
220 case DW_EH_PE_ptr:
221 result = getP(addr);
222 p += sizeof(pint_t);
223 addr = (pint_t) p;
224 break;
225 case DW_EH_PE_uleb128:
226 result = (pint_t)getULEB128(addr, end);
227 break;
228 case DW_EH_PE_udata2:
229 result = get16(addr);
230 p += 2;
231 addr = (pint_t) p;
232 break;
233 case DW_EH_PE_udata4:
234 result = get32(addr);
235 p += 4;
236 addr = (pint_t) p;
237 break;
238 case DW_EH_PE_udata8:
239 result = (pint_t)get64(addr);
240 p += 8;
241 addr = (pint_t) p;
242 break;
243 case DW_EH_PE_sleb128:
244 result = (pint_t)getSLEB128(addr, end);
245 break;
246 case DW_EH_PE_sdata2:
247 // Sign extend from signed 16-bit value.
248 result = (pint_t)(int16_t)get16(addr);
249 p += 2;
250 addr = (pint_t) p;
251 break;
252 case DW_EH_PE_sdata4:
253 // Sign extend from signed 32-bit value.
254 result = (pint_t)(int32_t)get32(addr);
255 p += 4;
256 addr = (pint_t) p;
257 break;
258 case DW_EH_PE_sdata8:
259 result = (pint_t)get64(addr);
260 p += 8;
261 addr = (pint_t) p;
262 break;
263 default:
264 _LIBUNWIND_ABORT("unknown pointer encoding");
265 }
266
267 // then add relative offset
268 switch (encoding & 0x70) {
269 case DW_EH_PE_absptr:
270 // do nothing
271 break;
272 case DW_EH_PE_pcrel:
273 result += startAddr;
274 break;
275 case DW_EH_PE_textrel:
276 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
277 break;
278 case DW_EH_PE_datarel:
279 _LIBUNWIND_ABORT("DW_EH_PE_datarel pointer encoding not supported");
280 break;
281 case DW_EH_PE_funcrel:
282 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
283 break;
284 case DW_EH_PE_aligned:
285 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
286 break;
287 default:
288 _LIBUNWIND_ABORT("unknown pointer encoding");
289 break;
290 }
291
292 if (encoding & DW_EH_PE_indirect)
293 result = getP(result);
294
295 return result;
296 }
297
298 #if __APPLE__
299 struct dyld_unwind_sections
300 {
301 const struct mach_header* mh;
302 const void* dwarf_section;
303 uintptr_t dwarf_section_length;
304 const void* compact_unwind_section;
305 uintptr_t compact_unwind_section_length;
306 };
307 #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
308 && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
309 || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
310 // In 10.7.0 or later, libSystem.dylib implements this function.
311 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
312 #else
313 // In 10.6.x and earlier, we need to implement this functionality.
_dyld_find_unwind_sections(void * addr,dyld_unwind_sections * info)314 static inline bool _dyld_find_unwind_sections(void* addr,
315 dyld_unwind_sections* info) {
316 // Find mach-o image containing address.
317 Dl_info dlinfo;
318 if (!dladdr(addr, &dlinfo))
319 return false;
320 const mach_header *mh = (const mach_header *)dlinfo.dli_saddr;
321
322 // Find dwarf unwind section in that image.
323 unsigned long size;
324 const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size);
325 if (!p)
326 return false;
327
328 // Fill in return struct.
329 info->mh = mh;
330 info->dwarf_section = p;
331 info->dwarf_section_length = size;
332 info->compact_unwind_section = 0;
333 info->compact_unwind_section_length = 0;
334
335 return true;
336 }
337 #endif
338 #endif
339
findUnwindSections(pint_t targetAddr,UnwindInfoSections & info)340 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
341 UnwindInfoSections &info) {
342 #if __APPLE__
343 dyld_unwind_sections dyldInfo;
344 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
345 info.dso_base = (uintptr_t)dyldInfo.mh;
346 #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
347 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
348 info.dwarf_section_length = dyldInfo.dwarf_section_length;
349 #endif
350 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
351 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
352 return true;
353 }
354 #elif LIBCXXABI_ARM_EHABI
355 #if !_LIBUNWIND_IS_BAREMETAL
356 int length = 0;
357 info.arm_section = (uintptr_t) dl_unwind_find_exidx(
358 (_Unwind_Ptr) targetAddr, &length);
359 info.arm_section_length = length;
360 #else
361 // Bare metal, statically linked
362 info.arm_section = (uintptr_t)(&__exidx_start);
363 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
364 #endif
365 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x\n",
366 info.arm_section, info.arm_section_length);
367 if (info.arm_section && info.arm_section_length)
368 return true;
369 #endif
370
371 return false;
372 }
373
374
findOtherFDE(pint_t targetAddr,pint_t & fde)375 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
376 #if __APPLE__
377 return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
378 #else
379 // TO DO: if OS has way to dynamically register FDEs, check that.
380 return false;
381 #endif
382 }
383
findFunctionName(pint_t addr,char * buf,size_t bufLen,unw_word_t * offset)384 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
385 size_t bufLen,
386 unw_word_t *offset) {
387 #if !_LIBUNWIND_IS_BAREMETAL
388 Dl_info dyldInfo;
389 if (dladdr((void *)addr, &dyldInfo)) {
390 if (dyldInfo.dli_sname != NULL) {
391 strlcpy(buf, dyldInfo.dli_sname, bufLen);
392 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
393 return true;
394 }
395 }
396 #endif
397 return false;
398 }
399
400
401
402 #if UNW_REMOTE
403
404 /// OtherAddressSpace is used as a template parameter to UnwindCursor when
405 /// unwinding a thread in the another process. The other process can be a
406 /// different endianness and a different pointer size which is handled by
407 /// the P template parameter.
408 template <typename P>
409 class OtherAddressSpace {
410 public:
OtherAddressSpace(task_t task)411 OtherAddressSpace(task_t task) : fTask(task) {}
412
413 typedef typename P::uint_t pint_t;
414
415 uint8_t get8(pint_t addr);
416 uint16_t get16(pint_t addr);
417 uint32_t get32(pint_t addr);
418 uint64_t get64(pint_t addr);
419 pint_t getP(pint_t addr);
420 uint64_t getULEB128(pint_t &addr, pint_t end);
421 int64_t getSLEB128(pint_t &addr, pint_t end);
422 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
423 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
424 unw_word_t *offset);
425 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
426 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
427 private:
428 void *localCopy(pint_t addr);
429
430 task_t fTask;
431 };
432
get8(pint_t addr)433 template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) {
434 return *((uint8_t *)localCopy(addr));
435 }
436
get16(pint_t addr)437 template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) {
438 return P::E::get16(*(uint16_t *)localCopy(addr));
439 }
440
get32(pint_t addr)441 template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) {
442 return P::E::get32(*(uint32_t *)localCopy(addr));
443 }
444
get64(pint_t addr)445 template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) {
446 return P::E::get64(*(uint64_t *)localCopy(addr));
447 }
448
449 template <typename P>
getP(pint_t addr)450 typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) {
451 return P::getP(*(uint64_t *)localCopy(addr));
452 }
453
454 template <typename P>
getULEB128(pint_t & addr,pint_t end)455 uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
456 uintptr_t size = (end - addr);
457 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
458 LocalAddressSpace::pint_t sladdr = laddr;
459 uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
460 addr += (laddr - sladdr);
461 return result;
462 }
463
464 template <typename P>
getSLEB128(pint_t & addr,pint_t end)465 int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
466 uintptr_t size = (end - addr);
467 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
468 LocalAddressSpace::pint_t sladdr = laddr;
469 uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
470 addr += (laddr - sladdr);
471 return result;
472 }
473
localCopy(pint_t addr)474 template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) {
475 // FIX ME
476 }
477
478 template <typename P>
findFunctionName(pint_t addr,char * buf,size_t bufLen,unw_word_t * offset)479 bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
480 size_t bufLen, unw_word_t *offset) {
481 // FIX ME
482 }
483
484 /// unw_addr_space is the base class that abstract unw_addr_space_t type in
485 /// libunwind.h points to.
486 struct unw_addr_space {
487 cpu_type_t cpuType;
488 task_t taskPort;
489 };
490
491 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
492 /// to when examining
493 /// a 32-bit intel process.
494 struct unw_addr_space_i386 : public unw_addr_space {
unw_addr_space_i386libunwind::unw_addr_space_i386495 unw_addr_space_i386(task_t task) : oas(task) {}
496 OtherAddressSpace<Pointer32<LittleEndian> > oas;
497 };
498
499 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
500 /// points to when examining
501 /// a 64-bit intel process.
502 struct unw_addr_space_x86_64 : public unw_addr_space {
unw_addr_space_x86_64libunwind::unw_addr_space_x86_64503 unw_addr_space_x86_64(task_t task) : oas(task) {}
504 OtherAddressSpace<Pointer64<LittleEndian> > oas;
505 };
506
507 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
508 /// to when examining
509 /// a 32-bit PowerPC process.
510 struct unw_addr_space_ppc : public unw_addr_space {
unw_addr_space_ppclibunwind::unw_addr_space_ppc511 unw_addr_space_ppc(task_t task) : oas(task) {}
512 OtherAddressSpace<Pointer32<BigEndian> > oas;
513 };
514
515 #endif // UNW_REMOTE
516
517 } // namespace libunwind
518
519 #endif // __ADDRESSSPACE_HPP__
520