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