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