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_USE_DLADDR
22 #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
23 #define _LIBUNWIND_USE_DLADDR 1
24 #else
25 #define _LIBUNWIND_USE_DLADDR 0
26 #endif
27 #endif
28
29 #if _LIBUNWIND_USE_DLADDR
30 #include <dlfcn.h>
31 #endif
32
33 #ifdef __APPLE__
34 #include <mach-o/getsect.h>
35 namespace libunwind {
36 bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
37 }
38 #endif
39
40 #include "libunwind.h"
41 #include "config.h"
42 #include "dwarf2.h"
43 #include "EHHeaderParser.hpp"
44 #include "Registers.hpp"
45
46 #ifdef __APPLE__
47
48 struct dyld_unwind_sections
49 {
50 const struct mach_header* mh;
51 const void* dwarf_section;
52 uintptr_t dwarf_section_length;
53 const void* compact_unwind_section;
54 uintptr_t compact_unwind_section_length;
55 };
56 #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
57 && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
58 || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
59 // In 10.7.0 or later, libSystem.dylib implements this function.
60 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
61 #else
62 // In 10.6.x and earlier, we need to implement this functionality. Note
63 // that this requires a newer version of libmacho (from cctools) than is
64 // present in libSystem on 10.6.x (for getsectiondata).
_dyld_find_unwind_sections(void * addr,dyld_unwind_sections * info)65 static inline bool _dyld_find_unwind_sections(void* addr,
66 dyld_unwind_sections* info) {
67 // Find mach-o image containing address.
68 Dl_info dlinfo;
69 if (!dladdr(addr, &dlinfo))
70 return false;
71 #if __LP64__
72 const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
73 #else
74 const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
75 #endif
76
77 // Initialize the return struct
78 info->mh = (const struct mach_header *)mh;
79 info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
80 info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
81
82 if (!info->dwarf_section) {
83 info->dwarf_section_length = 0;
84 }
85
86 if (!info->compact_unwind_section) {
87 info->compact_unwind_section_length = 0;
88 }
89
90 return true;
91 }
92 #endif
93
94 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
95
96 // When statically linked on bare-metal, the symbols for the EH table are looked
97 // up without going through the dynamic loader.
98
99 // The following linker script may be used to produce the necessary sections and symbols.
100 // Unless the --eh-frame-hdr linker option is provided, the section is not generated
101 // and does not take space in the output file.
102 //
103 // .eh_frame :
104 // {
105 // __eh_frame_start = .;
106 // KEEP(*(.eh_frame))
107 // __eh_frame_end = .;
108 // }
109 //
110 // .eh_frame_hdr :
111 // {
112 // KEEP(*(.eh_frame_hdr))
113 // }
114 //
115 // __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
116 // __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
117
118 extern char __eh_frame_start;
119 extern char __eh_frame_end;
120
121 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
122 extern char __eh_frame_hdr_start;
123 extern char __eh_frame_hdr_end;
124 #endif
125
126 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
127
128 // When statically linked on bare-metal, the symbols for the EH table are looked
129 // up without going through the dynamic loader.
130 extern char __exidx_start;
131 extern char __exidx_end;
132
133 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
134
135 // ELF-based systems may use dl_iterate_phdr() to access sections
136 // containing unwinding information. The ElfW() macro for pointer-size
137 // independent ELF header traversal is not provided by <link.h> on some
138 // systems (e.g., FreeBSD). On these systems the data structures are
139 // just called Elf_XXX. Define ElfW() locally.
140 #ifndef _WIN32
141 #include <link.h>
142 #else
143 #include <windows.h>
144 #include <psapi.h>
145 #endif
146 #if !defined(ElfW)
147 #define ElfW(type) Elf_##type
148 #endif
149
150 #endif
151
152 namespace libunwind {
153
154 /// Used by findUnwindSections() to return info about needed sections.
155 struct UnwindInfoSections {
156 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
157 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
158 // No dso_base for SEH or ARM EHABI.
159 uintptr_t dso_base;
160 #endif
161 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
162 uintptr_t dwarf_section;
163 uintptr_t dwarf_section_length;
164 #endif
165 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
166 uintptr_t dwarf_index_section;
167 uintptr_t dwarf_index_section_length;
168 #endif
169 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
170 uintptr_t compact_unwind_section;
171 uintptr_t compact_unwind_section_length;
172 #endif
173 #if defined(_LIBUNWIND_ARM_EHABI)
174 uintptr_t arm_section;
175 uintptr_t arm_section_length;
176 #endif
177 };
178
179
180 /// LocalAddressSpace is used as a template parameter to UnwindCursor when
181 /// unwinding a thread in the same process. The wrappers compile away,
182 /// making local unwinds fast.
183 class _LIBUNWIND_HIDDEN LocalAddressSpace {
184 public:
185 typedef uintptr_t pint_t;
186 typedef intptr_t sint_t;
get8(pint_t addr)187 uint8_t get8(pint_t addr) {
188 uint8_t val;
189 memcpy(&val, (void *)addr, sizeof(val));
190 return val;
191 }
get16(pint_t addr)192 uint16_t get16(pint_t addr) {
193 uint16_t val;
194 memcpy(&val, (void *)addr, sizeof(val));
195 return val;
196 }
get32(pint_t addr)197 uint32_t get32(pint_t addr) {
198 uint32_t val;
199 memcpy(&val, (void *)addr, sizeof(val));
200 return val;
201 }
get64(pint_t addr)202 uint64_t get64(pint_t addr) {
203 uint64_t val;
204 memcpy(&val, (void *)addr, sizeof(val));
205 return val;
206 }
getDouble(pint_t addr)207 double getDouble(pint_t addr) {
208 double val;
209 memcpy(&val, (void *)addr, sizeof(val));
210 return val;
211 }
getVector(pint_t addr)212 v128 getVector(pint_t addr) {
213 v128 val;
214 memcpy(&val, (void *)addr, sizeof(val));
215 return val;
216 }
217 uintptr_t getP(pint_t addr);
218 uint64_t getRegister(pint_t addr);
219 static uint64_t getULEB128(pint_t &addr, pint_t end);
220 static int64_t getSLEB128(pint_t &addr, pint_t end);
221
222 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
223 pint_t datarelBase = 0);
224 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
225 unw_word_t *offset);
226 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
227 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
228
229 static LocalAddressSpace sThisAddressSpace;
230 };
231
getP(pint_t addr)232 inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
233 #if __SIZEOF_POINTER__ == 8
234 return get64(addr);
235 #else
236 return get32(addr);
237 #endif
238 }
239
getRegister(pint_t addr)240 inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
241 #if __SIZEOF_POINTER__ == 8 || defined(__mips64)
242 return get64(addr);
243 #else
244 return get32(addr);
245 #endif
246 }
247
248 /// Read a ULEB128 into a 64-bit word.
getULEB128(pint_t & addr,pint_t end)249 inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
250 const uint8_t *p = (uint8_t *)addr;
251 const uint8_t *pend = (uint8_t *)end;
252 uint64_t result = 0;
253 int bit = 0;
254 do {
255 uint64_t b;
256
257 if (p == pend)
258 _LIBUNWIND_ABORT("truncated uleb128 expression");
259
260 b = *p & 0x7f;
261
262 if (bit >= 64 || b << bit >> bit != b) {
263 _LIBUNWIND_ABORT("malformed uleb128 expression");
264 } else {
265 result |= b << bit;
266 bit += 7;
267 }
268 } while (*p++ >= 0x80);
269 addr = (pint_t) p;
270 return result;
271 }
272
273 /// Read a SLEB128 into a 64-bit word.
getSLEB128(pint_t & addr,pint_t end)274 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
275 const uint8_t *p = (uint8_t *)addr;
276 const uint8_t *pend = (uint8_t *)end;
277 int64_t result = 0;
278 int bit = 0;
279 uint8_t byte;
280 do {
281 if (p == pend)
282 _LIBUNWIND_ABORT("truncated sleb128 expression");
283 byte = *p++;
284 result |= ((byte & 0x7f) << bit);
285 bit += 7;
286 } while (byte & 0x80);
287 // sign extend negative numbers
288 if ((byte & 0x40) != 0)
289 result |= (-1ULL) << bit;
290 addr = (pint_t) p;
291 return result;
292 }
293
294 inline LocalAddressSpace::pint_t
getEncodedP(pint_t & addr,pint_t end,uint8_t encoding,pint_t datarelBase)295 LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
296 pint_t datarelBase) {
297 pint_t startAddr = addr;
298 const uint8_t *p = (uint8_t *)addr;
299 pint_t result;
300
301 // first get value
302 switch (encoding & 0x0F) {
303 case DW_EH_PE_ptr:
304 result = getP(addr);
305 p += sizeof(pint_t);
306 addr = (pint_t) p;
307 break;
308 case DW_EH_PE_uleb128:
309 result = (pint_t)getULEB128(addr, end);
310 break;
311 case DW_EH_PE_udata2:
312 result = get16(addr);
313 p += 2;
314 addr = (pint_t) p;
315 break;
316 case DW_EH_PE_udata4:
317 result = get32(addr);
318 p += 4;
319 addr = (pint_t) p;
320 break;
321 case DW_EH_PE_udata8:
322 result = (pint_t)get64(addr);
323 p += 8;
324 addr = (pint_t) p;
325 break;
326 case DW_EH_PE_sleb128:
327 result = (pint_t)getSLEB128(addr, end);
328 break;
329 case DW_EH_PE_sdata2:
330 // Sign extend from signed 16-bit value.
331 result = (pint_t)(int16_t)get16(addr);
332 p += 2;
333 addr = (pint_t) p;
334 break;
335 case DW_EH_PE_sdata4:
336 // Sign extend from signed 32-bit value.
337 result = (pint_t)(int32_t)get32(addr);
338 p += 4;
339 addr = (pint_t) p;
340 break;
341 case DW_EH_PE_sdata8:
342 result = (pint_t)get64(addr);
343 p += 8;
344 addr = (pint_t) p;
345 break;
346 default:
347 _LIBUNWIND_ABORT("unknown pointer encoding");
348 }
349
350 // then add relative offset
351 switch (encoding & 0x70) {
352 case DW_EH_PE_absptr:
353 // do nothing
354 break;
355 case DW_EH_PE_pcrel:
356 result += startAddr;
357 break;
358 case DW_EH_PE_textrel:
359 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
360 break;
361 case DW_EH_PE_datarel:
362 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
363 // default value of 0, and we abort in the event that someone calls this
364 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
365 if (datarelBase == 0)
366 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
367 result += datarelBase;
368 break;
369 case DW_EH_PE_funcrel:
370 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
371 break;
372 case DW_EH_PE_aligned:
373 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
374 break;
375 default:
376 _LIBUNWIND_ABORT("unknown pointer encoding");
377 break;
378 }
379
380 if (encoding & DW_EH_PE_indirect)
381 result = getP(result);
382
383 return result;
384 }
385
findUnwindSections(pint_t targetAddr,UnwindInfoSections & info)386 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
387 UnwindInfoSections &info) {
388 #ifdef __APPLE__
389 dyld_unwind_sections dyldInfo;
390 if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
391 info.dso_base = (uintptr_t)dyldInfo.mh;
392 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
393 info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
394 info.dwarf_section_length = dyldInfo.dwarf_section_length;
395 #endif
396 info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
397 info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
398 return true;
399 }
400 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
401 // Bare metal is statically linked, so no need to ask the dynamic loader
402 info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
403 info.dwarf_section = (uintptr_t)(&__eh_frame_start);
404 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
405 (void *)info.dwarf_section, (void *)info.dwarf_section_length);
406 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
407 info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
408 info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
409 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
410 (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
411 #endif
412 if (info.dwarf_section_length)
413 return true;
414 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
415 // Bare metal is statically linked, so no need to ask the dynamic loader
416 info.arm_section = (uintptr_t)(&__exidx_start);
417 info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
418 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
419 (void *)info.arm_section, (void *)info.arm_section_length);
420 if (info.arm_section && info.arm_section_length)
421 return true;
422 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
423 HMODULE mods[1024];
424 HANDLE process = GetCurrentProcess();
425 DWORD needed;
426
427 if (!EnumProcessModules(process, mods, sizeof(mods), &needed))
428 return false;
429
430 for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
431 PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
432 PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
433 PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
434 PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
435 bool found_obj = false;
436 bool found_hdr = false;
437
438 info.dso_base = (uintptr_t)mods[i];
439 for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
440 uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
441 uintptr_t end = begin + pish->Misc.VirtualSize;
442 if (!strncmp((const char *)pish->Name, ".text",
443 IMAGE_SIZEOF_SHORT_NAME)) {
444 if (targetAddr >= begin && targetAddr < end)
445 found_obj = true;
446 } else if (!strncmp((const char *)pish->Name, ".eh_frame",
447 IMAGE_SIZEOF_SHORT_NAME)) {
448 info.dwarf_section = begin;
449 info.dwarf_section_length = pish->Misc.VirtualSize;
450 found_hdr = true;
451 }
452 if (found_obj && found_hdr)
453 return true;
454 }
455 }
456 return false;
457 #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
458 // Don't even bother, since Windows has functions that do all this stuff
459 // for us.
460 return true;
461 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) && \
462 (__ANDROID_API__ < 21)
463 int length = 0;
464 info.arm_section =
465 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
466 info.arm_section_length = (uintptr_t)length;
467 if (info.arm_section && info.arm_section_length)
468 return true;
469 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
470 struct dl_iterate_cb_data {
471 LocalAddressSpace *addressSpace;
472 UnwindInfoSections *sects;
473 uintptr_t targetAddr;
474 };
475
476 dl_iterate_cb_data cb_data = {this, &info, targetAddr};
477 int found = dl_iterate_phdr(
478 [](struct dl_phdr_info *pinfo, size_t, void *data) -> int {
479 auto cbdata = static_cast<dl_iterate_cb_data *>(data);
480 bool found_obj = false;
481 bool found_hdr = false;
482
483 assert(cbdata);
484 assert(cbdata->sects);
485
486 if (cbdata->targetAddr < pinfo->dlpi_addr) {
487 return false;
488 }
489
490 #if !defined(Elf_Half)
491 typedef ElfW(Half) Elf_Half;
492 #endif
493 #if !defined(Elf_Phdr)
494 typedef ElfW(Phdr) Elf_Phdr;
495 #endif
496 #if !defined(Elf_Addr) && defined(__ANDROID__)
497 typedef ElfW(Addr) Elf_Addr;
498 #endif
499
500 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
501 #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
502 #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
503 #endif
504 size_t object_length;
505 #if defined(__ANDROID__)
506 Elf_Addr image_base =
507 pinfo->dlpi_phnum
508 ? reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
509 reinterpret_cast<const Elf_Phdr *>(pinfo->dlpi_phdr)
510 ->p_offset
511 : 0;
512 #endif
513
514 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
515 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
516 if (phdr->p_type == PT_LOAD) {
517 uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
518 #if defined(__ANDROID__)
519 if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
520 begin = begin + image_base;
521 #endif
522 uintptr_t end = begin + phdr->p_memsz;
523 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
524 cbdata->sects->dso_base = begin;
525 object_length = phdr->p_memsz;
526 found_obj = true;
527 }
528 } else if (phdr->p_type == PT_GNU_EH_FRAME) {
529 EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
530 uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr;
531 #if defined(__ANDROID__)
532 if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
533 eh_frame_hdr_start = eh_frame_hdr_start + image_base;
534 #endif
535 cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
536 cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
537 found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
538 *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
539 hdrInfo);
540 if (found_hdr)
541 cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
542 }
543 }
544
545 if (found_obj && found_hdr) {
546 cbdata->sects->dwarf_section_length = object_length;
547 return true;
548 } else {
549 return false;
550 }
551 #else // defined(_LIBUNWIND_ARM_EHABI)
552 for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
553 const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
554 if (phdr->p_type == PT_LOAD) {
555 uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
556 uintptr_t end = begin + phdr->p_memsz;
557 if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
558 found_obj = true;
559 } else if (phdr->p_type == PT_ARM_EXIDX) {
560 uintptr_t exidx_start = pinfo->dlpi_addr + phdr->p_vaddr;
561 cbdata->sects->arm_section = exidx_start;
562 cbdata->sects->arm_section_length = phdr->p_memsz;
563 found_hdr = true;
564 }
565 }
566 return found_obj && found_hdr;
567 #endif
568 },
569 &cb_data);
570 return static_cast<bool>(found);
571 #endif
572
573 return false;
574 }
575
576
findOtherFDE(pint_t targetAddr,pint_t & fde)577 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
578 #ifdef __APPLE__
579 return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
580 #else
581 // TO DO: if OS has way to dynamically register FDEs, check that.
582 (void)targetAddr;
583 (void)fde;
584 return false;
585 #endif
586 }
587
findFunctionName(pint_t addr,char * buf,size_t bufLen,unw_word_t * offset)588 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
589 size_t bufLen,
590 unw_word_t *offset) {
591 #if _LIBUNWIND_USE_DLADDR
592 Dl_info dyldInfo;
593 if (dladdr((void *)addr, &dyldInfo)) {
594 if (dyldInfo.dli_sname != NULL) {
595 snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
596 *offset = (addr - (pint_t) dyldInfo.dli_saddr);
597 return true;
598 }
599 }
600 #endif
601 return false;
602 }
603
604
605
606 #ifdef UNW_REMOTE
607
608 /// RemoteAddressSpace is used as a template parameter to UnwindCursor when
609 /// unwinding a thread in the another process. The other process can be a
610 /// different endianness and a different pointer size which is handled by
611 /// the P template parameter.
612 template <typename P>
613 class RemoteAddressSpace {
614 public:
RemoteAddressSpace(task_t task)615 RemoteAddressSpace(task_t task) : fTask(task) {}
616
617 typedef typename P::uint_t pint_t;
618
619 uint8_t get8(pint_t addr);
620 uint16_t get16(pint_t addr);
621 uint32_t get32(pint_t addr);
622 uint64_t get64(pint_t addr);
623 pint_t getP(pint_t addr);
624 uint64_t getRegister(pint_t addr);
625 uint64_t getULEB128(pint_t &addr, pint_t end);
626 int64_t getSLEB128(pint_t &addr, pint_t end);
627 pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
628 pint_t datarelBase = 0);
629 bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
630 unw_word_t *offset);
631 bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
632 bool findOtherFDE(pint_t targetAddr, pint_t &fde);
633 private:
634 void *localCopy(pint_t addr);
635
636 task_t fTask;
637 };
638
get8(pint_t addr)639 template <typename P> uint8_t RemoteAddressSpace<P>::get8(pint_t addr) {
640 return *((uint8_t *)localCopy(addr));
641 }
642
get16(pint_t addr)643 template <typename P> uint16_t RemoteAddressSpace<P>::get16(pint_t addr) {
644 return P::E::get16(*(uint16_t *)localCopy(addr));
645 }
646
get32(pint_t addr)647 template <typename P> uint32_t RemoteAddressSpace<P>::get32(pint_t addr) {
648 return P::E::get32(*(uint32_t *)localCopy(addr));
649 }
650
get64(pint_t addr)651 template <typename P> uint64_t RemoteAddressSpace<P>::get64(pint_t addr) {
652 return P::E::get64(*(uint64_t *)localCopy(addr));
653 }
654
655 template <typename P>
getP(pint_t addr)656 typename P::uint_t RemoteAddressSpace<P>::getP(pint_t addr) {
657 return P::getP(*(uint64_t *)localCopy(addr));
658 }
659
660 template <typename P>
getRegister(pint_t addr)661 typename P::uint_t OtherAddressSpace<P>::getRegister(pint_t addr) {
662 return P::getRegister(*(uint64_t *)localCopy(addr));
663 }
664
665 template <typename P>
getULEB128(pint_t & addr,pint_t end)666 uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
667 uintptr_t size = (end - addr);
668 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
669 LocalAddressSpace::pint_t sladdr = laddr;
670 uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
671 addr += (laddr - sladdr);
672 return result;
673 }
674
675 template <typename P>
getSLEB128(pint_t & addr,pint_t end)676 int64_t RemoteAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
677 uintptr_t size = (end - addr);
678 LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
679 LocalAddressSpace::pint_t sladdr = laddr;
680 uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
681 addr += (laddr - sladdr);
682 return result;
683 }
684
localCopy(pint_t addr)685 template <typename P> void *RemoteAddressSpace<P>::localCopy(pint_t addr) {
686 // FIX ME
687 }
688
689 template <typename P>
findFunctionName(pint_t addr,char * buf,size_t bufLen,unw_word_t * offset)690 bool RemoteAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
691 size_t bufLen,
692 unw_word_t *offset) {
693 // FIX ME
694 }
695
696 /// unw_addr_space is the base class that abstract unw_addr_space_t type in
697 /// libunwind.h points to.
698 struct unw_addr_space {
699 cpu_type_t cpuType;
700 task_t taskPort;
701 };
702
703 /// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
704 /// to when examining
705 /// a 32-bit intel process.
706 struct unw_addr_space_i386 : public unw_addr_space {
unw_addr_space_i386libunwind::unw_addr_space_i386707 unw_addr_space_i386(task_t task) : oas(task) {}
708 RemoteAddressSpace<Pointer32<LittleEndian>> oas;
709 };
710
711 /// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
712 /// points to when examining
713 /// a 64-bit intel process.
714 struct unw_addr_space_x86_64 : public unw_addr_space {
unw_addr_space_x86_64libunwind::unw_addr_space_x86_64715 unw_addr_space_x86_64(task_t task) : oas(task) {}
716 RemoteAddressSpace<Pointer64<LittleEndian>> oas;
717 };
718
719 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
720 /// to when examining
721 /// a 32-bit PowerPC process.
722 struct unw_addr_space_ppc : public unw_addr_space {
unw_addr_space_ppclibunwind::unw_addr_space_ppc723 unw_addr_space_ppc(task_t task) : oas(task) {}
724 RemoteAddressSpace<Pointer32<BigEndian>> oas;
725 };
726
727 /// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
728 /// to when examining a 64-bit PowerPC process.
729 struct unw_addr_space_ppc64 : public unw_addr_space {
unw_addr_space_ppc64libunwind::unw_addr_space_ppc64730 unw_addr_space_ppc64(task_t task) : oas(task) {}
731 RemoteAddressSpace<Pointer64<LittleEndian>> oas;
732 };
733
734 #endif // UNW_REMOTE
735
736 } // namespace libunwind
737
738 #endif // __ADDRESSSPACE_HPP__
739