/*
* Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014 Samsung Electronics
+ * Copyright (C) 2014 University of Szeged
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ==============================================================================
+ *
+ * University of Illinois/NCSA
+ * Open Source License
+ *
+ * Copyright (c) 2009-2014 by the contributors of LLVM/libc++abi project.
+ *
+ * All rights reserved.
+ *
+ * Developed by:
+ *
+ * LLVM Team
+ *
+ * University of Illinois at Urbana-Champaign
+ *
+ * http://llvm.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal with
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimers.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimers in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the names of the LLVM Team, University of Illinois at
+ * Urbana-Champaign, nor the names of its contributors may be used to
+ * endorse or promote products derived from this Software without specific
+ * prior written permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+ * SOFTWARE.
+ *
+ * ==============================================================================
+ *
+ * Copyright (c) 2009-2014 by the contributors of LLVM/libc++abi project.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
*/
#include "config.h"
#if ENABLE(FTL_JIT)
+#if OS(DARWIN)
#include <mach-o/compact_unwind_encoding.h>
+#endif
#include <wtf/ListDump.h>
namespace JSC { namespace FTL {
UnwindInfo::UnwindInfo() { }
UnwindInfo::~UnwindInfo() { }
-namespace {
+namespace {
+#if OS(DARWIN)
struct CompactUnwind {
void* function;
uint32_t size;
void* personality;
void* lsda;
};
+#elif OS(LINUX)
+// DWARF unwind instructions
+enum {
+ DW_CFA_nop = 0x0,
+ DW_CFA_set_loc = 0x1,
+ DW_CFA_advance_loc1 = 0x2,
+ DW_CFA_advance_loc2 = 0x3,
+ DW_CFA_advance_loc4 = 0x4,
+ DW_CFA_offset_extended = 0x5,
+ DW_CFA_def_cfa = 0xC,
+ DW_CFA_def_cfa_register = 0xD,
+ DW_CFA_def_cfa_offset = 0xE,
+ DW_CFA_offset_extended_sf = 0x11,
+ DW_CFA_def_cfa_sf = 0x12,
+ DW_CFA_def_cfa_offset_sf = 0x13,
+ // high 2 bits are 0x1, lower 6 bits are delta
+ DW_CFA_advance_loc = 0x40,
+ // high 2 bits are 0x2, lower 6 bits are register
+ DW_CFA_offset = 0x80
+};
+
+enum {
+ DW_CFA_operand_mask = 0x3F // low 6 bits mask for opcode-encoded operands in DW_CFA_advance_loc and DW_CFA_offset
+};
+
+// FSF exception handling Pointer-Encoding constants
+enum {
+ DW_EH_PE_ptr = 0x00,
+ DW_EH_PE_uleb128 = 0x01,
+ DW_EH_PE_udata2 = 0x02,
+ DW_EH_PE_udata4 = 0x03,
+ DW_EH_PE_udata8 = 0x04,
+ DW_EH_PE_sleb128 = 0x09,
+ DW_EH_PE_sdata2 = 0x0A,
+ DW_EH_PE_sdata4 = 0x0B,
+ DW_EH_PE_sdata8 = 0x0C,
+ DW_EH_PE_absptr = 0x00,
+ DW_EH_PE_pcrel = 0x10,
+ DW_EH_PE_indirect = 0x80
+};
+
+enum {
+ DW_EH_PE_relative_mask = 0x70
+};
+
+// 64-bit x86_64 registers
+enum {
+ UNW_X86_64_rbx = 3,
+ UNW_X86_64_rbp = 6,
+ UNW_X86_64_r12 = 12,
+ UNW_X86_64_r13 = 13,
+ UNW_X86_64_r14 = 14,
+ UNW_X86_64_r15 = 15
+};
+
+enum {
+ DW_X86_64_RET_addr = 16
+};
+
+enum {
+ UNW_ARM64_x0 = 0,
+ UNW_ARM64_x1 = 1,
+ UNW_ARM64_x2 = 2,
+ UNW_ARM64_x3 = 3,
+ UNW_ARM64_x4 = 4,
+ UNW_ARM64_x5 = 5,
+ UNW_ARM64_x6 = 6,
+ UNW_ARM64_x7 = 7,
+ UNW_ARM64_x8 = 8,
+ UNW_ARM64_x9 = 9,
+ UNW_ARM64_x10 = 10,
+ UNW_ARM64_x11 = 11,
+ UNW_ARM64_x12 = 12,
+ UNW_ARM64_x13 = 13,
+ UNW_ARM64_x14 = 14,
+ UNW_ARM64_x15 = 15,
+ UNW_ARM64_x16 = 16,
+ UNW_ARM64_x17 = 17,
+ UNW_ARM64_x18 = 18,
+ UNW_ARM64_x19 = 19,
+ UNW_ARM64_x20 = 20,
+ UNW_ARM64_x21 = 21,
+ UNW_ARM64_x22 = 22,
+ UNW_ARM64_x23 = 23,
+ UNW_ARM64_x24 = 24,
+ UNW_ARM64_x25 = 25,
+ UNW_ARM64_x26 = 26,
+ UNW_ARM64_x27 = 27,
+ UNW_ARM64_x28 = 28,
+ UNW_ARM64_fp = 29,
+ UNW_ARM64_x30 = 30,
+ UNW_ARM64_sp = 31,
+ UNW_ARM64_v0 = 64,
+ UNW_ARM64_v1 = 65,
+ UNW_ARM64_v2 = 66,
+ UNW_ARM64_v3 = 67,
+ UNW_ARM64_v4 = 68,
+ UNW_ARM64_v5 = 69,
+ UNW_ARM64_v6 = 70,
+ UNW_ARM64_v7 = 71,
+ UNW_ARM64_v8 = 72,
+ UNW_ARM64_v9 = 73,
+ UNW_ARM64_v10 = 74,
+ UNW_ARM64_v11 = 75,
+ UNW_ARM64_v12 = 76,
+ UNW_ARM64_v13 = 77,
+ UNW_ARM64_v14 = 78,
+ UNW_ARM64_v15 = 79,
+ UNW_ARM64_v16 = 80,
+ UNW_ARM64_v17 = 81,
+ UNW_ARM64_v18 = 82,
+ UNW_ARM64_v19 = 83,
+ UNW_ARM64_v20 = 84,
+ UNW_ARM64_v21 = 85,
+ UNW_ARM64_v22 = 86,
+ UNW_ARM64_v23 = 87,
+ UNW_ARM64_v24 = 88,
+ UNW_ARM64_v25 = 89,
+ UNW_ARM64_v26 = 90,
+ UNW_ARM64_v27 = 91,
+ UNW_ARM64_v28 = 92,
+ UNW_ARM64_v29 = 93,
+ UNW_ARM64_v30 = 94,
+ UNW_ARM64_v31 = 95
+};
+
+static uint8_t get8(uintptr_t addr) { return *((uint8_t*)addr); }
+static uint16_t get16(uintptr_t addr) { return *((uint16_t*)addr); }
+static uint32_t get32(uintptr_t addr) { return *((uint32_t*)addr); }
+static uint64_t get64(uintptr_t addr) { return *((uint64_t*)addr); }
+
+static uintptr_t getP(uintptr_t addr)
+{
+ // FIXME: add support for 32 bit pointers on 32 bit architectures
+ return get64(addr);
+}
+
+static uint64_t getULEB128(uintptr_t& addr, uintptr_t end)
+{
+ const uint8_t* p = (uint8_t*)addr;
+ const uint8_t* pend = (uint8_t*)end;
+ uint64_t result = 0;
+ int bit = 0;
+ do {
+ uint64_t b;
+
+ RELEASE_ASSERT(p != pend); // truncated uleb128 expression
+
+ b = *p & 0x7f;
+
+ RELEASE_ASSERT(!(bit >= 64 || b << bit >> bit != b)); // malformed uleb128 expression
+
+ result |= b << bit;
+ bit += 7;
+ } while (*p++ >= 0x80);
+ addr = (uintptr_t)p;
+ return result;
+}
+
+static int64_t getSLEB128(uintptr_t& addr, uintptr_t end)
+{
+ const uint8_t* p = (uint8_t*)addr;
+ const uint8_t* pend = (uint8_t*)end;
+
+ int64_t result = 0;
+ int bit = 0;
+ uint8_t byte;
+ do {
+ RELEASE_ASSERT(p != pend); // truncated sleb128 expression
+
+ byte = *p++;
+ result |= ((byte & 0x7f) << bit);
+ bit += 7;
+ } while (byte & 0x80);
+ // sign extend negative numbers
+ if ((byte & 0x40))
+ result |= (-1LL) << bit;
+ addr = (uintptr_t)p;
+ return result;
+}
+
+static uintptr_t getEncodedP(uintptr_t& addr, uintptr_t end, uint8_t encoding)
+{
+ uintptr_t startAddr = addr;
+ const uint8_t* p = (uint8_t*)addr;
+ uintptr_t result;
+
+ // first get value
+ switch (encoding & 0x0F) {
+ case DW_EH_PE_ptr:
+ result = getP(addr);
+ p += sizeof(uintptr_t);
+ addr = (uintptr_t)p;
+ break;
+ case DW_EH_PE_uleb128:
+ result = getULEB128(addr, end);
+ break;
+ case DW_EH_PE_udata2:
+ result = get16(addr);
+ p += 2;
+ addr = (uintptr_t)p;
+ break;
+ case DW_EH_PE_udata4:
+ result = get32(addr);
+ p += 4;
+ addr = (uintptr_t)p;
+ break;
+ case DW_EH_PE_udata8:
+ result = get64(addr);
+ p += 8;
+ addr = (uintptr_t)p;
+ break;
+ case DW_EH_PE_sleb128:
+ result = getSLEB128(addr, end);
+ break;
+ case DW_EH_PE_sdata2:
+ result = (int16_t)get16(addr);
+ p += 2;
+ addr = (uintptr_t)p;
+ break;
+ case DW_EH_PE_sdata4:
+ result = (int32_t)get32(addr);
+ p += 4;
+ addr = (uintptr_t)p;
+ break;
+ case DW_EH_PE_sdata8:
+ result = get64(addr);
+ p += 8;
+ addr = (uintptr_t)p;
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED(); // unknown pointer encoding
+ }
+
+ // then add relative offset
+ switch (encoding & DW_EH_PE_relative_mask) {
+ case DW_EH_PE_absptr:
+ // do nothing
+ break;
+ case DW_EH_PE_pcrel:
+ result += startAddr;
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED(); // unsupported or unknown pointer encoding
+ }
+
+ if (encoding & DW_EH_PE_indirect)
+ result = getP(result);
+
+ return result;
+}
+
+// Information encoded in a CIE (Common Information Entry)
+struct CIE_Info {
+ uintptr_t cieStart;
+ uintptr_t cieLength;
+ uintptr_t cieInstructions;
+ uint8_t pointerEncoding;
+ uint8_t lsdaEncoding;
+ uint8_t personalityEncoding;
+ uint8_t personalityOffsetInCIE;
+ uintptr_t personality;
+ int dataAlignFactor;
+ bool fdesHaveAugmentationData;
+};
+
+// Information about an FDE (Frame Description Entry)
+struct FDE_Info {
+ uintptr_t fdeStart;
+ uintptr_t fdeLength;
+ uintptr_t fdeInstructions;
+ uintptr_t lsda;
+};
+
+// Information about a frame layout and registers saved determined
+// by "running" the dwarf FDE "instructions"
+#if CPU(ARM64)
+enum { MaxRegisterNumber = 120 };
+#elif CPU(X86_64)
+enum { MaxRegisterNumber = 17 };
+#else
+#error "Unrecognized architecture"
+#endif
+
+struct RegisterLocation {
+ bool saved;
+ int64_t offset;
+};
+struct PrologInfo {
+ uint32_t cfaRegister;
+ int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
+ RegisterLocation savedRegisters[MaxRegisterNumber]; // from where to restore registers
+};
+
+static void parseCIE(uintptr_t cie, CIE_Info* cieInfo)
+{
+ cieInfo->pointerEncoding = 0;
+ cieInfo->lsdaEncoding = 0;
+ cieInfo->personalityEncoding = 0;
+ cieInfo->personalityOffsetInCIE = 0;
+ cieInfo->personality = 0;
+ cieInfo->dataAlignFactor = 0;
+ cieInfo->fdesHaveAugmentationData = false;
+ cieInfo->cieStart = cie;
+
+ uintptr_t p = cie;
+ uint64_t cieLength = get32(p);
+ p += 4;
+ uintptr_t cieContentEnd = p + cieLength;
+ if (cieLength == 0xffffffff) {
+ // 0xffffffff means length is really next 8 bytes
+ cieLength = get64(p);
+ p += 8;
+ cieContentEnd = p + cieLength;
+ }
+
+ RELEASE_ASSERT(cieLength);
+
+ // CIE ID is always 0
+ RELEASE_ASSERT(!get32(p)); // CIE ID is not zero
+ p += 4;
+ // Version is always 1 or 3
+ uint8_t version = get8(p);
+ RELEASE_ASSERT((version == 1) || (version == 3)); // CIE version is not 1 or 3
+
+ ++p;
+ // save start of augmentation string and find end
+ uintptr_t strStart = p;
+ while (get8(p))
+ ++p;
+ ++p;
+ // parse code aligment factor
+ getULEB128(p, cieContentEnd);
+ // parse data alignment factor
+ cieInfo->dataAlignFactor = getSLEB128(p, cieContentEnd);
+ // parse return address register
+ getULEB128(p, cieContentEnd);
+ // parse augmentation data based on augmentation string
+ if (get8(strStart) == 'z') {
+ // parse augmentation data length
+ getULEB128(p, cieContentEnd);
+ for (uintptr_t s = strStart; get8(s) != '\0'; ++s) {
+ switch (get8(s)) {
+ case 'z':
+ cieInfo->fdesHaveAugmentationData = true;
+ break;
+ case 'P': // FIXME: should assert on personality (just to keep in sync with the CU behaviour)
+ cieInfo->personalityEncoding = get8(p);
+ ++p;
+ cieInfo->personalityOffsetInCIE = p - cie;
+ cieInfo->personality = getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
+ break;
+ case 'L': // FIXME: should assert on LSDA (just to keep in sync with the CU behaviour)
+ cieInfo->lsdaEncoding = get8(p);
+ ++p;
+ break;
+ case 'R':
+ cieInfo->pointerEncoding = get8(p);
+ ++p;
+ break;
+ default:
+ // ignore unknown letters
+ break;
+ }
+ }
+ }
+ cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
+ cieInfo->cieInstructions = p;
+}
+
+static void findFDE(uintptr_t pc, uintptr_t ehSectionStart, uint32_t sectionLength, FDE_Info* fdeInfo, CIE_Info* cieInfo)
+{
+ uintptr_t p = ehSectionStart;
+ const uintptr_t ehSectionEnd = p + sectionLength;
+ while (p < ehSectionEnd) {
+ uintptr_t currentCFI = p;
+ uint64_t cfiLength = get32(p);
+ p += 4;
+ if (cfiLength == 0xffffffff) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = get64(p);
+ p += 8;
+ }
+ RELEASE_ASSERT(cfiLength); // end marker reached before finding FDE for pc
+
+ uint32_t id = get32(p);
+ if (!id) {
+ // skip over CIEs
+ p += cfiLength;
+ } else {
+ // process FDE to see if it covers pc
+ uintptr_t nextCFI = p + cfiLength;
+ uint32_t ciePointer = get32(p);
+ uintptr_t cieStart = p - ciePointer;
+ // validate pointer to CIE is within section
+ RELEASE_ASSERT((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)); // malformed FDE. CIE is bad
+
+ parseCIE(cieStart, cieInfo);
+
+ p += 4;
+ // parse pc begin and range
+ uintptr_t pcStart = getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
+ uintptr_t pcRange = getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
+
+ // test if pc is within the function this FDE covers
+ // if pc is not in begin/range, skip this FDE
+ if ((pcStart <= pc) && (pc < pcStart+pcRange)) {
+ // parse rest of info
+ fdeInfo->lsda = 0;
+ // check for augmentation length
+ if (cieInfo->fdesHaveAugmentationData) {
+ uintptr_t augLen = getULEB128(p, nextCFI);
+ uintptr_t endOfAug = p + augLen;
+ if (cieInfo->lsdaEncoding) {
+ // peek at value (without indirection). Zero means no lsda
+ uintptr_t lsdaStart = p;
+ if (getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F)) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ fdeInfo->lsda = getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+ }
+ }
+ p = endOfAug;
+ }
+ fdeInfo->fdeStart = currentCFI;
+ fdeInfo->fdeLength = nextCFI - currentCFI;
+ fdeInfo->fdeInstructions = p;
+
+ return; // FDE found
+ }
+
+ p = nextCFI;
+ }
+ }
+
+ RELEASE_ASSERT_NOT_REACHED(); // no FDE found for pc
+}
+
+static void executeDefCFARegister(uint64_t reg, PrologInfo* results)
+{
+ RELEASE_ASSERT(reg <= MaxRegisterNumber); // reg too big
+ results->cfaRegister = reg;
+}
+
+static void executeDefCFAOffset(int64_t offset, PrologInfo* results)
+{
+ RELEASE_ASSERT(offset <= 0x80000000); // cfa has negative offset (dwarf might contain epilog)
+ results->cfaRegisterOffset = offset;
+}
+
+static void executeOffset(uint64_t reg, int64_t offset, PrologInfo *results)
+{
+ if (reg > MaxRegisterNumber)
+ return;
+
+ RELEASE_ASSERT(!results->savedRegisters[reg].saved);
+ results->savedRegisters[reg].saved = true;
+ results->savedRegisters[reg].offset = offset;
+}
+
+static void parseInstructions(uintptr_t instructions, uintptr_t instructionsEnd, const CIE_Info& cieInfo, PrologInfo* results)
+{
+ uintptr_t p = instructions;
+
+ // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
+ while ((p < instructionsEnd)) {
+ uint64_t reg;
+ uint8_t opcode = get8(p);
+ uint8_t operand;
+ ++p;
+ switch (opcode) {
+ case DW_CFA_nop:
+ break;
+ case DW_CFA_set_loc:
+ getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
+ break;
+ case DW_CFA_advance_loc1:
+ p += 1;
+ break;
+ case DW_CFA_advance_loc2:
+ p += 2;
+ break;
+ case DW_CFA_advance_loc4:
+ p += 4;
+ break;
+ case DW_CFA_def_cfa:
+ executeDefCFARegister(getULEB128(p, instructionsEnd), results);
+ executeDefCFAOffset(getULEB128(p, instructionsEnd), results);
+ break;
+ case DW_CFA_def_cfa_sf:
+ executeDefCFARegister(getULEB128(p, instructionsEnd), results);
+ executeDefCFAOffset(getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results);
+ break;
+ case DW_CFA_def_cfa_register:
+ executeDefCFARegister(getULEB128(p, instructionsEnd), results);
+ break;
+ case DW_CFA_def_cfa_offset:
+ executeDefCFAOffset(getULEB128(p, instructionsEnd), results);
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ executeDefCFAOffset(getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results);
+ break;
+ case DW_CFA_offset_extended:
+ reg = getULEB128(p, instructionsEnd);
+ executeOffset(reg, getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results);
+ break;
+ case DW_CFA_offset_extended_sf:
+ reg = getULEB128(p, instructionsEnd);
+ executeOffset(reg, getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results);
+ break;
+ default:
+ operand = opcode & DW_CFA_operand_mask;
+ switch (opcode & ~DW_CFA_operand_mask) {
+ case DW_CFA_offset:
+ executeOffset(operand, getULEB128(p, instructionsEnd) * cieInfo.dataAlignFactor, results);
+ break;
+ case DW_CFA_advance_loc:
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED(); // unknown or unsupported CFA opcode
+ }
+ }
+ }
+}
+
+static void parseFDEInstructions(const FDE_Info& fdeInfo, const CIE_Info& cieInfo, PrologInfo* results)
+{
+ // clear results
+ bzero(results, sizeof(PrologInfo));
+
+ // parse CIE then FDE instructions
+ parseInstructions(cieInfo.cieInstructions, cieInfo.cieStart + cieInfo.cieLength, cieInfo, results);
+ parseInstructions(fdeInfo.fdeInstructions, fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, results);
+}
+#endif
} // anonymous namespace
bool UnwindInfo::parse(void* section, size_t size, GeneratedFunction generatedFunction)
{
m_registers.clear();
-
- RELEASE_ASSERT(!!section == !!size);
+ RELEASE_ASSERT(!!section);
if (!section)
return false;
-
+
+#if OS(DARWIN)
RELEASE_ASSERT(size >= sizeof(CompactUnwind));
CompactUnwind* data = bitwise_cast<CompactUnwind*>(section);
#else
#error "Unrecognized architecture"
#endif
-
+
+#elif OS(LINUX)
+ FDE_Info fdeInfo;
+ CIE_Info cieInfo;
+ PrologInfo prolog;
+
+ findFDE((uintptr_t)generatedFunction, (uintptr_t)section, size, &fdeInfo, &cieInfo);
+ parseFDEInstructions(fdeInfo, cieInfo, &prolog);
+
+#if CPU(X86_64)
+ RELEASE_ASSERT(prolog.cfaRegister == UNW_X86_64_rbp);
+ RELEASE_ASSERT(prolog.cfaRegisterOffset == 16);
+ RELEASE_ASSERT(prolog.savedRegisters[UNW_X86_64_rbp].saved);
+ RELEASE_ASSERT(prolog.savedRegisters[UNW_X86_64_rbp].offset == -prolog.cfaRegisterOffset);
+
+ for (int i = 0; i < MaxRegisterNumber; ++i) {
+ if (prolog.savedRegisters[i].saved) {
+ switch (i) {
+ case UNW_X86_64_rbx:
+ m_registers.append(RegisterAtOffset(X86Registers::ebx, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_X86_64_r12:
+ m_registers.append(RegisterAtOffset(X86Registers::r12, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_X86_64_r13:
+ m_registers.append(RegisterAtOffset(X86Registers::r13, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_X86_64_r14:
+ m_registers.append(RegisterAtOffset(X86Registers::r14, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_X86_64_r15:
+ m_registers.append(RegisterAtOffset(X86Registers::r15, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_X86_64_rbp:
+ m_registers.append(RegisterAtOffset(X86Registers::ebp, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case DW_X86_64_RET_addr:
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED(); // non-standard register being saved in prolog
+ }
+ }
+ }
+#elif CPU(ARM64)
+ RELEASE_ASSERT(prolog.cfaRegister == UNW_ARM64_fp);
+ RELEASE_ASSERT(prolog.cfaRegisterOffset == 16);
+ RELEASE_ASSERT(prolog.savedRegisters[UNW_ARM64_fp].saved);
+ RELEASE_ASSERT(prolog.savedRegisters[UNW_ARM64_fp].offset == -prolog.cfaRegisterOffset);
+
+ for (int i = 0; i < MaxRegisterNumber; ++i) {
+ if (prolog.savedRegisters[i].saved) {
+ switch (i) {
+ case UNW_ARM64_x0:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x0, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x1:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x1, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x2:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x2, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x3:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x3, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x4:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x4, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x5:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x5, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x6:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x6, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x7:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x7, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x8:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x8, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x9:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x9, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x10:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x10, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x11:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x11, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x12:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x12, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x13:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x13, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x14:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x14, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x15:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x15, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x16:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x16, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x17:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x17, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x18:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x18, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x19:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x19, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x20:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x20, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x21:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x21, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x22:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x22, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x23:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x23, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x24:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x24, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x25:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x25, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x26:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x26, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x27:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x27, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x28:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x28, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_fp:
+ m_registers.append(RegisterAtOffset(ARM64Registers::fp, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_x30:
+ m_registers.append(RegisterAtOffset(ARM64Registers::x30, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_sp:
+ m_registers.append(RegisterAtOffset(ARM64Registers::sp, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v0:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q0, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v1:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q1, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v2:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q2, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v3:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q3, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v4:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q4, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v5:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q5, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v6:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q6, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v7:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q7, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v8:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q8, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v9:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q9, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v10:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q10, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v11:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q11, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v12:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q12, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v13:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q13, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v14:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q14, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v15:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q15, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v16:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q16, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v17:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q17, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v18:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q18, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v19:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q19, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v20:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q20, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v21:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q21, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v22:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q22, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v23:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q23, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v24:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q24, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v25:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q25, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v26:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q26, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v27:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q27, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v28:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q28, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v29:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q29, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v30:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q30, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ case UNW_ARM64_v31:
+ m_registers.append(RegisterAtOffset(ARM64Registers::q31, prolog.savedRegisters[i].offset + prolog.cfaRegisterOffset));
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED(); // non-standard register being saved in prolog
+ }
+ }
+ }
+#else
+#error "Unrecognized architecture"
+#endif
+
+#endif
std::sort(m_registers.begin(), m_registers.end());
return true;
}