diff options
| author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-10-15 09:45:50 +0000 |
|---|---|---|
| committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2015-10-15 09:45:50 +0000 |
| commit | e15dd966d523731101f70ccf768bba12435a0208 (patch) | |
| tree | ae9cb828a24ded2585a41af3f21411523b47897d /Source/JavaScriptCore/ftl/FTLUnwindInfo.cpp | |
| download | WebKitGtk-tarball-e15dd966d523731101f70ccf768bba12435a0208.tar.gz | |
webkitgtk-2.10.2webkitgtk-2.10.2
Diffstat (limited to 'Source/JavaScriptCore/ftl/FTLUnwindInfo.cpp')
| -rw-r--r-- | Source/JavaScriptCore/ftl/FTLUnwindInfo.cpp | 1044 |
1 files changed, 1044 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/ftl/FTLUnwindInfo.cpp b/Source/JavaScriptCore/ftl/FTLUnwindInfo.cpp new file mode 100644 index 000000000..2867a7245 --- /dev/null +++ b/Source/JavaScriptCore/ftl/FTLUnwindInfo.cpp @@ -0,0 +1,1044 @@ +/* + * 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * 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. + * + * ============================================================================== + * + * 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" +#include "FTLUnwindInfo.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 { +#if OS(DARWIN) +struct CompactUnwind { + void* function; + uint32_t size; + compact_unwind_encoding_t encoding; + 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); + if (!section) + return false; + +#if OS(DARWIN) + RELEASE_ASSERT(size >= sizeof(CompactUnwind)); + + CompactUnwind* data = bitwise_cast<CompactUnwind*>(section); + + RELEASE_ASSERT(!data->personality); // We don't know how to handle this. + RELEASE_ASSERT(!data->lsda); // We don't know how to handle this. + RELEASE_ASSERT(data->function == generatedFunction); // The unwind data better be for our function. + + compact_unwind_encoding_t encoding = data->encoding; + RELEASE_ASSERT(!(encoding & UNWIND_IS_NOT_FUNCTION_START)); + RELEASE_ASSERT(!(encoding & UNWIND_HAS_LSDA)); + RELEASE_ASSERT(!(encoding & UNWIND_PERSONALITY_MASK)); + +#if CPU(X86_64) + RELEASE_ASSERT((encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_RBP_FRAME); + + int32_t offset = -((encoding & UNWIND_X86_64_RBP_FRAME_OFFSET) >> 16) * 8; + uint32_t nextRegisters = encoding; + for (unsigned i = 5; i--;) { + uint32_t currentRegister = nextRegisters & 7; + nextRegisters >>= 3; + + switch (currentRegister) { + case UNWIND_X86_64_REG_NONE: + break; + + case UNWIND_X86_64_REG_RBX: + m_registers.append(RegisterAtOffset(X86Registers::ebx, offset)); + break; + + case UNWIND_X86_64_REG_R12: + m_registers.append(RegisterAtOffset(X86Registers::r12, offset)); + break; + + case UNWIND_X86_64_REG_R13: + m_registers.append(RegisterAtOffset(X86Registers::r13, offset)); + break; + + case UNWIND_X86_64_REG_R14: + m_registers.append(RegisterAtOffset(X86Registers::r14, offset)); + break; + + case UNWIND_X86_64_REG_R15: + m_registers.append(RegisterAtOffset(X86Registers::r15, offset)); + break; + + case UNWIND_X86_64_REG_RBP: + m_registers.append(RegisterAtOffset(X86Registers::ebp, offset)); + break; + + default: + RELEASE_ASSERT_NOT_REACHED(); + } + + offset += 8; + } +#elif CPU(ARM64) + RELEASE_ASSERT((encoding & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_FRAME); + + m_registers.append(RegisterAtOffset(ARM64Registers::fp, 0)); + + int32_t offset = 0; + if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { + m_registers.append(RegisterAtOffset(ARM64Registers::x19, offset -= 8)); + m_registers.append(RegisterAtOffset(ARM64Registers::x20, offset -= 8)); + } + if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { + m_registers.append(RegisterAtOffset(ARM64Registers::x21, offset -= 8)); + m_registers.append(RegisterAtOffset(ARM64Registers::x22, offset -= 8)); + } + if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { + m_registers.append(RegisterAtOffset(ARM64Registers::x23, offset -= 8)); + m_registers.append(RegisterAtOffset(ARM64Registers::x24, offset -= 8)); + } + if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { + m_registers.append(RegisterAtOffset(ARM64Registers::x25, offset -= 8)); + m_registers.append(RegisterAtOffset(ARM64Registers::x26, offset -= 8)); + } + if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { + m_registers.append(RegisterAtOffset(ARM64Registers::x27, offset -= 8)); + m_registers.append(RegisterAtOffset(ARM64Registers::x28, offset -= 8)); + } + if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { + m_registers.append(RegisterAtOffset(ARM64Registers::q8, offset -= 8)); + m_registers.append(RegisterAtOffset(ARM64Registers::q9, offset -= 8)); + } + if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { + m_registers.append(RegisterAtOffset(ARM64Registers::q10, offset -= 8)); + m_registers.append(RegisterAtOffset(ARM64Registers::q11, offset -= 8)); + } + if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { + m_registers.append(RegisterAtOffset(ARM64Registers::q12, offset -= 8)); + m_registers.append(RegisterAtOffset(ARM64Registers::q13, offset -= 8)); + } + if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { + m_registers.append(RegisterAtOffset(ARM64Registers::q14, offset -= 8)); + m_registers.append(RegisterAtOffset(ARM64Registers::q15, offset -= 8)); + } +#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; +} + +void UnwindInfo::dump(PrintStream& out) const +{ + out.print(listDump(m_registers)); +} + +RegisterAtOffset* UnwindInfo::find(Reg reg) const +{ + return tryBinarySearch<RegisterAtOffset, Reg>(m_registers, m_registers.size(), reg, RegisterAtOffset::getReg); +} + +unsigned UnwindInfo::indexOf(Reg reg) const +{ + if (RegisterAtOffset* pointer = find(reg)) + return pointer - m_registers.begin(); + return UINT_MAX; +} + +} } // namespace JSC::FTL + +#endif // ENABLE(FTL_JIT) + |
