blob: 73013c73ff71759663b2ec9ea5c9e005ad7217c6 [file] [log] [blame]
Saleem Abdulrasool17552662015-04-24 19:39:17 +00001//===------------------------- 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>
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
Logan Chien06b0c7a2015-07-19 15:23:10 +000037#if _LIBUNWIND_ARM_EHABI
Ed Maste87785ae2015-10-16 19:40:09 +000038#if defined(__FreeBSD__)
39
40typedef void *_Unwind_Ptr;
41
42#elif defined(__linux__)
Saleem Abdulrasool17552662015-04-24 19:39:17 +000043
44typedef long unsigned int *_Unwind_Ptr;
45extern "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.
55struct EHTEntry {
56 uint32_t functionOffset;
57 uint32_t unwindOpcodes;
58};
59extern EHTEntry __exidx_start;
60extern EHTEntry __exidx_end;
61#endif // !defined(_LIBUNWIND_IS_BAREMETAL)
Logan Chien06b0c7a2015-07-19 15:23:10 +000062#endif // _LIBUNWIND_ARM_EHABI
Saleem Abdulrasool17552662015-04-24 19:39:17 +000063
Ed Schouten86f3b4b2015-04-29 20:43:44 +000064#if defined(__CloudABI__) || defined(__FreeBSD__) || defined(__linux__)
Saleem Abdulrasool17552662015-04-24 19:39:17 +000065#if _LIBUNWIND_SUPPORT_DWARF_UNWIND && _LIBUNWIND_SUPPORT_DWARF_INDEX
66#include <link.h>
Ed Schouten86f3b4b2015-04-29 20:43:44 +000067// 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
Saleem Abdulrasool17552662015-04-24 19:39:17 +000074#include "EHHeaderParser.hpp"
75#endif
76#endif
77
78namespace libunwind {
79
80/// Used by findUnwindSections() to return info about needed sections.
81struct 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
Logan Chien06b0c7a2015-07-19 15:23:10 +000099#if _LIBUNWIND_ARM_EHABI
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000100 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.
109class __attribute__((visibility("hidden"))) LocalAddressSpace {
110public:
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
162inline 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.
171inline 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.
196inline 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
216inline LocalAddressSpace::pint_t
217LocalAddressSpace::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
350inline 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 }
Logan Chien06b0c7a2015-07-19 15:23:10 +0000364#elif _LIBUNWIND_ARM_EHABI
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000365 #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
Viktor Kutuzova28f5b32015-05-06 10:32:28 +0000402#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];
Saleem Abdulrasool17552662015-04-24 19:39:17 +0000411 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
450inline 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
461inline 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.
485template <typename P>
486class OtherAddressSpace {
487public:
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);
505private:
506 void *localCopy(pint_t addr);
507
508 task_t fTask;
509};
510
511template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) {
512 return *((uint8_t *)localCopy(addr));
513}
514
515template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) {
516 return P::E::get16(*(uint16_t *)localCopy(addr));
517}
518
519template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) {
520 return P::E::get32(*(uint32_t *)localCopy(addr));
521}
522
523template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) {
524 return P::E::get64(*(uint64_t *)localCopy(addr));
525}
526
527template <typename P>
528typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) {
529 return P::getP(*(uint64_t *)localCopy(addr));
530}
531
532template <typename P>
533uint64_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
542template <typename P>
543int64_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
552template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) {
553 // FIX ME
554}
555
556template <typename P>
557bool 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.
564struct 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.
572struct 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.
580struct 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.
588struct 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__