1 //===------------------------- AddressSpace.hpp ---------------------------===//
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
8 // Abstracts accessing local vs remote address spaces.
10 //===----------------------------------------------------------------------===//
12 #ifndef __ADDRESSSPACE_HPP__
13 #define __ADDRESSSPACE_HPP__
20 #ifndef _LIBUNWIND_USE_DLADDR
21 #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
22 #define _LIBUNWIND_USE_DLADDR 1
24 #define _LIBUNWIND_USE_DLADDR 0
28 #if _LIBUNWIND_USE_DLADDR
30 #if defined(__unix__) && defined(__ELF__) && defined(_LIBUNWIND_HAS_COMMENT_LIB_PRAGMA)
31 #pragma comment(lib, "dl")
36 #include <mach-o/getsect.h>
38 bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr
, void *&fde
);
42 #include "libunwind.h"
45 #include "EHHeaderParser.hpp"
46 #include "Registers.hpp"
50 struct dyld_unwind_sections
52 const struct mach_header
* mh
;
53 const void* dwarf_section
;
54 uintptr_t dwarf_section_length
;
55 const void* compact_unwind_section
;
56 uintptr_t compact_unwind_section_length
;
58 #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
59 && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
60 || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
61 // In 10.7.0 or later, libSystem.dylib implements this function.
62 extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections
*);
64 // In 10.6.x and earlier, we need to implement this functionality. Note
65 // that this requires a newer version of libmacho (from cctools) than is
66 // present in libSystem on 10.6.x (for getsectiondata).
67 static inline bool _dyld_find_unwind_sections(void* addr
,
68 dyld_unwind_sections
* info
) {
69 // Find mach-o image containing address.
71 if (!dladdr(addr
, &dlinfo
))
74 const struct mach_header_64
*mh
= (const struct mach_header_64
*)dlinfo
.dli_fbase
;
76 const struct mach_header
*mh
= (const struct mach_header
*)dlinfo
.dli_fbase
;
79 // Initialize the return struct
80 info
->mh
= (const struct mach_header
*)mh
;
81 info
->dwarf_section
= getsectiondata(mh
, "__TEXT", "__eh_frame", &info
->dwarf_section_length
);
82 info
->compact_unwind_section
= getsectiondata(mh
, "__TEXT", "__unwind_info", &info
->compact_unwind_section_length
);
84 if (!info
->dwarf_section
) {
85 info
->dwarf_section_length
= 0;
88 if (!info
->compact_unwind_section
) {
89 info
->compact_unwind_section_length
= 0;
96 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
98 // When statically linked on bare-metal, the symbols for the EH table are looked
99 // up without going through the dynamic loader.
101 // The following linker script may be used to produce the necessary sections and symbols.
102 // Unless the --eh-frame-hdr linker option is provided, the section is not generated
103 // and does not take space in the output file.
107 // __eh_frame_start = .;
108 // KEEP(*(.eh_frame))
109 // __eh_frame_end = .;
114 // KEEP(*(.eh_frame_hdr))
117 // __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
118 // __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
120 extern char __eh_frame_start
;
121 extern char __eh_frame_end
;
123 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
124 extern char __eh_frame_hdr_start
;
125 extern char __eh_frame_hdr_end
;
128 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
130 // When statically linked on bare-metal, the symbols for the EH table are looked
131 // up without going through the dynamic loader.
132 extern char __exidx_start
;
133 extern char __exidx_end
;
135 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
137 // ELF-based systems may use dl_iterate_phdr() to access sections
138 // containing unwinding information. The ElfW() macro for pointer-size
139 // independent ELF header traversal is not provided by <link.h> on some
140 // systems (e.g., FreeBSD). On these systems the data structures are
141 // just called Elf_XXX. Define ElfW() locally.
149 #define ElfW(type) Elf_##type
154 namespace libunwind
{
156 /// Used by findUnwindSections() to return info about needed sections.
157 struct UnwindInfoSections
{
158 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
159 defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
160 // No dso_base for SEH or ARM EHABI.
163 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
164 uintptr_t dwarf_section
;
165 uintptr_t dwarf_section_length
;
167 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
168 uintptr_t dwarf_index_section
;
169 uintptr_t dwarf_index_section_length
;
171 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
172 uintptr_t compact_unwind_section
;
173 uintptr_t compact_unwind_section_length
;
175 #if defined(_LIBUNWIND_ARM_EHABI)
176 uintptr_t arm_section
;
177 uintptr_t arm_section_length
;
182 /// LocalAddressSpace is used as a template parameter to UnwindCursor when
183 /// unwinding a thread in the same process. The wrappers compile away,
184 /// making local unwinds fast.
185 class _LIBUNWIND_HIDDEN LocalAddressSpace
{
187 typedef uintptr_t pint_t
;
188 typedef intptr_t sint_t
;
189 uint8_t get8(pint_t addr
) {
191 memcpy(&val
, (void *)addr
, sizeof(val
));
194 uint16_t get16(pint_t addr
) {
196 memcpy(&val
, (void *)addr
, sizeof(val
));
199 uint32_t get32(pint_t addr
) {
201 memcpy(&val
, (void *)addr
, sizeof(val
));
204 uint64_t get64(pint_t addr
) {
206 memcpy(&val
, (void *)addr
, sizeof(val
));
209 double getDouble(pint_t addr
) {
211 memcpy(&val
, (void *)addr
, sizeof(val
));
214 v128
getVector(pint_t addr
) {
216 memcpy(&val
, (void *)addr
, sizeof(val
));
219 uintptr_t getP(pint_t addr
);
220 uint64_t getRegister(pint_t addr
);
221 static uint64_t getULEB128(pint_t
&addr
, pint_t end
);
222 static int64_t getSLEB128(pint_t
&addr
, pint_t end
);
224 pint_t
getEncodedP(pint_t
&addr
, pint_t end
, uint8_t encoding
,
225 pint_t datarelBase
= 0);
226 bool findFunctionName(pint_t addr
, char *buf
, size_t bufLen
,
228 bool findUnwindSections(pint_t targetAddr
, UnwindInfoSections
&info
);
229 bool findOtherFDE(pint_t targetAddr
, pint_t
&fde
);
231 static LocalAddressSpace sThisAddressSpace
;
234 inline uintptr_t LocalAddressSpace::getP(pint_t addr
) {
235 #if __SIZEOF_POINTER__ == 8
242 inline uint64_t LocalAddressSpace::getRegister(pint_t addr
) {
243 #if __SIZEOF_POINTER__ == 8 || defined(__mips64)
250 /// Read a ULEB128 into a 64-bit word.
251 inline uint64_t LocalAddressSpace::getULEB128(pint_t
&addr
, pint_t end
) {
252 const uint8_t *p
= (uint8_t *)addr
;
253 const uint8_t *pend
= (uint8_t *)end
;
260 _LIBUNWIND_ABORT("truncated uleb128 expression");
264 if (bit
>= 64 || b
<< bit
>> bit
!= b
) {
265 _LIBUNWIND_ABORT("malformed uleb128 expression");
270 } while (*p
++ >= 0x80);
275 /// Read a SLEB128 into a 64-bit word.
276 inline int64_t LocalAddressSpace::getSLEB128(pint_t
&addr
, pint_t end
) {
277 const uint8_t *p
= (uint8_t *)addr
;
278 const uint8_t *pend
= (uint8_t *)end
;
284 _LIBUNWIND_ABORT("truncated sleb128 expression");
286 result
|= ((byte
& 0x7f) << bit
);
288 } while (byte
& 0x80);
289 // sign extend negative numbers
290 if ((byte
& 0x40) != 0)
291 result
|= (-1ULL) << bit
;
296 inline LocalAddressSpace::pint_t
297 LocalAddressSpace::getEncodedP(pint_t
&addr
, pint_t end
, uint8_t encoding
,
298 pint_t datarelBase
) {
299 pint_t startAddr
= addr
;
300 const uint8_t *p
= (uint8_t *)addr
;
304 switch (encoding
& 0x0F) {
310 case DW_EH_PE_uleb128
:
311 result
= (pint_t
)getULEB128(addr
, end
);
313 case DW_EH_PE_udata2
:
314 result
= get16(addr
);
318 case DW_EH_PE_udata4
:
319 result
= get32(addr
);
323 case DW_EH_PE_udata8
:
324 result
= (pint_t
)get64(addr
);
328 case DW_EH_PE_sleb128
:
329 result
= (pint_t
)getSLEB128(addr
, end
);
331 case DW_EH_PE_sdata2
:
332 // Sign extend from signed 16-bit value.
333 result
= (pint_t
)(int16_t)get16(addr
);
337 case DW_EH_PE_sdata4
:
338 // Sign extend from signed 32-bit value.
339 result
= (pint_t
)(int32_t)get32(addr
);
343 case DW_EH_PE_sdata8
:
344 result
= (pint_t
)get64(addr
);
349 _LIBUNWIND_ABORT("unknown pointer encoding");
352 // then add relative offset
353 switch (encoding
& 0x70) {
354 case DW_EH_PE_absptr
:
360 case DW_EH_PE_textrel
:
361 _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
363 case DW_EH_PE_datarel
:
364 // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
365 // default value of 0, and we abort in the event that someone calls this
366 // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
367 if (datarelBase
== 0)
368 _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
369 result
+= datarelBase
;
371 case DW_EH_PE_funcrel
:
372 _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
374 case DW_EH_PE_aligned
:
375 _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
378 _LIBUNWIND_ABORT("unknown pointer encoding");
382 if (encoding
& DW_EH_PE_indirect
)
383 result
= getP(result
);
388 inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr
,
389 UnwindInfoSections
&info
) {
391 dyld_unwind_sections dyldInfo
;
392 if (_dyld_find_unwind_sections((void *)targetAddr
, &dyldInfo
)) {
393 info
.dso_base
= (uintptr_t)dyldInfo
.mh
;
394 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
395 info
.dwarf_section
= (uintptr_t)dyldInfo
.dwarf_section
;
396 info
.dwarf_section_length
= dyldInfo
.dwarf_section_length
;
398 info
.compact_unwind_section
= (uintptr_t)dyldInfo
.compact_unwind_section
;
399 info
.compact_unwind_section_length
= dyldInfo
.compact_unwind_section_length
;
402 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
403 // Bare metal is statically linked, so no need to ask the dynamic loader
404 info
.dwarf_section_length
= (uintptr_t)(&__eh_frame_end
- &__eh_frame_start
);
405 info
.dwarf_section
= (uintptr_t)(&__eh_frame_start
);
406 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
407 (void *)info
.dwarf_section
, (void *)info
.dwarf_section_length
);
408 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
409 info
.dwarf_index_section
= (uintptr_t)(&__eh_frame_hdr_start
);
410 info
.dwarf_index_section_length
= (uintptr_t)(&__eh_frame_hdr_end
- &__eh_frame_hdr_start
);
411 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
412 (void *)info
.dwarf_index_section
, (void *)info
.dwarf_index_section_length
);
414 if (info
.dwarf_section_length
)
416 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
417 // Bare metal is statically linked, so no need to ask the dynamic loader
418 info
.arm_section
= (uintptr_t)(&__exidx_start
);
419 info
.arm_section_length
= (uintptr_t)(&__exidx_end
- &__exidx_start
);
420 _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
421 (void *)info
.arm_section
, (void *)info
.arm_section_length
);
422 if (info
.arm_section
&& info
.arm_section_length
)
424 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
426 HANDLE process
= GetCurrentProcess();
429 if (!EnumProcessModules(process
, mods
, sizeof(mods
), &needed
))
432 for (unsigned i
= 0; i
< (needed
/ sizeof(HMODULE
)); i
++) {
433 PIMAGE_DOS_HEADER pidh
= (PIMAGE_DOS_HEADER
)mods
[i
];
434 PIMAGE_NT_HEADERS pinh
= (PIMAGE_NT_HEADERS
)((BYTE
*)pidh
+ pidh
->e_lfanew
);
435 PIMAGE_FILE_HEADER pifh
= (PIMAGE_FILE_HEADER
)&pinh
->FileHeader
;
436 PIMAGE_SECTION_HEADER pish
= IMAGE_FIRST_SECTION(pinh
);
437 bool found_obj
= false;
438 bool found_hdr
= false;
440 info
.dso_base
= (uintptr_t)mods
[i
];
441 for (unsigned j
= 0; j
< pifh
->NumberOfSections
; j
++, pish
++) {
442 uintptr_t begin
= pish
->VirtualAddress
+ (uintptr_t)mods
[i
];
443 uintptr_t end
= begin
+ pish
->Misc
.VirtualSize
;
444 if (!strncmp((const char *)pish
->Name
, ".text",
445 IMAGE_SIZEOF_SHORT_NAME
)) {
446 if (targetAddr
>= begin
&& targetAddr
< end
)
448 } else if (!strncmp((const char *)pish
->Name
, ".eh_frame",
449 IMAGE_SIZEOF_SHORT_NAME
)) {
450 info
.dwarf_section
= begin
;
451 info
.dwarf_section_length
= pish
->Misc
.VirtualSize
;
454 if (found_obj
&& found_hdr
)
459 #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
460 // Don't even bother, since Windows has functions that do all this stuff
465 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) && \
466 (__ANDROID_API__ < 21)
469 (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr
)targetAddr
, &length
);
470 info
.arm_section_length
= (uintptr_t)length
;
471 if (info
.arm_section
&& info
.arm_section_length
)
473 #elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
474 struct dl_iterate_cb_data
{
475 LocalAddressSpace
*addressSpace
;
476 UnwindInfoSections
*sects
;
477 uintptr_t targetAddr
;
480 dl_iterate_cb_data cb_data
= {this, &info
, targetAddr
};
481 int found
= dl_iterate_phdr(
482 [](struct dl_phdr_info
*pinfo
, size_t, void *data
) -> int {
483 auto cbdata
= static_cast<dl_iterate_cb_data
*>(data
);
484 bool found_obj
= false;
485 bool found_hdr
= false;
488 assert(cbdata
->sects
);
490 if (cbdata
->targetAddr
< pinfo
->dlpi_addr
) {
494 #if !defined(Elf_Half)
495 typedef ElfW(Half
) Elf_Half
;
497 #if !defined(Elf_Phdr)
498 typedef ElfW(Phdr
) Elf_Phdr
;
500 #if !defined(Elf_Addr) && defined(__ANDROID__)
501 typedef ElfW(Addr
) Elf_Addr
;
504 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
505 #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
506 #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
508 size_t object_length
;
509 #if defined(__ANDROID__)
510 Elf_Addr image_base
=
512 ? reinterpret_cast<Elf_Addr
>(pinfo
->dlpi_phdr
) -
513 reinterpret_cast<const Elf_Phdr
*>(pinfo
->dlpi_phdr
)
518 for (Elf_Half i
= 0; i
< pinfo
->dlpi_phnum
; i
++) {
519 const Elf_Phdr
*phdr
= &pinfo
->dlpi_phdr
[i
];
520 if (phdr
->p_type
== PT_LOAD
) {
521 uintptr_t begin
= pinfo
->dlpi_addr
+ phdr
->p_vaddr
;
522 #if defined(__ANDROID__)
523 if (pinfo
->dlpi_addr
== 0 && phdr
->p_vaddr
< image_base
)
524 begin
= begin
+ image_base
;
526 uintptr_t end
= begin
+ phdr
->p_memsz
;
527 if (cbdata
->targetAddr
>= begin
&& cbdata
->targetAddr
< end
) {
528 cbdata
->sects
->dso_base
= begin
;
529 object_length
= phdr
->p_memsz
;
532 } else if (phdr
->p_type
== PT_GNU_EH_FRAME
) {
533 EHHeaderParser
<LocalAddressSpace
>::EHHeaderInfo hdrInfo
;
534 uintptr_t eh_frame_hdr_start
= pinfo
->dlpi_addr
+ phdr
->p_vaddr
;
535 #if defined(__ANDROID__)
536 if (pinfo
->dlpi_addr
== 0 && phdr
->p_vaddr
< image_base
)
537 eh_frame_hdr_start
= eh_frame_hdr_start
+ image_base
;
539 cbdata
->sects
->dwarf_index_section
= eh_frame_hdr_start
;
540 cbdata
->sects
->dwarf_index_section_length
= phdr
->p_memsz
;
541 found_hdr
= EHHeaderParser
<LocalAddressSpace
>::decodeEHHdr(
542 *cbdata
->addressSpace
, eh_frame_hdr_start
, phdr
->p_memsz
,
545 cbdata
->sects
->dwarf_section
= hdrInfo
.eh_frame_ptr
;
549 if (found_obj
&& found_hdr
) {
550 cbdata
->sects
->dwarf_section_length
= object_length
;
555 #else // defined(_LIBUNWIND_ARM_EHABI)
556 for (Elf_Half i
= 0; i
< pinfo
->dlpi_phnum
; i
++) {
557 const Elf_Phdr
*phdr
= &pinfo
->dlpi_phdr
[i
];
558 if (phdr
->p_type
== PT_LOAD
) {
559 uintptr_t begin
= pinfo
->dlpi_addr
+ phdr
->p_vaddr
;
560 uintptr_t end
= begin
+ phdr
->p_memsz
;
561 if (cbdata
->targetAddr
>= begin
&& cbdata
->targetAddr
< end
)
563 } else if (phdr
->p_type
== PT_ARM_EXIDX
) {
564 uintptr_t exidx_start
= pinfo
->dlpi_addr
+ phdr
->p_vaddr
;
565 cbdata
->sects
->arm_section
= exidx_start
;
566 cbdata
->sects
->arm_section_length
= phdr
->p_memsz
;
570 return found_obj
&& found_hdr
;
574 return static_cast<bool>(found
);
581 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr
, pint_t
&fde
) {
583 return checkKeyMgrRegisteredFDEs(targetAddr
, *((void**)&fde
));
585 // TO DO: if OS has way to dynamically register FDEs, check that.
592 inline bool LocalAddressSpace::findFunctionName(pint_t addr
, char *buf
,
594 unw_word_t
*offset
) {
595 #if _LIBUNWIND_USE_DLADDR
597 if (dladdr((void *)addr
, &dyldInfo
)) {
598 if (dyldInfo
.dli_sname
!= NULL
) {
599 snprintf(buf
, bufLen
, "%s", dyldInfo
.dli_sname
);
600 *offset
= (addr
- (pint_t
) dyldInfo
.dli_saddr
);
613 } // namespace libunwind
615 #endif // __ADDRESSSPACE_HPP__