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