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