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