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 #ifdef __APPLE__
396 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
397 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
398 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
399 #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
400 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
401 // Code inside findUnwindSections handles all these cases.
402 //
403 // Although the above ifdef chain is ugly, there doesn't seem to be a cleaner
404 // way to handle it. The generalized boolean expression is:
405 //
406 //  A OR (B AND C) OR (D AND C) OR (B AND E) OR (F AND E) OR (D AND G)
407 //
408 // Running it through various boolean expression simplifiers gives expressions
409 // that don't help at all.
410 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
411 
412 #if !defined(Elf_Half)
413   typedef ElfW(Half) Elf_Half;
414 #endif
415 #if !defined(Elf_Phdr)
416   typedef ElfW(Phdr) Elf_Phdr;
417 #endif
418 #if !defined(Elf_Addr)
419   typedef ElfW(Addr) Elf_Addr;
420 #endif
421 
422 static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) {
423   Elf_Addr image_base = pinfo->dlpi_addr;
424 #if defined(__ANDROID__) && __ANDROID_API__ < 18
425   if (image_base == 0) {
426     // Normally, an image base of 0 indicates a non-PIE executable. On
427     // versions of Android prior to API 18, the dynamic linker reported a
428     // dlpi_addr of 0 for PIE executables. Compute the true image base
429     // using the PT_PHDR segment.
430     // See https://github.com/android/ndk/issues/505.
431     for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
432       const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
433       if (phdr->p_type == PT_PHDR) {
434         image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
435           phdr->p_vaddr;
436         break;
437       }
438     }
439   }
440 #endif
441   return image_base;
442 }
443 
444 struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
445   LocalAddressSpace *addressSpace;
446   UnwindInfoSections *sects;
447   uintptr_t targetAddr;
448 };
449 
450 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
451   #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
452     #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
453   #endif
454 
455 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
456 #include "FrameHeaderCache.hpp"
457 
458 // There should be just one of these per process.
459 static FrameHeaderCache ProcessFrameHeaderCache;
460 #endif
461 
462 static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
463                                dl_iterate_cb_data *cbdata) {
464   if (phdr->p_type == PT_LOAD) {
465     uintptr_t begin = image_base + phdr->p_vaddr;
466     uintptr_t end = begin + phdr->p_memsz;
467     if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
468       cbdata->sects->dso_base = begin;
469       cbdata->sects->dwarf_section_length = phdr->p_memsz;
470       return true;
471     }
472   }
473   return false;
474 }
475 
476 static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
477                                     size_t pinfo_size, void *data) {
478   auto cbdata = static_cast<dl_iterate_cb_data *>(data);
479   if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
480     return 0;
481 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
482   if (ProcessFrameHeaderCache.find(pinfo, pinfo_size, data))
483     return 1;
484 #endif
485 
486   Elf_Addr image_base = calculateImageBase(pinfo);
487   bool found_obj = false;
488   bool found_hdr = false;
489 
490   // Third phdr is usually the executable phdr.
491   if (pinfo->dlpi_phnum > 2)
492     found_obj = checkAddrInSegment(&pinfo->dlpi_phdr[2], image_base, cbdata);
493 
494   // PT_GNU_EH_FRAME is usually near the end. Iterate backward. We already know
495   // that there is one or more phdrs.
496   for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
497     const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
498     if (!found_hdr && phdr->p_type == PT_GNU_EH_FRAME) {
499       EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
500       uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
501       cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
502       cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
503       found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
504           *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
505           hdrInfo);
506       if (found_hdr)
507         cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
508     } else if (!found_obj) {
509       found_obj = checkAddrInSegment(phdr, image_base, cbdata);
510     }
511     if (found_obj && found_hdr) {
512 #if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
513       ProcessFrameHeaderCache.add(cbdata->sects);
514 #endif
515       return 1;
516     }
517   }
518   cbdata->sects->dwarf_section_length = 0;
519   return 0;
520 }
521 
522 #else  // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
523 // Given all the #ifdef's above, the code here is for
524 // defined(LIBUNWIND_ARM_EHABI)
525 
526 static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t,
527                                     void *data) {
528   auto *cbdata = static_cast<dl_iterate_cb_data *>(data);
529   bool found_obj = false;
530   bool found_hdr = false;
531 
532   assert(cbdata);
533   assert(cbdata->sects);
534 
535   if (cbdata->targetAddr < pinfo->dlpi_addr)
536     return 0;
537 
538   Elf_Addr image_base = calculateImageBase(pinfo);
539 
540   for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
541     const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
542     if (phdr->p_type == PT_LOAD) {
543       uintptr_t begin = image_base + phdr->p_vaddr;
544       uintptr_t end = begin + phdr->p_memsz;
545       if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
546         found_obj = true;
547     } else if (phdr->p_type == PT_ARM_EXIDX) {
548       uintptr_t exidx_start = image_base + phdr->p_vaddr;
549       cbdata->sects->arm_section = exidx_start;
550       cbdata->sects->arm_section_length = phdr->p_memsz;
551       found_hdr = true;
552     }
553   }
554   return found_obj && found_hdr;
555 }
556 #endif  // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
557 #endif  // defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
558 
559 
560 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
561                                                   UnwindInfoSections &info) {
562 #ifdef __APPLE__
563   dyld_unwind_sections dyldInfo;
564   if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
565     info.dso_base                      = (uintptr_t)dyldInfo.mh;
566  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
567     info.dwarf_section                 = (uintptr_t)dyldInfo.dwarf_section;
568     info.dwarf_section_length          = dyldInfo.dwarf_section_length;
569  #endif
570     info.compact_unwind_section        = (uintptr_t)dyldInfo.compact_unwind_section;
571     info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
572     return true;
573   }
574 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
575   // Bare metal is statically linked, so no need to ask the dynamic loader
576   info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
577   info.dwarf_section =        (uintptr_t)(&__eh_frame_start);
578   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
579                              (void *)info.dwarf_section, (void *)info.dwarf_section_length);
580 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
581   info.dwarf_index_section =        (uintptr_t)(&__eh_frame_hdr_start);
582   info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
583   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
584                              (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
585 #endif
586   if (info.dwarf_section_length)
587     return true;
588 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
589   // Bare metal is statically linked, so no need to ask the dynamic loader
590   info.arm_section =        (uintptr_t)(&__exidx_start);
591   info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
592   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
593                              (void *)info.arm_section, (void *)info.arm_section_length);
594   if (info.arm_section && info.arm_section_length)
595     return true;
596 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
597   HMODULE mods[1024];
598   HANDLE process = GetCurrentProcess();
599   DWORD needed;
600 
601   if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
602     DWORD err = GetLastError();
603     _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
604                                "returned error %d", (int)err);
605     return false;
606   }
607 
608   for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
609     PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
610     PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
611     PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
612     PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
613     bool found_obj = false;
614     bool found_hdr = false;
615 
616     info.dso_base = (uintptr_t)mods[i];
617     for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
618       uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
619       uintptr_t end = begin + pish->Misc.VirtualSize;
620       if (!strncmp((const char *)pish->Name, ".text",
621                    IMAGE_SIZEOF_SHORT_NAME)) {
622         if (targetAddr >= begin && targetAddr < end)
623           found_obj = true;
624       } else if (!strncmp((const char *)pish->Name, ".eh_frame",
625                           IMAGE_SIZEOF_SHORT_NAME)) {
626         info.dwarf_section = begin;
627         info.dwarf_section_length = pish->Misc.VirtualSize;
628         found_hdr = true;
629       }
630       if (found_obj && found_hdr)
631         return true;
632     }
633   }
634   return false;
635 #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
636   // Don't even bother, since Windows has functions that do all this stuff
637   // for us.
638   (void)targetAddr;
639   (void)info;
640   return true;
641 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
642   // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
643   // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
644   int length = 0;
645   info.arm_section =
646       (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
647   info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
648   if (info.arm_section && info.arm_section_length)
649     return true;
650 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
651   dl_iterate_cb_data cb_data = {this, &info, targetAddr};
652   int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
653   return static_cast<bool>(found);
654 #endif
655 
656   return false;
657 }
658 
659 
660 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
661 #ifdef __APPLE__
662   return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
663 #else
664   // TO DO: if OS has way to dynamically register FDEs, check that.
665   (void)targetAddr;
666   (void)fde;
667   return false;
668 #endif
669 }
670 
671 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
672                                                 size_t bufLen,
673                                                 unw_word_t *offset) {
674 #if _LIBUNWIND_USE_DLADDR
675   Dl_info dyldInfo;
676   if (dladdr((void *)addr, &dyldInfo)) {
677     if (dyldInfo.dli_sname != NULL) {
678       snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
679       *offset = (addr - (pint_t) dyldInfo.dli_saddr);
680       return true;
681     }
682   }
683 #else
684   (void)addr;
685   (void)buf;
686   (void)bufLen;
687   (void)offset;
688 #endif
689   return false;
690 }
691 
692 } // namespace libunwind
693 
694 #endif // __ADDRESSSPACE_HPP__
695