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 #include "FrameHeaderCache.hpp"
456 
457 // There should be just one of these per process.
458 static FrameHeaderCache ProcessFrameHeaderCache;
459 
460 static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
461                                dl_iterate_cb_data *cbdata) {
462   if (phdr->p_type == PT_LOAD) {
463     uintptr_t begin = image_base + phdr->p_vaddr;
464     uintptr_t end = begin + phdr->p_memsz;
465     if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
466       cbdata->sects->dso_base = begin;
467       cbdata->sects->dwarf_section_length = phdr->p_memsz;
468       return true;
469     }
470   }
471   return false;
472 }
473 
474 int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t pinfo_size,
475                              void *data) {
476   auto cbdata = static_cast<dl_iterate_cb_data *>(data);
477   if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
478     return 0;
479   if (ProcessFrameHeaderCache.find(pinfo, pinfo_size, data))
480     return 1;
481 
482   Elf_Addr image_base = calculateImageBase(pinfo);
483   bool found_obj = false;
484   bool found_hdr = false;
485 
486   // Third phdr is usually the executable phdr.
487   if (pinfo->dlpi_phnum > 2)
488     found_obj = checkAddrInSegment(&pinfo->dlpi_phdr[2], image_base, cbdata);
489 
490   // PT_GNU_EH_FRAME is usually near the end. Iterate backward. We already know
491   // that there is one or more phdrs.
492   for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
493     const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
494     if (!found_hdr && phdr->p_type == PT_GNU_EH_FRAME) {
495       EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
496       uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
497       cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
498       cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
499       found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
500           *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
501           hdrInfo);
502       if (found_hdr)
503         cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
504     } else if (!found_obj) {
505       found_obj = checkAddrInSegment(phdr, image_base, cbdata);
506     }
507     if (found_obj && found_hdr) {
508       ProcessFrameHeaderCache.add(cbdata->sects);
509       return 1;
510     }
511   }
512   cbdata->sects->dwarf_section_length = 0;
513   return 0;
514 }
515 
516 #else  // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
517 // Given all the #ifdef's above, the code here is for
518 // defined(LIBUNWIND_ARM_EHABI)
519 
520 int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t, void *data) {
521   auto *cbdata = static_cast<dl_iterate_cb_data *>(data);
522   bool found_obj = false;
523   bool found_hdr = false;
524 
525   assert(cbdata);
526   assert(cbdata->sects);
527 
528   if (cbdata->targetAddr < pinfo->dlpi_addr)
529     return 0;
530 
531   Elf_Addr image_base = calculateImageBase(pinfo);
532 
533   for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
534     const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
535     if (phdr->p_type == PT_LOAD) {
536       uintptr_t begin = image_base + phdr->p_vaddr;
537       uintptr_t end = begin + phdr->p_memsz;
538       if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
539         found_obj = true;
540     } else if (phdr->p_type == PT_ARM_EXIDX) {
541       uintptr_t exidx_start = image_base + phdr->p_vaddr;
542       cbdata->sects->arm_section = exidx_start;
543       cbdata->sects->arm_section_length = phdr->p_memsz;
544       found_hdr = true;
545     }
546   }
547   return found_obj && found_hdr;
548 }
549 #endif  // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
550 #endif  // defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
551 
552 
553 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
554                                                   UnwindInfoSections &info) {
555 #ifdef __APPLE__
556   dyld_unwind_sections dyldInfo;
557   if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
558     info.dso_base                      = (uintptr_t)dyldInfo.mh;
559  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
560     info.dwarf_section                 = (uintptr_t)dyldInfo.dwarf_section;
561     info.dwarf_section_length          = dyldInfo.dwarf_section_length;
562  #endif
563     info.compact_unwind_section        = (uintptr_t)dyldInfo.compact_unwind_section;
564     info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
565     return true;
566   }
567 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
568   // Bare metal is statically linked, so no need to ask the dynamic loader
569   info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
570   info.dwarf_section =        (uintptr_t)(&__eh_frame_start);
571   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
572                              (void *)info.dwarf_section, (void *)info.dwarf_section_length);
573 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
574   info.dwarf_index_section =        (uintptr_t)(&__eh_frame_hdr_start);
575   info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
576   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
577                              (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
578 #endif
579   if (info.dwarf_section_length)
580     return true;
581 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
582   // Bare metal is statically linked, so no need to ask the dynamic loader
583   info.arm_section =        (uintptr_t)(&__exidx_start);
584   info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
585   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
586                              (void *)info.arm_section, (void *)info.arm_section_length);
587   if (info.arm_section && info.arm_section_length)
588     return true;
589 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
590   HMODULE mods[1024];
591   HANDLE process = GetCurrentProcess();
592   DWORD needed;
593 
594   if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
595     DWORD err = GetLastError();
596     _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
597                                "returned error %d", (int)err);
598     return false;
599   }
600 
601   for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
602     PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
603     PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
604     PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
605     PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
606     bool found_obj = false;
607     bool found_hdr = false;
608 
609     info.dso_base = (uintptr_t)mods[i];
610     for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
611       uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
612       uintptr_t end = begin + pish->Misc.VirtualSize;
613       if (!strncmp((const char *)pish->Name, ".text",
614                    IMAGE_SIZEOF_SHORT_NAME)) {
615         if (targetAddr >= begin && targetAddr < end)
616           found_obj = true;
617       } else if (!strncmp((const char *)pish->Name, ".eh_frame",
618                           IMAGE_SIZEOF_SHORT_NAME)) {
619         info.dwarf_section = begin;
620         info.dwarf_section_length = pish->Misc.VirtualSize;
621         found_hdr = true;
622       }
623       if (found_obj && found_hdr)
624         return true;
625     }
626   }
627   return false;
628 #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
629   // Don't even bother, since Windows has functions that do all this stuff
630   // for us.
631   (void)targetAddr;
632   (void)info;
633   return true;
634 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
635   // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
636   // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
637   int length = 0;
638   info.arm_section =
639       (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
640   info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
641   if (info.arm_section && info.arm_section_length)
642     return true;
643 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
644   dl_iterate_cb_data cb_data = {this, &info, targetAddr};
645   int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
646   return static_cast<bool>(found);
647 #endif
648 
649   return false;
650 }
651 
652 
653 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
654 #ifdef __APPLE__
655   return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
656 #else
657   // TO DO: if OS has way to dynamically register FDEs, check that.
658   (void)targetAddr;
659   (void)fde;
660   return false;
661 #endif
662 }
663 
664 inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
665                                                 size_t bufLen,
666                                                 unw_word_t *offset) {
667 #if _LIBUNWIND_USE_DLADDR
668   Dl_info dyldInfo;
669   if (dladdr((void *)addr, &dyldInfo)) {
670     if (dyldInfo.dli_sname != NULL) {
671       snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
672       *offset = (addr - (pint_t) dyldInfo.dli_saddr);
673       return true;
674     }
675   }
676 #else
677   (void)addr;
678   (void)buf;
679   (void)bufLen;
680   (void)offset;
681 #endif
682   return false;
683 }
684 
685 } // namespace libunwind
686 
687 #endif // __ADDRESSSPACE_HPP__
688