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