AddressSpace.hpp revision 360784
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)
36struct EHABIIndexEntry {
37  uint32_t functionOffset;
38  uint32_t data;
39};
40#endif
41
42#ifdef __APPLE__
43#include <mach-o/getsect.h>
44namespace 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
127extern char __eh_frame_start;
128extern char __eh_frame_end;
129
130#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
131extern char __eh_frame_hdr_start;
132extern 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.
139extern char __exidx_start;
140extern 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
161namespace libunwind {
162
163/// Used by findUnwindSections() to return info about needed sections.
164struct 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.
192class _LIBUNWIND_HIDDEN LocalAddressSpace {
193public:
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
241inline 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
249inline 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.
258inline 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.
283inline 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
303inline LocalAddressSpace::pint_t
304LocalAddressSpace::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
395inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
396                                                  UnwindInfoSections &info) {
397#ifdef __APPLE__
398  dyld_unwind_sections dyldInfo;
399  if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
400    info.dso_base                      = (uintptr_t)dyldInfo.mh;
401 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
402    info.dwarf_section                 = (uintptr_t)dyldInfo.dwarf_section;
403    info.dwarf_section_length          = dyldInfo.dwarf_section_length;
404 #endif
405    info.compact_unwind_section        = (uintptr_t)dyldInfo.compact_unwind_section;
406    info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
407    return true;
408  }
409#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
410  // Bare metal is statically linked, so no need to ask the dynamic loader
411  info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
412  info.dwarf_section =        (uintptr_t)(&__eh_frame_start);
413  _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
414                             (void *)info.dwarf_section, (void *)info.dwarf_section_length);
415#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
416  info.dwarf_index_section =        (uintptr_t)(&__eh_frame_hdr_start);
417  info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
418  _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
419                             (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
420#endif
421  if (info.dwarf_section_length)
422    return true;
423#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
424  // Bare metal is statically linked, so no need to ask the dynamic loader
425  info.arm_section =        (uintptr_t)(&__exidx_start);
426  info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
427  _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
428                             (void *)info.arm_section, (void *)info.arm_section_length);
429  if (info.arm_section && info.arm_section_length)
430    return true;
431#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
432  HMODULE mods[1024];
433  HANDLE process = GetCurrentProcess();
434  DWORD needed;
435
436  if (!EnumProcessModules(process, mods, sizeof(mods), &needed)) {
437    DWORD err = GetLastError();
438    _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
439                               "returned error %d", (int)err);
440    return false;
441  }
442
443  for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
444    PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
445    PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
446    PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
447    PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
448    bool found_obj = false;
449    bool found_hdr = false;
450
451    info.dso_base = (uintptr_t)mods[i];
452    for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
453      uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
454      uintptr_t end = begin + pish->Misc.VirtualSize;
455      if (!strncmp((const char *)pish->Name, ".text",
456                   IMAGE_SIZEOF_SHORT_NAME)) {
457        if (targetAddr >= begin && targetAddr < end)
458          found_obj = true;
459      } else if (!strncmp((const char *)pish->Name, ".eh_frame",
460                          IMAGE_SIZEOF_SHORT_NAME)) {
461        info.dwarf_section = begin;
462        info.dwarf_section_length = pish->Misc.VirtualSize;
463        found_hdr = true;
464      }
465      if (found_obj && found_hdr)
466        return true;
467    }
468  }
469  return false;
470#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
471  // Don't even bother, since Windows has functions that do all this stuff
472  // for us.
473  (void)targetAddr;
474  (void)info;
475  return true;
476#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
477  // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
478  // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
479  int length = 0;
480  info.arm_section =
481      (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
482  info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
483  if (info.arm_section && info.arm_section_length)
484    return true;
485#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
486  struct dl_iterate_cb_data {
487    LocalAddressSpace *addressSpace;
488    UnwindInfoSections *sects;
489    uintptr_t targetAddr;
490  };
491
492  dl_iterate_cb_data cb_data = {this, &info, targetAddr};
493  int found = dl_iterate_phdr(
494      [](struct dl_phdr_info *pinfo, size_t, void *data) -> int {
495        auto cbdata = static_cast<dl_iterate_cb_data *>(data);
496        bool found_obj = false;
497        bool found_hdr = false;
498
499        assert(cbdata);
500        assert(cbdata->sects);
501
502        if (cbdata->targetAddr < pinfo->dlpi_addr) {
503          return false;
504        }
505
506#if !defined(Elf_Half)
507        typedef ElfW(Half) Elf_Half;
508#endif
509#if !defined(Elf_Phdr)
510        typedef ElfW(Phdr) Elf_Phdr;
511#endif
512#if !defined(Elf_Addr)
513        typedef ElfW(Addr) Elf_Addr;
514#endif
515
516        Elf_Addr image_base = pinfo->dlpi_addr;
517
518#if defined(__ANDROID__) && __ANDROID_API__ < 18
519        if (image_base == 0) {
520          // Normally, an image base of 0 indicates a non-PIE executable. On
521          // versions of Android prior to API 18, the dynamic linker reported a
522          // dlpi_addr of 0 for PIE executables. Compute the true image base
523          // using the PT_PHDR segment.
524          // See https://github.com/android/ndk/issues/505.
525          for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
526            const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
527            if (phdr->p_type == PT_PHDR) {
528              image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
529                  phdr->p_vaddr;
530              break;
531            }
532          }
533        }
534#endif
535
536 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
537  #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
538   #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
539  #endif
540        size_t object_length;
541
542        for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
543          const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
544          if (phdr->p_type == PT_LOAD) {
545            uintptr_t begin = image_base + phdr->p_vaddr;
546            uintptr_t end = begin + phdr->p_memsz;
547            if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
548              cbdata->sects->dso_base = begin;
549              object_length = phdr->p_memsz;
550              found_obj = true;
551            }
552          } else if (phdr->p_type == PT_GNU_EH_FRAME) {
553            EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
554            uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
555            cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
556            cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
557            found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
558                *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
559                hdrInfo);
560            if (found_hdr)
561              cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
562          }
563        }
564
565        if (found_obj && found_hdr) {
566          cbdata->sects->dwarf_section_length = object_length;
567          return true;
568        } else {
569          return false;
570        }
571 #else // defined(_LIBUNWIND_ARM_EHABI)
572        for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
573          const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
574          if (phdr->p_type == PT_LOAD) {
575            uintptr_t begin = image_base + phdr->p_vaddr;
576            uintptr_t end = begin + phdr->p_memsz;
577            if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
578              found_obj = true;
579          } else if (phdr->p_type == PT_ARM_EXIDX) {
580            uintptr_t exidx_start = image_base + phdr->p_vaddr;
581            cbdata->sects->arm_section = exidx_start;
582            cbdata->sects->arm_section_length = phdr->p_memsz;
583            found_hdr = true;
584          }
585        }
586        return found_obj && found_hdr;
587 #endif
588      },
589      &cb_data);
590  return static_cast<bool>(found);
591#endif
592
593  return false;
594}
595
596
597inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
598#ifdef __APPLE__
599  return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
600#else
601  // TO DO: if OS has way to dynamically register FDEs, check that.
602  (void)targetAddr;
603  (void)fde;
604  return false;
605#endif
606}
607
608inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
609                                                size_t bufLen,
610                                                unw_word_t *offset) {
611#if _LIBUNWIND_USE_DLADDR
612  Dl_info dyldInfo;
613  if (dladdr((void *)addr, &dyldInfo)) {
614    if (dyldInfo.dli_sname != NULL) {
615      snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
616      *offset = (addr - (pint_t) dyldInfo.dli_saddr);
617      return true;
618    }
619  }
620#else
621  (void)addr;
622  (void)buf;
623  (void)bufLen;
624  (void)offset;
625#endif
626  return false;
627}
628
629} // namespace libunwind
630
631#endif // __ADDRESSSPACE_HPP__
632