• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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