Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / libc++abi / trunk / src / Unwind / AddressSpace.hpp
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>
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 #if __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 !_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.
51 struct EHTEntry {
52   uint32_t functionOffset;
53   uint32_t unwindOpcodes;
54 };
55 extern EHTEntry __exidx_start;
56 extern EHTEntry __exidx_end;
57 #endif // !_LIBUNWIND_IS_BAREMETAL
58
59 #endif  // LIBCXXABI_ARM_EHABI
60
61 namespace libunwind {
62
63 /// Used by findUnwindSections() to return info about needed sections.
64 struct 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.
92 class __attribute__((visibility("hidden"))) LocalAddressSpace {
93 public:
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
144 inline 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.
153 inline 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.
178 inline 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
198 inline 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 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
328                                                   UnwindInfoSections &info) {
329 #if __APPLE__
330   dyld_unwind_sections dyldInfo;
331   if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
332     info.dso_base                      = (uintptr_t)dyldInfo.mh;
333  #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
334     info.dwarf_section                 = (uintptr_t)dyldInfo.dwarf_section;
335     info.dwarf_section_length          = dyldInfo.dwarf_section_length;
336  #endif
337     info.compact_unwind_section        = (uintptr_t)dyldInfo.compact_unwind_section;
338     info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
339     return true;
340   }
341 #elif LIBCXXABI_ARM_EHABI
342  #if _LIBUNWIND_IS_BAREMETAL
343   // Bare metal is statically linked, so no need to ask the dynamic loader
344   info.arm_section =        (uintptr_t)(&__exidx_start);
345   info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
346  #else
347   int length = 0;
348   info.arm_section = (uintptr_t) dl_unwind_find_exidx(
349       (_Unwind_Ptr) targetAddr, &length);
350   info.arm_section_length = (uintptr_t)length;
351  #endif
352   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x\n",
353                              info.arm_section, info.arm_section_length);
354   if (info.arm_section && info.arm_section_length)
355     return true;
356 #endif
357
358   return false;
359 }
360
361
362 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
363 #if __APPLE__
364   return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
365 #else
366   // TO DO: if OS has way to dynamically register FDEs, check that.
367   (void)targetAddr;
368   (void)fde;
369   return false;
370 #endif
371 }
372
373 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
374                                                 size_t bufLen,
375                                                 unw_word_t *offset) {
376 #if !_LIBUNWIND_IS_BAREMETAL
377   Dl_info dyldInfo;
378   if (dladdr((void *)addr, &dyldInfo)) {
379     if (dyldInfo.dli_sname != NULL) {
380       snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
381       *offset = (addr - (pint_t) dyldInfo.dli_saddr);
382       return true;
383     }
384   }
385 #endif
386   return false;
387 }
388
389
390
391 #if UNW_REMOTE
392
393 /// OtherAddressSpace is used as a template parameter to UnwindCursor when
394 /// unwinding a thread in the another process.  The other process can be a
395 /// different endianness and a different pointer size which is handled by
396 /// the P template parameter.
397 template <typename P>
398 class OtherAddressSpace {
399 public:
400   OtherAddressSpace(task_t task) : fTask(task) {}
401
402   typedef typename P::uint_t pint_t;
403
404   uint8_t   get8(pint_t addr);
405   uint16_t  get16(pint_t addr);
406   uint32_t  get32(pint_t addr);
407   uint64_t  get64(pint_t addr);
408   pint_t    getP(pint_t addr);
409   uint64_t  getULEB128(pint_t &addr, pint_t end);
410   int64_t   getSLEB128(pint_t &addr, pint_t end);
411   pint_t    getEncodedP(pint_t &addr, pint_t end, uint8_t encoding);
412   bool      findFunctionName(pint_t addr, char *buf, size_t bufLen,
413                         unw_word_t *offset);
414   bool      findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
415   bool      findOtherFDE(pint_t targetAddr, pint_t &fde);
416 private:
417   void *localCopy(pint_t addr);
418
419   task_t fTask;
420 };
421
422 template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) {
423   return *((uint8_t *)localCopy(addr));
424 }
425
426 template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) {
427   return P::E::get16(*(uint16_t *)localCopy(addr));
428 }
429
430 template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) {
431   return P::E::get32(*(uint32_t *)localCopy(addr));
432 }
433
434 template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) {
435   return P::E::get64(*(uint64_t *)localCopy(addr));
436 }
437
438 template <typename P>
439 typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) {
440   return P::getP(*(uint64_t *)localCopy(addr));
441 }
442
443 template <typename P>
444 uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
445   uintptr_t size = (end - addr);
446   LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
447   LocalAddressSpace::pint_t sladdr = laddr;
448   uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
449   addr += (laddr - sladdr);
450   return result;
451 }
452
453 template <typename P>
454 int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
455   uintptr_t size = (end - addr);
456   LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
457   LocalAddressSpace::pint_t sladdr = laddr;
458   uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
459   addr += (laddr - sladdr);
460   return result;
461 }
462
463 template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) {
464   // FIX ME
465 }
466
467 template <typename P>
468 bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
469                                             size_t bufLen, unw_word_t *offset) {
470   // FIX ME
471 }
472
473 /// unw_addr_space is the base class that abstract unw_addr_space_t type in
474 /// libunwind.h points to.
475 struct unw_addr_space {
476   cpu_type_t cpuType;
477   task_t taskPort;
478 };
479
480 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
481 /// to when examining
482 /// a 32-bit intel process.
483 struct unw_addr_space_i386 : public unw_addr_space {
484   unw_addr_space_i386(task_t task) : oas(task) {}
485   OtherAddressSpace<Pointer32<LittleEndian> > oas;
486 };
487
488 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
489 /// points to when examining
490 /// a 64-bit intel process.
491 struct unw_addr_space_x86_64 : public unw_addr_space {
492   unw_addr_space_x86_64(task_t task) : oas(task) {}
493   OtherAddressSpace<Pointer64<LittleEndian> > oas;
494 };
495
496 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
497 /// to when examining
498 /// a 32-bit PowerPC process.
499 struct unw_addr_space_ppc : public unw_addr_space {
500   unw_addr_space_ppc(task_t task) : oas(task) {}
501   OtherAddressSpace<Pointer32<BigEndian> > oas;
502 };
503
504 #endif // UNW_REMOTE
505
506 } // namespace libunwind
507
508 #endif // __ADDRESSSPACE_HPP__