Commit 1e66ac5755
Changed files (14)
lib/libunwind/include/libunwind.h
@@ -43,6 +43,12 @@
#define LIBUNWIND_AVAIL
#endif
+#if defined(_WIN32) && defined(__SEH__)
+ #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR __attribute__((__aligned__(16)))
+#else
+ #define LIBUNWIND_CURSOR_ALIGNMENT_ATTR
+#endif
+
/* error codes */
enum {
UNW_ESUCCESS = 0, /* no error */
@@ -68,7 +74,7 @@ typedef struct unw_context_t unw_context_t;
struct unw_cursor_t {
uint64_t data[_LIBUNWIND_CURSOR_SIZE];
-};
+} LIBUNWIND_CURSOR_ALIGNMENT_ATTR;
typedef struct unw_cursor_t unw_cursor_t;
typedef struct unw_addr_space *unw_addr_space_t;
lib/libunwind/src/AddressSpace.hpp
@@ -17,6 +17,12 @@
#include <stdlib.h>
#include <string.h>
+#include "libunwind.h"
+#include "config.h"
+#include "dwarf2.h"
+#include "EHHeaderParser.hpp"
+#include "Registers.hpp"
+
#ifndef _LIBUNWIND_USE_DLADDR
#if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
#define _LIBUNWIND_USE_DLADDR 1
@@ -39,19 +45,6 @@ struct EHABIIndexEntry {
};
#endif
-#ifdef __APPLE__
-#include <mach-o/getsect.h>
-namespace libunwind {
- bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
-}
-#endif
-
-#include "libunwind.h"
-#include "config.h"
-#include "dwarf2.h"
-#include "EHHeaderParser.hpp"
-#include "Registers.hpp"
-
#ifdef __APPLE__
struct dyld_unwind_sections
@@ -62,43 +55,9 @@ namespace libunwind {
const void* compact_unwind_section;
uintptr_t compact_unwind_section_length;
};
- #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
- && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
- || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
- // In 10.7.0 or later, libSystem.dylib implements this function.
- extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
- #else
- // In 10.6.x and earlier, we need to implement this functionality. Note
- // that this requires a newer version of libmacho (from cctools) than is
- // present in libSystem on 10.6.x (for getsectiondata).
- static inline bool _dyld_find_unwind_sections(void* addr,
- dyld_unwind_sections* info) {
- // Find mach-o image containing address.
- Dl_info dlinfo;
- if (!dladdr(addr, &dlinfo))
- return false;
-#if __LP64__
- const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
-#else
- const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
-#endif
- // Initialize the return struct
- info->mh = (const struct mach_header *)mh;
- info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
- info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
-
- if (!info->dwarf_section) {
- info->dwarf_section_length = 0;
- }
-
- if (!info->compact_unwind_section) {
- info->compact_unwind_section_length = 0;
- }
-
- return true;
- }
- #endif
+ // In 10.7.0 or later, libSystem.dylib implements this function.
+ extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
@@ -139,22 +98,15 @@ extern char __eh_frame_hdr_end;
extern char __exidx_start;
extern char __exidx_end;
-#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
-// ELF-based systems may use dl_iterate_phdr() to access sections
-// containing unwinding information. The ElfW() macro for pointer-size
-// independent ELF header traversal is not provided by <link.h> on some
-// systems (e.g., FreeBSD). On these systems the data structures are
-// just called Elf_XXX. Define ElfW() locally.
-#ifndef _WIN32
-#include <link.h>
-#else
#include <windows.h>
#include <psapi.h>
-#endif
-#if !defined(ElfW)
-#define ElfW(type) Elf_##type
-#endif
+
+#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR) || \
+ defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
+
+#include <link.h>
#endif
@@ -162,11 +114,15 @@ namespace libunwind {
/// Used by findUnwindSections() to return info about needed sections.
struct UnwindInfoSections {
-#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
- defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
- // No dso_base for SEH or ARM EHABI.
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || \
+ defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND) || \
+ defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
+ // No dso_base for SEH.
uintptr_t dso_base;
#endif
+#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
+ uintptr_t text_segment_length;
+#endif
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
uintptr_t dwarf_section;
uintptr_t dwarf_section_length;
@@ -290,11 +246,11 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
if (p == pend)
_LIBUNWIND_ABORT("truncated sleb128 expression");
byte = *p++;
- result |= ((byte & 0x7f) << bit);
+ result |= (uint64_t)(byte & 0x7f) << bit;
bit += 7;
} while (byte & 0x80);
// sign extend negative numbers
- if ((byte & 0x40) != 0)
+ if ((byte & 0x40) != 0 && bit < 64)
result |= (-1ULL) << bit;
addr = (pint_t) p;
return result;
@@ -392,23 +348,14 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
return result;
}
-#ifdef __APPLE__
-#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
-#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
-#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
-#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
-#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
-// Code inside findUnwindSections handles all these cases.
-//
-// Although the above ifdef chain is ugly, there doesn't seem to be a cleaner
-// way to handle it. The generalized boolean expression is:
-//
-// A OR (B AND C) OR (D AND C) OR (B AND E) OR (F AND E) OR (D AND G)
-//
-// Running it through various boolean expression simplifiers gives expressions
-// that don't help at all.
-#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+#if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
+// The ElfW() macro for pointer-size independent ELF header traversal is not
+// provided by <link.h> on some systems (e.g., FreeBSD). On these systems the
+// data structures are just called Elf_XXX. Define ElfW() locally.
+#if !defined(ElfW)
+ #define ElfW(type) Elf_##type
+#endif
#if !defined(Elf_Half)
typedef ElfW(Half) Elf_Half;
#endif
@@ -447,16 +394,12 @@ struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
uintptr_t targetAddr;
};
-#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
- #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
- #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
- #endif
-
#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
#include "FrameHeaderCache.hpp"
-// There should be just one of these per process.
-static FrameHeaderCache ProcessFrameHeaderCache;
+// Typically there is one cache per process, but when libunwind is built as a
+// hermetic static library, then each shared object may have its own cache.
+static FrameHeaderCache TheFrameHeaderCache;
#endif
static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
@@ -466,95 +409,93 @@ static bool checkAddrInSegment(const Elf_Phdr *phdr, size_t image_base,
uintptr_t end = begin + phdr->p_memsz;
if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
cbdata->sects->dso_base = begin;
- cbdata->sects->dwarf_section_length = phdr->p_memsz;
+ cbdata->sects->text_segment_length = phdr->p_memsz;
return true;
}
}
return false;
}
+static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base,
+ dl_iterate_cb_data *cbdata) {
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+ if (phdr->p_type == PT_GNU_EH_FRAME) {
+ EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
+ uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
+ cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
+ cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
+ if (EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
+ *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
+ hdrInfo)) {
+ // .eh_frame_hdr records the start of .eh_frame, but not its size.
+ // Rely on a zero terminator to find the end of the section.
+ cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
+ cbdata->sects->dwarf_section_length = UINTPTR_MAX;
+ return true;
+ }
+ }
+ return false;
+#elif defined(_LIBUNWIND_ARM_EHABI)
+ if (phdr->p_type == PT_ARM_EXIDX) {
+ uintptr_t exidx_start = image_base + phdr->p_vaddr;
+ cbdata->sects->arm_section = exidx_start;
+ cbdata->sects->arm_section_length = phdr->p_memsz;
+ return true;
+ }
+ return false;
+#else
+#error Need one of _LIBUNWIND_SUPPORT_DWARF_INDEX or _LIBUNWIND_ARM_EHABI
+#endif
+}
+
static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
size_t pinfo_size, void *data) {
auto cbdata = static_cast<dl_iterate_cb_data *>(data);
if (pinfo->dlpi_phnum == 0 || cbdata->targetAddr < pinfo->dlpi_addr)
return 0;
#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
- if (ProcessFrameHeaderCache.find(pinfo, pinfo_size, data))
+ if (TheFrameHeaderCache.find(pinfo, pinfo_size, data))
return 1;
+#else
+ // Avoid warning about unused variable.
+ (void)pinfo_size;
#endif
Elf_Addr image_base = calculateImageBase(pinfo);
- bool found_obj = false;
- bool found_hdr = false;
- // Third phdr is usually the executable phdr.
- if (pinfo->dlpi_phnum > 2)
- found_obj = checkAddrInSegment(&pinfo->dlpi_phdr[2], image_base, cbdata);
+ // Most shared objects seen in this callback function likely don't contain the
+ // target address, so optimize for that. Scan for a matching PT_LOAD segment
+ // first and bail when it isn't found.
+ bool found_text = false;
+ for (Elf_Half i = 0; i < pinfo->dlpi_phnum; ++i) {
+ if (checkAddrInSegment(&pinfo->dlpi_phdr[i], image_base, cbdata)) {
+ found_text = true;
+ break;
+ }
+ }
+ if (!found_text)
+ return 0;
- // PT_GNU_EH_FRAME is usually near the end. Iterate backward. We already know
- // that there is one or more phdrs.
+ // PT_GNU_EH_FRAME and PT_ARM_EXIDX are usually near the end. Iterate
+ // backward.
+ bool found_unwind = false;
for (Elf_Half i = pinfo->dlpi_phnum; i > 0; i--) {
const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i - 1];
- if (!found_hdr && phdr->p_type == PT_GNU_EH_FRAME) {
- EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
- uintptr_t eh_frame_hdr_start = image_base + phdr->p_vaddr;
- cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
- cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
- found_hdr = EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
- *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
- hdrInfo);
- if (found_hdr)
- cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
- } else if (!found_obj) {
- found_obj = checkAddrInSegment(phdr, image_base, cbdata);
- }
- if (found_obj && found_hdr) {
-#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
- ProcessFrameHeaderCache.add(cbdata->sects);
-#endif
- return 1;
+ if (checkForUnwindInfoSegment(phdr, image_base, cbdata)) {
+ found_unwind = true;
+ break;
}
}
- cbdata->sects->dwarf_section_length = 0;
- return 0;
-}
-
-#else // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
-// Given all the #ifdef's above, the code here is for
-// defined(LIBUNWIND_ARM_EHABI)
-
-static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo, size_t,
- void *data) {
- auto *cbdata = static_cast<dl_iterate_cb_data *>(data);
- bool found_obj = false;
- bool found_hdr = false;
-
- assert(cbdata);
- assert(cbdata->sects);
-
- if (cbdata->targetAddr < pinfo->dlpi_addr)
+ if (!found_unwind)
return 0;
- Elf_Addr image_base = calculateImageBase(pinfo);
-
- for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
- const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
- if (phdr->p_type == PT_LOAD) {
- uintptr_t begin = image_base + phdr->p_vaddr;
- uintptr_t end = begin + phdr->p_memsz;
- if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
- found_obj = true;
- } else if (phdr->p_type == PT_ARM_EXIDX) {
- uintptr_t exidx_start = image_base + phdr->p_vaddr;
- cbdata->sects->arm_section = exidx_start;
- cbdata->sects->arm_section_length = phdr->p_memsz;
- found_hdr = true;
- }
- }
- return found_obj && found_hdr;
+#if defined(_LIBUNWIND_USE_FRAME_HEADER_CACHE)
+ TheFrameHeaderCache.add(cbdata->sects);
+#endif
+ return 1;
}
-#endif // defined(LIBUNWIND_SUPPORT_DWARF_UNWIND)
-#endif // defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+
+#endif // defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
@@ -572,6 +513,7 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
return true;
}
#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
+ info.dso_base = 0;
// Bare metal is statically linked, so no need to ask the dynamic loader
info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
info.dwarf_section = (uintptr_t)(&__eh_frame_start);
@@ -638,16 +580,14 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
(void)targetAddr;
(void)info;
return true;
-#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__)
- // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
- // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
+#elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
int length = 0;
info.arm_section =
(uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
if (info.arm_section && info.arm_section_length)
return true;
-#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+#elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
dl_iterate_cb_data cb_data = {this, &info, targetAddr};
int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
return static_cast<bool>(found);
@@ -658,14 +598,10 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
-#ifdef __APPLE__
- return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
-#else
// TO DO: if OS has way to dynamically register FDEs, check that.
(void)targetAddr;
(void)fde;
return false;
-#endif
}
inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
lib/libunwind/src/assembly.h
@@ -25,9 +25,6 @@
#define PPC64_OFFS_VRSAVE 304
#define PPC64_OFFS_FP 312
#define PPC64_OFFS_V 824
-#ifdef _ARCH_PWR8
-#define PPC64_HAS_VMX
-#endif
#elif defined(__APPLE__) && defined(__aarch64__)
#define SEPARATOR %%
#else
@@ -48,6 +45,24 @@
#define PPC64_OPD2
#endif
+#if defined(__ARM_FEATURE_BTI_DEFAULT)
+ .pushsection ".note.gnu.property", "a" SEPARATOR \
+ .balign 8 SEPARATOR \
+ .long 4 SEPARATOR \
+ .long 0x10 SEPARATOR \
+ .long 0x5 SEPARATOR \
+ .asciz "GNU" SEPARATOR \
+ .long 0xc0000000 SEPARATOR /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ \
+ .long 4 SEPARATOR \
+ .long 3 SEPARATOR /* GNU_PROPERTY_AARCH64_FEATURE_1_BTI AND */ \
+ /* GNU_PROPERTY_AARCH64_FEATURE_1_PAC */ \
+ .long 0 SEPARATOR \
+ .popsection SEPARATOR
+#define AARCH64_BTI bti c
+#else
+#define AARCH64_BTI
+#endif
+
#define GLUE2(a, b) a ## b
#define GLUE(a, b) GLUE2(a, b)
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
@@ -144,7 +159,8 @@
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
PPC64_OPD1 \
SYMBOL_NAME(name): \
- PPC64_OPD2
+ PPC64_OPD2 \
+ AARCH64_BTI
#if defined(__arm__)
#if !defined(__ARM_ARCH)
lib/libunwind/src/config.h
@@ -18,23 +18,15 @@
#include <stdint.h>
#include <stdlib.h>
-// Define static_assert() unless already defined by compiler.
-#ifndef __has_feature
- #define __has_feature(__x) 0
-#endif
-#if !(__has_feature(cxx_static_assert)) && !defined(static_assert)
- #define static_assert(__b, __m) \
- extern int compile_time_assert_failed[ ( __b ) ? 1 : -1 ] \
- __attribute__( ( unused ) );
-#endif
+#include <__libunwind_config.h>
// Platform specific configuration defines.
#ifdef __APPLE__
#if defined(FOR_DYLD)
- #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+ #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
#else
- #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
- #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
+ #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
+ #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
#endif
#elif defined(_WIN32)
#ifdef __SEH__
@@ -42,8 +34,19 @@
#else
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
#endif
+#elif defined(_LIBUNWIND_IS_BAREMETAL)
+ #if !defined(_LIBUNWIND_ARM_EHABI)
+ #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
+ #define _LIBUNWIND_SUPPORT_DWARF_INDEX 1
+ #endif
+#elif defined(__BIONIC__) && defined(_LIBUNWIND_ARM_EHABI)
+ // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
+ // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
+ #define _LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX 1
#else
- #if defined(__ARM_DWARF_EH__) || !defined(__arm__)
+ // Assume an ELF system with a dl_iterate_phdr function.
+ #define _LIBUNWIND_USE_DL_ITERATE_PHDR 1
+ #if !defined(_LIBUNWIND_ARM_EHABI)
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 1
#endif
@@ -91,6 +94,8 @@
#error Unsupported target
#endif
+// Apple/armv7k defaults to DWARF/Compact unwinding, but its libunwind also
+// needs to include the SJLJ APIs.
#if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__)
#define _LIBUNWIND_BUILD_SJLJ_APIS
#endif
@@ -111,8 +116,27 @@
#endif
#endif
-#if defined(__powerpc64__) && defined(_ARCH_PWR8)
-#define PPC64_HAS_VMX
+#ifndef _LIBUNWIND_REMEMBER_HEAP_ALLOC
+#if defined(_LIBUNWIND_REMEMBER_STACK_ALLOC) || defined(__APPLE__) || \
+ defined(__linux__) || defined(__ANDROID__) || defined(__MINGW32__) || \
+ defined(_LIBUNWIND_IS_BAREMETAL)
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) alloca(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr) \
+ do { \
+ } while (0)
+#elif defined(_WIN32)
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) _malloca(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr) _freea(_ptr)
+#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED
+#else
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) malloc(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr) free(_ptr)
+#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED
+#endif
+#else /* _LIBUNWIND_REMEMBER_HEAP_ALLOC */
+#define _LIBUNWIND_REMEMBER_ALLOC(_size) malloc(_size)
+#define _LIBUNWIND_REMEMBER_FREE(_ptr) free(_ptr)
+#define _LIBUNWIND_REMEMBER_CLEANUP_NEEDED
#endif
#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL)
lib/libunwind/src/DwarfInstructions.hpp
@@ -93,7 +93,8 @@ typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
case CFI_Parser<A>::kRegisterInRegister:
return registers.getRegister((int)savedReg.value);
-
+ case CFI_Parser<A>::kRegisterUndefined:
+ return 0;
case CFI_Parser<A>::kRegisterUnused:
case CFI_Parser<A>::kRegisterOffsetFromCFA:
// FIX ME
@@ -117,6 +118,7 @@ double DwarfInstructions<A, R>::getSavedFloatRegister(
case CFI_Parser<A>::kRegisterIsExpression:
case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterUndefined:
case CFI_Parser<A>::kRegisterOffsetFromCFA:
case CFI_Parser<A>::kRegisterInRegister:
// FIX ME
@@ -140,6 +142,7 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister(
case CFI_Parser<A>::kRegisterIsExpression:
case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterUndefined:
case CFI_Parser<A>::kRegisterOffsetFromCFA:
case CFI_Parser<A>::kRegisterInRegister:
// FIX ME
@@ -190,6 +193,10 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
prolog.savedRegisters[i]));
else
return UNW_EBADREG;
+ } else if (i == (int)cieInfo.returnAddressRegister) {
+ // Leaf function keeps the return address in register and there is no
+ // explicit intructions how to restore it.
+ returnAddress = registers.getRegister(cieInfo.returnAddressRegister);
}
}
lib/libunwind/src/DwarfParser.hpp
@@ -69,6 +69,7 @@ public:
};
enum RegisterSavedWhere {
kRegisterUnused,
+ kRegisterUndefined,
kRegisterInCFA,
kRegisterOffsetFromCFA,
kRegisterInRegister,
@@ -87,9 +88,6 @@ public:
int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
int64_t cfaExpression; // CFA = expression
uint32_t spExtraArgSize;
- uint32_t codeOffsetAtStackDecrement;
- bool registersInOtherRegisters;
- bool sameValueUsed;
RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
enum class InitializeTime { kLazy, kNormal };
@@ -134,8 +132,26 @@ public:
PrologInfo info;
};
+ struct RememberStack {
+ PrologInfoStackEntry *entry;
+ RememberStack() : entry(nullptr) {}
+ ~RememberStack() {
+#if defined(_LIBUNWIND_REMEMBER_CLEANUP_NEEDED)
+ // Clean up rememberStack. Even in the case where every
+ // DW_CFA_remember_state is paired with a DW_CFA_restore_state,
+ // parseInstructions can skip restore opcodes if it reaches the target PC
+ // and stops interpreting, so we have to make sure we don't leak memory.
+ while (entry) {
+ PrologInfoStackEntry *next = entry->next;
+ _LIBUNWIND_REMEMBER_FREE(entry);
+ entry = next;
+ }
+#endif
+ }
+ };
+
static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
- uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
+ uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
CIE_Info *cieInfo);
static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
FDE_Info *fdeInfo, CIE_Info *cieInfo);
@@ -144,13 +160,6 @@ public:
int arch, PrologInfo *results);
static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
-
-private:
- static bool parseInstructions(A &addressSpace, pint_t instructions,
- pint_t instructionsEnd, const CIE_Info &cieInfo,
- pint_t pcoffset,
- PrologInfoStackEntry *&rememberStack, int arch,
- PrologInfo *results);
};
/// Parse a FDE into a CIE_Info and an FDE_Info
@@ -166,7 +175,7 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
p += 8;
}
if (cfiLength == 0)
- return "FDE has zero length"; // end marker
+ return "FDE has zero length"; // zero terminator
uint32_t ciePointer = addressSpace.get32(p);
if (ciePointer == 0)
return "FDE is really a CIE"; // this is a CIE not an FDE
@@ -211,11 +220,13 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
/// Scan an eh_frame section to find an FDE for a pc
template <typename A>
bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
- uint32_t sectionLength, pint_t fdeHint,
+ uintptr_t sectionLength, pint_t fdeHint,
FDE_Info *fdeInfo, CIE_Info *cieInfo) {
//fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
- const pint_t ehSectionEnd = p + sectionLength;
+ const pint_t ehSectionEnd = (sectionLength == UINTPTR_MAX)
+ ? static_cast<pint_t>(-1)
+ : (ehSectionStart + sectionLength);
while (p < ehSectionEnd) {
pint_t currentCFI = p;
//fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
@@ -227,7 +238,7 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
p += 8;
}
if (cfiLength == 0)
- return false; // end marker
+ return false; // zero terminator
uint32_t id = addressSpace.get32(p);
if (id == 0) {
// Skip over CIEs.
@@ -336,7 +347,8 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
// parse data alignment factor
cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
// parse return address register
- uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
+ uint64_t raReg = (version == 1) ? addressSpace.get8(p++)
+ : addressSpace.getULEB128(p, cieContentEnd);
assert(raReg < 255 && "return address register too large");
cieInfo->returnAddressRegister = (uint8_t)raReg;
// parse augmentation data based on augmentation string
@@ -390,418 +402,409 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC,
int arch, PrologInfo *results) {
- PrologInfoStackEntry *rememberStack = NULL;
-
- // parse CIE then FDE instructions
- bool returnValue =
- parseInstructions(addressSpace, cieInfo.cieInstructions,
- cieInfo.cieStart + cieInfo.cieLength, cieInfo,
- (pint_t)(-1), rememberStack, arch, results) &&
- parseInstructions(addressSpace, fdeInfo.fdeInstructions,
- fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
- upToPC - fdeInfo.pcStart, rememberStack, arch, results);
-
-#if !defined(_LIBUNWIND_NO_HEAP)
- // Clean up rememberStack. Even in the case where every DW_CFA_remember_state
- // is paired with a DW_CFA_restore_state, parseInstructions can skip restore
- // opcodes if it reaches the target PC and stops interpreting, so we have to
- // make sure we don't leak memory.
- while (rememberStack) {
- PrologInfoStackEntry *next = rememberStack->next;
- free(rememberStack);
- rememberStack = next;
- }
-#endif
-
- return returnValue;
-}
+ // Alloca is used for the allocation of the rememberStack entries. It removes
+ // the dependency on new/malloc but the below for loop can not be refactored
+ // into functions. Entry could be saved during the processing of a CIE and
+ // restored by an FDE.
+ RememberStack rememberStack;
+
+ struct ParseInfo {
+ pint_t instructions;
+ pint_t instructionsEnd;
+ pint_t pcoffset;
+ };
-/// "run" the DWARF instructions
-template <typename A>
-bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
- pint_t instructionsEnd,
- const CIE_Info &cieInfo, pint_t pcoffset,
- PrologInfoStackEntry *&rememberStack,
- int arch, PrologInfo *results) {
- pint_t p = instructions;
- pint_t codeOffset = 0;
- // initialState initialized as registers in results are modified. Use
- // PrologInfo accessor functions to avoid reading uninitialized data.
- PrologInfo initialState(PrologInfo::InitializeTime::kLazy);
-
- _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
- static_cast<uint64_t>(instructionsEnd));
-
- // see DWARF Spec, section 6.4.2 for details on unwind opcodes
- while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
- uint64_t reg;
- uint64_t reg2;
- int64_t offset;
- uint64_t length;
- uint8_t opcode = addressSpace.get8(p);
- uint8_t operand;
-#if !defined(_LIBUNWIND_NO_HEAP)
- PrologInfoStackEntry *entry;
-#endif
- ++p;
- switch (opcode) {
- case DW_CFA_nop:
- _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
- break;
- case DW_CFA_set_loc:
- codeOffset =
- addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
- break;
- case DW_CFA_advance_loc1:
- codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
- p += 1;
- _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
- static_cast<uint64_t>(codeOffset));
- break;
- case DW_CFA_advance_loc2:
- codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
- p += 2;
- _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
- static_cast<uint64_t>(codeOffset));
- break;
- case DW_CFA_advance_loc4:
- codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
- p += 4;
- _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
- static_cast<uint64_t>(codeOffset));
- break;
- case DW_CFA_offset_extended:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
- * cieInfo.dataAlignFactor;
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
- return false;
- }
- results->setRegister(reg, kRegisterInCFA, offset, initialState);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
- "offset=%" PRId64 ")\n",
- reg, offset);
- break;
- case DW_CFA_restore_extended:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
- return false;
- }
- results->restoreRegisterToInitialState(reg, initialState);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
- break;
- case DW_CFA_undefined:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_undefined DWARF unwind, reg too big");
- return false;
- }
- results->setRegisterLocation(reg, kRegisterUnused, initialState);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
- break;
- case DW_CFA_same_value:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_same_value DWARF unwind, reg too big");
- return false;
- }
- // <rdar://problem/8456377> DW_CFA_same_value unsupported
- // "same value" means register was stored in frame, but its current
- // value has not changed, so no need to restore from frame.
- // We model this as if the register was never saved.
- results->setRegisterLocation(reg, kRegisterUnused, initialState);
- // set flag to disable conversion to compact unwind
- results->sameValueUsed = true;
- _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
- break;
- case DW_CFA_register:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- reg2 = addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_register DWARF unwind, reg too big");
- return false;
- }
- if (reg2 > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_register DWARF unwind, reg2 too big");
- return false;
- }
- results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,
- initialState);
- // set flag to disable conversion to compact unwind
- results->registersInOtherRegisters = true;
- _LIBUNWIND_TRACE_DWARF(
- "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
- break;
-#if !defined(_LIBUNWIND_NO_HEAP)
- case DW_CFA_remember_state:
- // avoid operator new, because that would be an upward dependency
- entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
- if (entry != NULL) {
- entry->next = rememberStack;
- entry->info = *results;
- rememberStack = entry;
- } else {
- return false;
- }
- _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
- break;
- case DW_CFA_restore_state:
- if (rememberStack != NULL) {
- PrologInfoStackEntry *top = rememberStack;
- *results = top->info;
- rememberStack = top->next;
- free((char *)top);
- } else {
- return false;
- }
- _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
- break;
-#endif
- case DW_CFA_def_cfa:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
- return false;
- }
- results->cfaRegister = (uint32_t)reg;
- results->cfaRegisterOffset = (int32_t)offset;
- _LIBUNWIND_TRACE_DWARF(
- "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
- break;
- case DW_CFA_def_cfa_register:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
- return false;
- }
- results->cfaRegister = (uint32_t)reg;
- _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
- break;
- case DW_CFA_def_cfa_offset:
- results->cfaRegisterOffset = (int32_t)
- addressSpace.getULEB128(p, instructionsEnd);
- results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
- _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
- results->cfaRegisterOffset);
- break;
- case DW_CFA_def_cfa_expression:
- results->cfaRegister = 0;
- results->cfaExpression = (int64_t)p;
- length = addressSpace.getULEB128(p, instructionsEnd);
- assert(length < static_cast<pint_t>(~0) && "pointer overflow");
- p += static_cast<pint_t>(length);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
- ", length=%" PRIu64 ")\n",
- results->cfaExpression, length);
- break;
- case DW_CFA_expression:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_expression DWARF unwind, reg too big");
- return false;
- }
- results->setRegister(reg, kRegisterAtExpression, (int64_t)p,
- initialState);
- length = addressSpace.getULEB128(p, instructionsEnd);
- assert(length < static_cast<pint_t>(~0) && "pointer overflow");
- p += static_cast<pint_t>(length);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
- "expression=0x%" PRIx64 ", "
- "length=%" PRIu64 ")\n",
- reg, results->savedRegisters[reg].value, length);
- break;
- case DW_CFA_offset_extended_sf:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
- return false;
- }
- offset =
- addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
- results->setRegister(reg, kRegisterInCFA, offset, initialState);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
- "offset=%" PRId64 ")\n",
- reg, offset);
- break;
- case DW_CFA_def_cfa_sf:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- offset =
- addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
- return false;
- }
- results->cfaRegister = (uint32_t)reg;
- results->cfaRegisterOffset = (int32_t)offset;
- _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
- "offset=%" PRId64 ")\n",
- reg, offset);
- break;
- case DW_CFA_def_cfa_offset_sf:
- results->cfaRegisterOffset = (int32_t)
- (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
- results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
- _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
- results->cfaRegisterOffset);
- break;
- case DW_CFA_val_offset:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG(
- "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
- ") out of range\n",
- reg);
- return false;
- }
- offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
- * cieInfo.dataAlignFactor;
- results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
- "offset=%" PRId64 "\n",
- reg, offset);
- break;
- case DW_CFA_val_offset_sf:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
- return false;
- }
- offset =
- addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
- results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
- "offset=%" PRId64 "\n",
- reg, offset);
- break;
- case DW_CFA_val_expression:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0(
- "malformed DW_CFA_val_expression DWARF unwind, reg too big");
- return false;
- }
- results->setRegister(reg, kRegisterIsExpression, (int64_t)p,
- initialState);
- length = addressSpace.getULEB128(p, instructionsEnd);
- assert(length < static_cast<pint_t>(~0) && "pointer overflow");
- p += static_cast<pint_t>(length);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
- "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
- reg, results->savedRegisters[reg].value, length);
- break;
- case DW_CFA_GNU_args_size:
- length = addressSpace.getULEB128(p, instructionsEnd);
- results->spExtraArgSize = (uint32_t)length;
- _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
- break;
- case DW_CFA_GNU_negative_offset_extended:
- reg = addressSpace.getULEB128(p, instructionsEnd);
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
- "unwind, reg too big");
- return false;
+ ParseInfo parseInfoArray[] = {
+ {cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength,
+ (pint_t)(-1)},
+ {fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength,
+ upToPC - fdeInfo.pcStart}};
+
+ for (const auto &info : parseInfoArray) {
+ pint_t p = info.instructions;
+ pint_t instructionsEnd = info.instructionsEnd;
+ pint_t pcoffset = info.pcoffset;
+ pint_t codeOffset = 0;
+
+ // initialState initialized as registers in results are modified. Use
+ // PrologInfo accessor functions to avoid reading uninitialized data.
+ PrologInfo initialState(PrologInfo::InitializeTime::kLazy);
+
+ _LIBUNWIND_TRACE_DWARF("parseFDEInstructions(instructions=0x%0" PRIx64
+ ")\n",
+ static_cast<uint64_t>(instructionsEnd));
+
+ // see DWARF Spec, section 6.4.2 for details on unwind opcodes
+ while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
+ uint64_t reg;
+ uint64_t reg2;
+ int64_t offset;
+ uint64_t length;
+ uint8_t opcode = addressSpace.get8(p);
+ uint8_t operand;
+
+ ++p;
+ switch (opcode) {
+ case DW_CFA_nop:
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
+ break;
+ case DW_CFA_set_loc:
+ codeOffset = addressSpace.getEncodedP(p, instructionsEnd,
+ cieInfo.pointerEncoding);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
+ break;
+ case DW_CFA_advance_loc1:
+ codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
+ p += 1;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
+ static_cast<uint64_t>(codeOffset));
+ break;
+ case DW_CFA_advance_loc2:
+ codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
+ p += 2;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
+ static_cast<uint64_t>(codeOffset));
+ break;
+ case DW_CFA_advance_loc4:
+ codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
+ p += 4;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
+ static_cast<uint64_t>(codeOffset));
+ break;
+ case DW_CFA_offset_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+ cieInfo.dataAlignFactor;
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
+ return false;
+ }
+ results->setRegister(reg, kRegisterInCFA, offset, initialState);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
+ "offset=%" PRId64 ")\n",
+ reg, offset);
+ break;
+ case DW_CFA_restore_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
+ return false;
+ }
+ results->restoreRegisterToInitialState(reg, initialState);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n",
+ reg);
+ break;
+ case DW_CFA_undefined:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_undefined DWARF unwind, reg too big");
+ return false;
+ }
+ results->setRegisterLocation(reg, kRegisterUndefined, initialState);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
+ break;
+ case DW_CFA_same_value:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_same_value DWARF unwind, reg too big");
+ return false;
+ }
+ // <rdar://problem/8456377> DW_CFA_same_value unsupported
+ // "same value" means register was stored in frame, but its current
+ // value has not changed, so no need to restore from frame.
+ // We model this as if the register was never saved.
+ results->setRegisterLocation(reg, kRegisterUnused, initialState);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
+ break;
+ case DW_CFA_register:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ reg2 = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_register DWARF unwind, reg too big");
+ return false;
+ }
+ if (reg2 > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_register DWARF unwind, reg2 too big");
+ return false;
+ }
+ results->setRegister(reg, kRegisterInRegister, (int64_t)reg2,
+ initialState);
+ _LIBUNWIND_TRACE_DWARF(
+ "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
+ break;
+ case DW_CFA_remember_state: {
+ // Avoid operator new because that would be an upward dependency.
+ // Avoid malloc because it needs heap allocation.
+ PrologInfoStackEntry *entry =
+ (PrologInfoStackEntry *)_LIBUNWIND_REMEMBER_ALLOC(
+ sizeof(PrologInfoStackEntry));
+ if (entry != NULL) {
+ entry->next = rememberStack.entry;
+ entry->info = *results;
+ rememberStack.entry = entry;
+ } else {
+ return false;
+ }
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
+ break;
}
- offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
- * cieInfo.dataAlignFactor;
- results->setRegister(reg, kRegisterInCFA, -offset, initialState);
- _LIBUNWIND_TRACE_DWARF(
- "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
- break;
+ case DW_CFA_restore_state:
+ if (rememberStack.entry != NULL) {
+ PrologInfoStackEntry *top = rememberStack.entry;
+ *results = top->info;
+ rememberStack.entry = top->next;
+ _LIBUNWIND_REMEMBER_FREE(top);
+ } else {
+ return false;
+ }
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
+ break;
+ case DW_CFA_def_cfa:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
+ return false;
+ }
+ results->cfaRegister = (uint32_t)reg;
+ results->cfaRegisterOffset = (int32_t)offset;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64
+ ")\n",
+ reg, offset);
+ break;
+ case DW_CFA_def_cfa_register:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
+ return false;
+ }
+ results->cfaRegister = (uint32_t)reg;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
+ break;
+ case DW_CFA_def_cfa_offset:
+ results->cfaRegisterOffset =
+ (int32_t)addressSpace.getULEB128(p, instructionsEnd);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
+ results->cfaRegisterOffset);
+ break;
+ case DW_CFA_def_cfa_expression:
+ results->cfaRegister = 0;
+ results->cfaExpression = (int64_t)p;
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+ p += static_cast<pint_t>(length);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
+ ", length=%" PRIu64 ")\n",
+ results->cfaExpression, length);
+ break;
+ case DW_CFA_expression:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_expression DWARF unwind, reg too big");
+ return false;
+ }
+ results->setRegister(reg, kRegisterAtExpression, (int64_t)p,
+ initialState);
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+ p += static_cast<pint_t>(length);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
+ "expression=0x%" PRIx64 ", "
+ "length=%" PRIu64 ")\n",
+ reg, results->savedRegisters[reg].value, length);
+ break;
+ case DW_CFA_offset_extended_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
+ return false;
+ }
+ offset = addressSpace.getSLEB128(p, instructionsEnd) *
+ cieInfo.dataAlignFactor;
+ results->setRegister(reg, kRegisterInCFA, offset, initialState);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
+ "offset=%" PRId64 ")\n",
+ reg, offset);
+ break;
+ case DW_CFA_def_cfa_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ offset = addressSpace.getSLEB128(p, instructionsEnd) *
+ cieInfo.dataAlignFactor;
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
+ return false;
+ }
+ results->cfaRegister = (uint32_t)reg;
+ results->cfaRegisterOffset = (int32_t)offset;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
+ "offset=%" PRId64 ")\n",
+ reg, offset);
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ results->cfaRegisterOffset =
+ (int32_t)(addressSpace.getSLEB128(p, instructionsEnd) *
+ cieInfo.dataAlignFactor);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
+ results->cfaRegisterOffset);
+ break;
+ case DW_CFA_val_offset:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG(
+ "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
+ ") out of range\n",
+ reg);
+ return false;
+ }
+ offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+ cieInfo.dataAlignFactor;
+ results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
+ "offset=%" PRId64 "\n",
+ reg, offset);
+ break;
+ case DW_CFA_val_offset_sf:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
+ return false;
+ }
+ offset = addressSpace.getSLEB128(p, instructionsEnd) *
+ cieInfo.dataAlignFactor;
+ results->setRegister(reg, kRegisterOffsetFromCFA, offset, initialState);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
+ "offset=%" PRId64 "\n",
+ reg, offset);
+ break;
+ case DW_CFA_val_expression:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_val_expression DWARF unwind, reg too big");
+ return false;
+ }
+ results->setRegister(reg, kRegisterIsExpression, (int64_t)p,
+ initialState);
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+ p += static_cast<pint_t>(length);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
+ "expression=0x%" PRIx64 ", length=%" PRIu64
+ ")\n",
+ reg, results->savedRegisters[reg].value, length);
+ break;
+ case DW_CFA_GNU_args_size:
+ length = addressSpace.getULEB128(p, instructionsEnd);
+ results->spExtraArgSize = (uint32_t)length;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
+ break;
+ case DW_CFA_GNU_negative_offset_extended:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
+ "unwind, reg too big");
+ return false;
+ }
+ offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+ cieInfo.dataAlignFactor;
+ results->setRegister(reg, kRegisterInCFA, -offset, initialState);
+ _LIBUNWIND_TRACE_DWARF(
+ "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
+ break;
#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
- // The same constant is used to represent different instructions on
- // AArch64 (negate_ra_state) and SPARC (window_save).
- static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
- "uses the same constant");
- case DW_CFA_AARCH64_negate_ra_state:
- switch (arch) {
+ // The same constant is used to represent different instructions on
+ // AArch64 (negate_ra_state) and SPARC (window_save).
+ static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
+ "uses the same constant");
+ case DW_CFA_AARCH64_negate_ra_state:
+ switch (arch) {
#if defined(_LIBUNWIND_TARGET_AARCH64)
case REGISTERS_ARM64: {
int64_t value =
results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^ 0x1;
- results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value, initialState);
+ results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value,
+ initialState);
_LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
} break;
#endif
#if defined(_LIBUNWIND_TARGET_SPARC)
- // case DW_CFA_GNU_window_save:
- case REGISTERS_SPARC:
- _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
- for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
- results->setRegister(reg, kRegisterInRegister,
- ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,
- initialState);
- }
+ // case DW_CFA_GNU_window_save:
+ case REGISTERS_SPARC:
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
+ for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
+ results->setRegister(reg, kRegisterInRegister,
+ ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0,
+ initialState);
+ }
- for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
- results->setRegister(reg, kRegisterInCFA,
- ((int64_t)reg - UNW_SPARC_L0) * 4, initialState);
+ for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
+ results->setRegister(reg, kRegisterInCFA,
+ ((int64_t)reg - UNW_SPARC_L0) * 4,
+ initialState);
+ }
+ break;
+#endif
}
break;
-#endif
- }
- break;
#else
- (void)arch;
+ (void)arch;
#endif
- default:
- operand = opcode & 0x3F;
- switch (opcode & 0xC0) {
- case DW_CFA_offset:
- reg = operand;
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
- ") out of range",
- reg);
- return false;
- }
- offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
- * cieInfo.dataAlignFactor;
- results->setRegister(reg, kRegisterInCFA, offset, initialState);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
- operand, offset);
- break;
- case DW_CFA_advance_loc:
- codeOffset += operand * cieInfo.codeAlignFactor;
- _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
- static_cast<uint64_t>(codeOffset));
- break;
- case DW_CFA_restore:
- reg = operand;
- if (reg > kMaxRegisterNumber) {
- _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
- ") out of range",
- reg);
+ default:
+ operand = opcode & 0x3F;
+ switch (opcode & 0xC0) {
+ case DW_CFA_offset:
+ reg = operand;
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
+ ") out of range",
+ reg);
+ return false;
+ }
+ offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) *
+ cieInfo.dataAlignFactor;
+ results->setRegister(reg, kRegisterInCFA, offset, initialState);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
+ operand, offset);
+ break;
+ case DW_CFA_advance_loc:
+ codeOffset += operand * cieInfo.codeAlignFactor;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
+ static_cast<uint64_t>(codeOffset));
+ break;
+ case DW_CFA_restore:
+ reg = operand;
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG(
+ "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
+ ") out of range",
+ reg);
+ return false;
+ }
+ results->restoreRegisterToInitialState(reg, initialState);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
+ static_cast<uint64_t>(operand));
+ break;
+ default:
+ _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
return false;
}
- results->restoreRegisterToInitialState(reg, initialState);
- _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
- static_cast<uint64_t>(operand));
- break;
- default:
- _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
- return false;
}
}
}
-
return true;
}
lib/libunwind/src/FrameHeaderCache.hpp
@@ -32,7 +32,7 @@
class _LIBUNWIND_HIDDEN FrameHeaderCache {
struct CacheEntry {
uintptr_t LowPC() { return Info.dso_base; };
- uintptr_t HighPC() { return Info.dso_base + Info.dwarf_section_length; };
+ uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; };
UnwindInfoSections Info;
CacheEntry *Next;
};
lib/libunwind/src/Registers.hpp
@@ -39,6 +39,8 @@ enum {
};
#if defined(_LIBUNWIND_TARGET_I386)
+class _LIBUNWIND_HIDDEN Registers_x86;
+extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);
/// Registers_x86 holds the register state of a thread in a 32-bit intel
/// process.
class _LIBUNWIND_HIDDEN Registers_x86 {
@@ -56,7 +58,7 @@ public:
v128 getVectorRegister(int num) const;
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
- void jumpto();
+ void jumpto() { __libunwind_Registers_x86_jumpto(this); }
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; }
static int getArch() { return REGISTERS_X86; }
@@ -248,6 +250,8 @@ inline void Registers_x86::setVectorRegister(int, v128) {
#if defined(_LIBUNWIND_TARGET_X86_64)
/// Registers_x86_64 holds the register state of a thread in a 64-bit intel
/// process.
+class _LIBUNWIND_HIDDEN Registers_x86_64;
+extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *);
class _LIBUNWIND_HIDDEN Registers_x86_64 {
public:
Registers_x86_64();
@@ -263,7 +267,7 @@ public:
v128 getVectorRegister(int num) const;
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
- void jumpto();
+ void jumpto() { __libunwind_Registers_x86_64_jumpto(this); }
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; }
static int getArch() { return REGISTERS_X86_64; }
@@ -1510,12 +1514,12 @@ inline void Registers_ppc64::setFloatRegister(int regNum, double value) {
}
inline bool Registers_ppc64::validVectorRegister(int regNum) const {
-#ifdef PPC64_HAS_VMX
+#if defined(__VSX__)
if (regNum >= UNW_PPC64_VS0 && regNum <= UNW_PPC64_VS31)
return true;
if (regNum >= UNW_PPC64_VS32 && regNum <= UNW_PPC64_VS63)
return true;
-#else
+#elif defined(__ALTIVEC__)
if (regNum >= UNW_PPC64_V0 && regNum <= UNW_PPC64_V31)
return true;
#endif
@@ -1771,6 +1775,8 @@ inline const char *Registers_ppc64::getRegisterName(int regNum) {
#if defined(_LIBUNWIND_TARGET_AARCH64)
/// Registers_arm64 holds the register state of a thread in a 64-bit arm
/// process.
+class _LIBUNWIND_HIDDEN Registers_arm64;
+extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
class _LIBUNWIND_HIDDEN Registers_arm64 {
public:
Registers_arm64();
@@ -1786,7 +1792,7 @@ public:
v128 getVectorRegister(int num) const;
void setVectorRegister(int num, v128 value);
static const char *getRegisterName(int num);
- void jumpto();
+ void jumpto() { __libunwind_Registers_arm64_jumpto(this); }
static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; }
static int getArch() { return REGISTERS_ARM64; }
lib/libunwind/src/Unwind-seh.cpp
@@ -46,18 +46,6 @@ using namespace libunwind;
/// handling.
#define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343
-/// Class of foreign exceptions based on unrecognized SEH exceptions.
-static const uint64_t kSEHExceptionClass = 0x434C4E4753454800; // CLNGSEH\0
-
-/// Exception cleanup routine used by \c _GCC_specific_handler to
-/// free foreign exceptions.
-static void seh_exc_cleanup(_Unwind_Reason_Code urc, _Unwind_Exception *exc) {
- (void)urc;
- if (exc->exception_class != kSEHExceptionClass)
- _LIBUNWIND_ABORT("SEH cleanup called on non-SEH exception");
- free(exc);
-}
-
static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx);
static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor);
static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor,
@@ -108,10 +96,10 @@ _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
}
} else {
// Foreign exception.
- exc = (_Unwind_Exception *)malloc(sizeof(_Unwind_Exception));
- exc->exception_class = kSEHExceptionClass;
- exc->exception_cleanup = seh_exc_cleanup;
- memset(exc->private_, 0, sizeof(exc->private_));
+ // We can't interact with them (we don't know the original target frame
+ // that we should pass on to RtlUnwindEx in _Unwind_Resume), so just
+ // pass without calling our destructors here.
+ return ExceptionContinueSearch;
}
if (!ctx) {
__unw_init_seh(&cursor, disp->ContextRecord);
lib/libunwind/src/Unwind_AppleExtras.cpp
@@ -8,35 +8,6 @@
//===----------------------------------------------------------------------===//
#include "config.h"
-#include "AddressSpace.hpp"
-#include "DwarfParser.hpp"
-
-
-// private keymgr stuff
-#define KEYMGR_GCC3_DW2_OBJ_LIST 302
-extern "C" {
- extern void _keymgr_set_and_unlock_processwide_ptr(int key, void *ptr);
- extern void *_keymgr_get_and_lock_processwide_ptr(int key);
-}
-
-// undocumented libgcc "struct object"
-struct libgcc_object {
- void *start;
- void *unused1;
- void *unused2;
- void *fde;
- unsigned long encoding;
- void *fde_end;
- libgcc_object *next;
-};
-
-// undocumented libgcc "struct km_object_info" referenced by
-// KEYMGR_GCC3_DW2_OBJ_LIST
-struct libgcc_object_info {
- libgcc_object *seen_objects;
- libgcc_object *unseen_objects;
- unsigned spare[2];
-};
// static linker symbols to prevent wrong two level namespace for _Unwind symbols
@@ -140,44 +111,3 @@ NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow)
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister)
#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)
-
-
-namespace libunwind {
-
-_LIBUNWIND_HIDDEN
-bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) {
-#if __MAC_OS_X_VERSION_MIN_REQUIRED
- // lastly check for old style keymgr registration of dynamically generated
- // FDEs acquire exclusive access to libgcc_object_info
- libgcc_object_info *head = (libgcc_object_info *)
- _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
- if (head != NULL) {
- // look at each FDE in keymgr
- for (libgcc_object *ob = head->unseen_objects; ob != NULL; ob = ob->next) {
- CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
- CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
- const char *msg = CFI_Parser<LocalAddressSpace>::decodeFDE(
- LocalAddressSpace::sThisAddressSpace,
- (uintptr_t)ob->fde, &fdeInfo, &cieInfo);
- if (msg == NULL) {
- // Check if this FDE is for a function that includes the pc
- if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) {
- fde = (void*)fdeInfo.pcStart;
- _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST,
- head);
- return true;
- }
- }
- }
- }
- // release libgcc_object_info
- _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
-#else
- (void)pc;
- (void)fde;
-#endif
- return false;
-}
-
-}
-
lib/libunwind/src/UnwindCursor.hpp
@@ -81,6 +81,7 @@ template <typename A>
class _LIBUNWIND_HIDDEN DwarfFDECache {
typedef typename A::pint_t pint_t;
public:
+ static constexpr pint_t kSearchAll = static_cast<pint_t>(-1);
static pint_t findFDE(pint_t mh, pint_t pc);
static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde);
static void removeAllIn(pint_t mh);
@@ -138,7 +139,7 @@ typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) {
pint_t result = 0;
_LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared());
for (entry *p = _buffer; p < _bufferUsed; ++p) {
- if ((mh == p->mh) || (mh == 0)) {
+ if ((mh == p->mh) || (mh == kSearchAll)) {
if ((p->ip_start <= pc) && (pc < p->ip_end)) {
result = p->fde;
break;
@@ -530,6 +531,8 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
: _addressSpace(as), _unwindInfoMissing(false) {
static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit),
"UnwindCursor<> does not fit in unw_cursor_t");
+ static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)),
+ "UnwindCursor<> requires more alignment than unw_cursor_t");
memset(&_info, 0, sizeof(_info));
memset(&_histTable, 0, sizeof(_histTable));
_dispContext.ContextRecord = &_msContext;
@@ -923,6 +926,9 @@ private:
#endif
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+ bool getInfoFromFdeCie(const typename CFI_Parser<A>::FDE_Info &fdeInfo,
+ const typename CFI_Parser<A>::CIE_Info &cieInfo,
+ pint_t pc, uintptr_t dso_base);
bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s,
uint32_t fdeSectionOffsetHint=0);
int stepWithDwarfFDE() {
@@ -1182,6 +1188,8 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
_isSignalFrame(false) {
static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit),
"UnwindCursor<> does not fit in unw_cursor_t");
+ static_assert((alignof(UnwindCursor<A, R>) <= alignof(unw_cursor_t)),
+ "UnwindCursor<> requires more alignment than unw_cursor_t");
memset(&_info, 0, sizeof(_info));
}
@@ -1472,6 +1480,32 @@ bool UnwindCursor<A, R>::getInfoFromEHABISection(
#endif
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromFdeCie(
+ const typename CFI_Parser<A>::FDE_Info &fdeInfo,
+ const typename CFI_Parser<A>::CIE_Info &cieInfo, pint_t pc,
+ uintptr_t dso_base) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
+ R::getArch(), &prolog)) {
+ // Save off parsed FDE info
+ _info.start_ip = fdeInfo.pcStart;
+ _info.end_ip = fdeInfo.pcEnd;
+ _info.lsda = fdeInfo.lsda;
+ _info.handler = cieInfo.personality;
+ // Some frameless functions need SP altered when resuming in function, so
+ // propagate spExtraArgSize.
+ _info.gp = prolog.spExtraArgSize;
+ _info.flags = 0;
+ _info.format = dwarfEncoding();
+ _info.unwind_info = fdeInfo.fdeStart;
+ _info.unwind_info_size = static_cast<uint32_t>(fdeInfo.fdeLength);
+ _info.extra = static_cast<unw_word_t>(dso_base);
+ return true;
+ }
+ return false;
+}
+
template <typename A, typename R>
bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
const UnwindInfoSections §s,
@@ -1483,7 +1517,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
// If compact encoding table gave offset into dwarf section, go directly there
if (fdeSectionOffsetHint != 0) {
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
- (uint32_t)sects.dwarf_section_length,
+ sects.dwarf_section_length,
sects.dwarf_section + fdeSectionOffsetHint,
&fdeInfo, &cieInfo);
}
@@ -1500,7 +1534,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
if (cachedFDE != 0) {
foundFDE =
CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
- (uint32_t)sects.dwarf_section_length,
+ sects.dwarf_section_length,
cachedFDE, &fdeInfo, &cieInfo);
foundInCache = foundFDE;
}
@@ -1508,25 +1542,11 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
if (!foundFDE) {
// Still not found, do full scan of __eh_frame section.
foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
- (uint32_t)sects.dwarf_section_length, 0,
+ sects.dwarf_section_length, 0,
&fdeInfo, &cieInfo);
}
if (foundFDE) {
- typename CFI_Parser<A>::PrologInfo prolog;
- if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
- R::getArch(), &prolog)) {
- // Save off parsed FDE info
- _info.start_ip = fdeInfo.pcStart;
- _info.end_ip = fdeInfo.pcEnd;
- _info.lsda = fdeInfo.lsda;
- _info.handler = cieInfo.personality;
- _info.gp = prolog.spExtraArgSize;
- _info.flags = 0;
- _info.format = dwarfEncoding();
- _info.unwind_info = fdeInfo.fdeStart;
- _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength;
- _info.extra = (unw_word_t) sects.dso_base;
-
+ if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, sects.dso_base)) {
// Add to cache (to make next lookup faster) if we had no hint
// and there was no index.
if (!foundInCache && (fdeSectionOffsetHint == 0)) {
@@ -1759,12 +1779,12 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
}
}
- // extact personality routine, if encoding says function has one
+ // extract personality routine, if encoding says function has one
uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >>
(__builtin_ctz(UNWIND_PERSONALITY_MASK));
if (personalityIndex != 0) {
--personalityIndex; // change 1-based to zero-based index
- if (personalityIndex > sectionHeader.personalityArrayCount()) {
+ if (personalityIndex >= sectionHeader.personalityArrayCount()) {
_LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, "
"but personality table has only %d entries",
encoding, personalityIndex,
@@ -1926,60 +1946,27 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
// There is no static unwind info for this pc. Look to see if an FDE was
// dynamically registered for it.
- pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc);
+ pint_t cachedFDE = DwarfFDECache<A>::findFDE(DwarfFDECache<A>::kSearchAll,
+ pc);
if (cachedFDE != 0) {
- CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
- CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
- const char *msg = CFI_Parser<A>::decodeFDE(_addressSpace,
- cachedFDE, &fdeInfo, &cieInfo);
- if (msg == NULL) {
- typename CFI_Parser<A>::PrologInfo prolog;
- if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
- pc, R::getArch(), &prolog)) {
- // save off parsed FDE info
- _info.start_ip = fdeInfo.pcStart;
- _info.end_ip = fdeInfo.pcEnd;
- _info.lsda = fdeInfo.lsda;
- _info.handler = cieInfo.personality;
- _info.gp = prolog.spExtraArgSize;
- // Some frameless functions need SP
- // altered when resuming in function.
- _info.flags = 0;
- _info.format = dwarfEncoding();
- _info.unwind_info = fdeInfo.fdeStart;
- _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength;
- _info.extra = 0;
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ if (!CFI_Parser<A>::decodeFDE(_addressSpace, cachedFDE, &fdeInfo, &cieInfo))
+ if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0))
return;
- }
- }
}
// Lastly, ask AddressSpace object about platform specific ways to locate
// other FDEs.
pint_t fde;
if (_addressSpace.findOtherFDE(pc, fde)) {
- CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
- CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
if (!CFI_Parser<A>::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) {
// Double check this FDE is for a function that includes the pc.
- if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) {
- typename CFI_Parser<A>::PrologInfo prolog;
- if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
- pc, R::getArch(), &prolog)) {
- // save off parsed FDE info
- _info.start_ip = fdeInfo.pcStart;
- _info.end_ip = fdeInfo.pcEnd;
- _info.lsda = fdeInfo.lsda;
- _info.handler = cieInfo.personality;
- _info.gp = prolog.spExtraArgSize;
- _info.flags = 0;
- _info.format = dwarfEncoding();
- _info.unwind_info = fdeInfo.fdeStart;
- _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength;
- _info.extra = 0;
+ if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd))
+ if (getInfoFromFdeCie(fdeInfo, cieInfo, pc, 0))
return;
- }
- }
}
}
#endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
lib/libunwind/src/UnwindLevel1.c
@@ -39,8 +39,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
__unw_init_local(cursor, uc);
// Walk each frame looking for a place to stop.
- bool handlerNotFound = true;
- while (handlerNotFound) {
+ while (true) {
// Ask libunwind to get next frame (skip over first which is
// _Unwind_RaiseException).
int stepResult = __unw_step(cursor);
@@ -102,7 +101,6 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
case _URC_HANDLER_FOUND:
// found a catch clause or locals that need destructing in this frame
// stop search and remember stack pointer at the frame
- handlerNotFound = false;
__unw_get_reg(cursor, UNW_REG_SP, &sp);
exception_object->private_2 = (uintptr_t)sp;
_LIBUNWIND_TRACE_UNWINDING(
lib/libunwind/src/UnwindRegistersRestore.S
@@ -13,14 +13,10 @@
#if !defined(__USING_SJLJ_EXCEPTIONS__)
#if defined(__i386__)
-DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
+DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto)
#
-# void libunwind::Registers_x86::jumpto()
+# extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);
#
-#if defined(_WIN32)
-# On windows, the 'this' pointer is passed in ecx instead of on the stack
- movl %ecx, %eax
-#else
# On entry:
# + +
# +-----------------------+
@@ -30,7 +26,6 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
# +-----------------------+ <-- SP
# + +
movl 4(%esp), %eax
-#endif
# set up eax and ret on new stack location
movl 28(%eax), %edx # edx holds new stack pointer
subl $8,%edx
@@ -60,9 +55,9 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
#elif defined(__x86_64__)
-DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
+DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto)
#
-# void libunwind::Registers_x86_64::jumpto()
+# extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *);
#
#if defined(_WIN64)
# On entry, thread_state pointer is in rcx; move it into rdi
@@ -175,7 +170,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv)
PPC64_LR(30)
PPC64_LR(31)
-#ifdef PPC64_HAS_VMX
+#if defined(__VSX__)
// restore VS registers
// (note that this also restores floating point registers and V registers,
@@ -317,6 +312,7 @@ PPC64_CLVS_BOTTOM(n)
PPC64_LF(30)
PPC64_LF(31)
+#if defined(__ALTIVEC__)
// restore vector registers if any are in use
ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave
cmpwi %r5, 0
@@ -378,6 +374,7 @@ PPC64_CLV_UNALIGNED_BOTTOM(n)
PPC64_CLV_UNALIGNEDh(31)
#endif
+#endif
Lnovec:
ld %r0, PPC64_OFFS_CR(%r3)
@@ -436,6 +433,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
lwz %r30,128(%r3)
lwz %r31,132(%r3)
+#ifndef __NO_FPRS__
// restore float registers
lfd %f0, 160(%r3)
lfd %f1, 168(%r3)
@@ -469,7 +467,9 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
lfd %f29,392(%r3)
lfd %f30,400(%r3)
lfd %f31,408(%r3)
+#endif
+#if defined(__ALTIVEC__)
// restore vector registers if any are in use
lwz %r5, 156(%r3) // test VRsave
cmpwi %r5, 0
@@ -542,6 +542,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
LOAD_VECTOR_UNALIGNEDh(29)
LOAD_VECTOR_UNALIGNEDh(30)
LOAD_VECTOR_UNALIGNEDh(31)
+#endif
Lnovec:
lwz %r0, 136(%r3) // __cr
@@ -560,13 +561,13 @@ Lnovec:
#elif defined(__aarch64__)
//
-// void libunwind::Registers_arm64::jumpto()
+// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
//
// On entry:
// thread_state pointer is in x0
//
.p2align 2
-DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv)
+DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
// skip restore of x0,x1 for now
ldp x2, x3, [x0, #0x010]
ldp x4, x5, [x0, #0x020]
lib/libunwind/src/UnwindRegistersSave.S
@@ -384,7 +384,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
mfvrsave %r0
std %r0, PPC64_OFFS_VRSAVE(%r3)
-#ifdef PPC64_HAS_VMX
+#if defined(__VSX__)
// save VS registers
// (note that this also saves floating point registers and V registers,
// because part of VS is mapped to these registers)
@@ -501,6 +501,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
PPC64_STF(30)
PPC64_STF(31)
+#if defined(__ALTIVEC__)
// save vector registers
// Use 16-bytes below the stack pointer as an
@@ -548,6 +549,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
PPC64_STV_UNALIGNED(30)
PPC64_STV_UNALIGNED(31)
+#endif
#endif
li %r3, 0 // return UNW_ESUCCESS
@@ -608,6 +610,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
mfctr %r0
stw %r0, 148(%r3)
+#if !defined(__NO_FPRS__)
// save float registers
stfd %f0, 160(%r3)
stfd %f1, 168(%r3)
@@ -641,8 +644,9 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
stfd %f29,392(%r3)
stfd %f30,400(%r3)
stfd %f31,408(%r3)
+#endif
-
+#if defined(__ALTIVEC__)
// save vector registers
subi %r4, %r1, 16
@@ -692,6 +696,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
SAVE_VECTOR_UNALIGNED(%v29, 424+0x1D0)
SAVE_VECTOR_UNALIGNED(%v30, 424+0x1E0)
SAVE_VECTOR_UNALIGNED(%v31, 424+0x1F0)
+#endif
li %r3, 0 // return UNW_ESUCCESS
blr