Update libunwind

llvm commit b2851aea80e5a8f0cfd6c3c5a56a6b00fb28c6b6
This commit is contained in:
Jakub Konka 2020-12-16 11:48:54 +01:00
parent 8612dac225
commit 1e66ac5755
14 changed files with 664 additions and 757 deletions

View File

@ -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;

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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; }

View File

@ -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);

View File

@ -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 &sects,
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 &sects,
@ -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)

View File

@ -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(

View File

@ -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]

View File

@ -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

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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)