| // Copyright (C) 2012 The Android Open Source Project |
| // All rights reserved. |
| // |
| // 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. |
| // 3. Neither the name of the project nor the names of its contributors |
| // may be used to endorse or promote products derived from this software |
| // without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``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 THE PROJECT 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. |
| //===----------------------------------------------------------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is dual licensed under the MIT and the University of Illinois Open |
| // Source Licenses. See LICENSE.TXT for details. |
| // |
| // |
| // This file implements the "Exception Handling APIs" |
| // http://www.codesourcery.com/public/cxx-abi/abi-eh.html |
| // http://www.intel.com/design/itanium/downloads/245358.htm |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include <cstdlib> |
| #include <endian.h> |
| #include "dwarf_helper.h" |
| |
| #if !defined(__BYTE_ORDER) || \ |
| !defined(__LITTLE_ENDIAN) || !defined(__BIG_ENDIAN) |
| #error "Endianness testing macros are not defined" |
| #endif |
| |
| #if __BYTE_ORDER != __LITTLE_ENDIAN && __BYTE_ORDER != __BIG_ENDIAN |
| #error "Unsupported endianness" |
| #endif |
| |
| namespace __cxxabiv1 { |
| |
| uintptr_t readULEB128(const uint8_t** data) { |
| uintptr_t result = 0; |
| uintptr_t shift = 0; |
| unsigned char byte; |
| const uint8_t *p = *data; |
| do { |
| byte = *p++; |
| result |= static_cast<uintptr_t>(byte & 0x7F) << shift; |
| shift += 7; |
| } while (byte & 0x80); |
| *data = p; |
| return result; |
| } |
| |
| intptr_t readSLEB128(const uint8_t** data) { |
| uintptr_t result = 0; |
| uintptr_t shift = 0; |
| unsigned char byte; |
| const uint8_t *p = *data; |
| do { |
| byte = *p++; |
| result |= static_cast<uintptr_t>(byte & 0x7F) << shift; |
| shift += 7; |
| } while (byte & 0x80); |
| *data = p; |
| if ((byte & 0x40) && (shift < (sizeof(result) << 3))) { |
| result |= static_cast<uintptr_t>(~0) << shift; |
| } |
| return static_cast<intptr_t>(result); |
| } |
| |
| static inline uint16_t readUData2(const uint8_t* data) { |
| #if __BYTE_ORDER == __LITTLE_ENDIAN |
| return ((static_cast<uint16_t>(data[0])) | |
| (static_cast<uint16_t>(data[1]) << 8)); |
| #elif __BYTE_ORDER == __BIG_ENDIAN |
| return ((static_cast<uint16_t>(data[0]) << 8) | |
| (static_cast<uint16_t>(data[1]))); |
| #endif |
| } |
| |
| static inline uint32_t readUData4(const uint8_t* data) { |
| #if __BYTE_ORDER == __LITTLE_ENDIAN |
| return ((static_cast<uint32_t>(data[0])) | |
| (static_cast<uint32_t>(data[1]) << 8) | |
| (static_cast<uint32_t>(data[2]) << 16) | |
| (static_cast<uint32_t>(data[3]) << 24)); |
| #elif __BYTE_ORDER == __BIG_ENDIAN |
| return ((static_cast<uint32_t>(data[0]) << 24) | |
| (static_cast<uint32_t>(data[1]) << 16) | |
| (static_cast<uint32_t>(data[2]) << 8) | |
| (static_cast<uint32_t>(data[3]))); |
| #endif |
| } |
| |
| static inline uint64_t readUData8(const uint8_t* data) { |
| #if __BYTE_ORDER == __LITTLE_ENDIAN |
| return ((static_cast<uint64_t>(data[0])) | |
| (static_cast<uint64_t>(data[1]) << 8) | |
| (static_cast<uint64_t>(data[2]) << 16) | |
| (static_cast<uint64_t>(data[3]) << 24) | |
| (static_cast<uint64_t>(data[4]) << 32) | |
| (static_cast<uint64_t>(data[5]) << 40) | |
| (static_cast<uint64_t>(data[6]) << 48) | |
| (static_cast<uint64_t>(data[7]) << 56)); |
| #elif __BYTE_ORDER == __BIG_ENDIAN |
| return ((static_cast<uint64_t>(data[0]) << 56) | |
| (static_cast<uint64_t>(data[1]) << 48) | |
| (static_cast<uint64_t>(data[2]) << 40) | |
| (static_cast<uint64_t>(data[3]) << 32) | |
| (static_cast<uint64_t>(data[4]) << 24) | |
| (static_cast<uint64_t>(data[5]) << 16) | |
| (static_cast<uint64_t>(data[6]) << 8) | |
| (static_cast<uint64_t>(data[7]))); |
| #endif |
| } |
| |
| static inline uintptr_t readAbsPtr(const uint8_t* data) { |
| if (sizeof(uintptr_t) == 4) { |
| return static_cast<uintptr_t>(readUData4(data)); |
| } else if (sizeof(uintptr_t) == 8) { |
| return static_cast<uintptr_t>(readUData8(data)); |
| } else { |
| abort(); |
| } |
| } |
| |
| uintptr_t readEncodedPointer(const uint8_t** data, |
| uint8_t encoding) { |
| uintptr_t result = 0; |
| if (encoding == DW_EH_PE_omit) { |
| return result; |
| } |
| const uint8_t* p = *data; |
| |
| switch (encoding & 0x0F) { |
| default: |
| abort(); |
| break; |
| case DW_EH_PE_absptr: |
| result = readAbsPtr(p); |
| p += sizeof(uintptr_t); |
| break; |
| case DW_EH_PE_uleb128: |
| result = readULEB128(&p); |
| break; |
| case DW_EH_PE_sleb128: |
| result = static_cast<uintptr_t>(readSLEB128(&p)); |
| break; |
| case DW_EH_PE_udata2: |
| result = readUData2(p); |
| p += sizeof(uint16_t); |
| break; |
| case DW_EH_PE_udata4: |
| result = readUData4(p); |
| p += sizeof(uint32_t); |
| break; |
| case DW_EH_PE_udata8: |
| result = static_cast<uintptr_t>(readUData8(p)); |
| p += sizeof(uint64_t); |
| break; |
| case DW_EH_PE_sdata2: |
| result = static_cast<uintptr_t>(static_cast<int16_t>(readUData2(p))); |
| p += sizeof(int16_t); |
| break; |
| case DW_EH_PE_sdata4: |
| result = static_cast<uintptr_t>(static_cast<int32_t>(readUData4(p))); |
| p += sizeof(int32_t); |
| break; |
| case DW_EH_PE_sdata8: |
| result = static_cast<uintptr_t>(static_cast<int64_t>(readUData8(p))); |
| p += sizeof(int64_t); |
| break; |
| } |
| |
| switch (encoding & 0x70) { |
| default: |
| abort(); |
| break; |
| case DW_EH_PE_absptr: |
| break; |
| case DW_EH_PE_pcrel: |
| if (result) { |
| result += (uintptr_t)(*data); |
| } |
| break; |
| } |
| |
| // finally, apply indirection |
| if (result && (encoding & DW_EH_PE_indirect)) { |
| result = *(reinterpret_cast<uintptr_t*>(result)); |
| } |
| *data = p; |
| return result; |
| } |
| |
| } // namespace __cxxabiv1 |