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