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