mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 07:32:44 +00:00
Update libunwind
llvm commit b2851aea80e5a8f0cfd6c3c5a56a6b00fb28c6b6
This commit is contained in:
parent
8612dac225
commit
1e66ac5755
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
// PT_GNU_EH_FRAME is usually near the end. Iterate backward. We already know
|
||||
// that there is one or more phdrs.
|
||||
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;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
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_text)
|
||||
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;
|
||||
// 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 (checkForUnwindInfoSegment(phdr, image_base, cbdata)) {
|
||||
found_unwind = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found_obj && found_hdr;
|
||||
if (!found_unwind)
|
||||
return 0;
|
||||
|
||||
#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,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
// 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;
|
||||
|
||||
// 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);
|
||||
struct ParseInfo {
|
||||
pint_t instructions;
|
||||
pint_t instructionsEnd;
|
||||
pint_t pcoffset;
|
||||
};
|
||||
|
||||
#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
|
||||
ParseInfo parseInfoArray[] = {
|
||||
{cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength,
|
||||
(pint_t)(-1)},
|
||||
{fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength,
|
||||
upToPC - fdeInfo.pcStart}};
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
for (const auto &info : parseInfoArray) {
|
||||
pint_t p = info.instructions;
|
||||
pint_t instructionsEnd = info.instructionsEnd;
|
||||
pint_t pcoffset = info.pcoffset;
|
||||
pint_t codeOffset = 0;
|
||||
|
||||
/// "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);
|
||||
// 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));
|
||||
_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;
|
||||
#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;
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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(
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user