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