mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-27 03:48:33 +00:00
57b08b0944
to reflect the new license. These used slightly different spellings that defeated my regular expressions. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351648
201 lines
4.9 KiB
C
201 lines
4.9 KiB
C
//===----------------------------- unwind-pe.h ----------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
// Pointer-Encoding decoder. Derived from:
|
|
// - libcxxabi/src/Unwind/dwarf2.h
|
|
// - libcxxabi/src/Unwind/AddressSpace.h
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef UNWIND_PE_H
|
|
#define UNWIND_PE_H
|
|
|
|
#include <assert.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
// FSF exception handling Pointer-Encoding constants
|
|
// Used in CFI augmentation by GCC
|
|
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_signed = 0x08,
|
|
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_textrel = 0x20,
|
|
DW_EH_PE_datarel = 0x30,
|
|
DW_EH_PE_funcrel = 0x40,
|
|
DW_EH_PE_aligned = 0x50,
|
|
DW_EH_PE_indirect = 0x80,
|
|
DW_EH_PE_omit = 0xFF
|
|
};
|
|
|
|
/// Read a ULEB128 into a 64-bit word.
|
|
static uint64_t unw_getULEB128(uintptr_t *addr) {
|
|
const uint8_t *p = (uint8_t *)*addr;
|
|
uint64_t result = 0;
|
|
int bit = 0;
|
|
do {
|
|
uint64_t b;
|
|
|
|
b = *p & 0x7f;
|
|
|
|
if (bit >= 64 || b << bit >> bit != b) {
|
|
assert(!"malformed uleb128 expression");
|
|
} else {
|
|
result |= b << bit;
|
|
bit += 7;
|
|
}
|
|
} while (*p++ >= 0x80);
|
|
*addr = (uintptr_t) p;
|
|
return result;
|
|
}
|
|
|
|
/// Read a SLEB128 into a 64-bit word.
|
|
static int64_t unw_getSLEB128(uintptr_t *addr) {
|
|
const uint8_t *p = (uint8_t *)addr;
|
|
int64_t result = 0;
|
|
int bit = 0;
|
|
uint8_t byte;
|
|
do {
|
|
byte = *p++;
|
|
result |= ((byte & 0x7f) << bit);
|
|
bit += 7;
|
|
} while (byte & 0x80);
|
|
// sign extend negative numbers
|
|
if ((byte & 0x40) != 0)
|
|
result |= (-1LL) << bit;
|
|
*addr = (uintptr_t) p;
|
|
return result;
|
|
}
|
|
|
|
static uint16_t unw_get16(uintptr_t addr) {
|
|
uint16_t val;
|
|
memcpy(&val, (void *)addr, sizeof(val));
|
|
return val;
|
|
}
|
|
|
|
static uint32_t unw_get32(uintptr_t addr) {
|
|
uint32_t val;
|
|
memcpy(&val, (void *)addr, sizeof(val));
|
|
return val;
|
|
}
|
|
|
|
static uint64_t unw_get64(uintptr_t addr) {
|
|
uint64_t val;
|
|
memcpy(&val, (void *)addr, sizeof(val));
|
|
return val;
|
|
}
|
|
|
|
static uintptr_t unw_getP(uintptr_t addr) {
|
|
if (sizeof(uintptr_t) == 8)
|
|
return unw_get64(addr);
|
|
else
|
|
return unw_get32(addr);
|
|
}
|
|
|
|
static const unsigned char *read_uleb128(const unsigned char *p,
|
|
_uleb128_t *ret) {
|
|
uintptr_t addr = (uintptr_t)p;
|
|
*ret = unw_getULEB128(&addr);
|
|
return (unsigned char *)addr;
|
|
}
|
|
|
|
static const unsigned char *read_encoded_value(struct _Unwind_Context *ctx,
|
|
unsigned char encoding,
|
|
const unsigned char *p,
|
|
_Unwind_Ptr *ret) {
|
|
uintptr_t addr = (uintptr_t)p;
|
|
uintptr_t startAddr = addr;
|
|
uintptr_t result;
|
|
|
|
(void)ctx;
|
|
|
|
// first get value
|
|
switch (encoding & 0x0F) {
|
|
case DW_EH_PE_ptr:
|
|
result = unw_getP(addr);
|
|
p += sizeof(uintptr_t);
|
|
break;
|
|
case DW_EH_PE_uleb128:
|
|
result = (uintptr_t)unw_getULEB128(&addr);
|
|
p = (const unsigned char *)addr;
|
|
break;
|
|
case DW_EH_PE_udata2:
|
|
result = unw_get16(addr);
|
|
p += 2;
|
|
break;
|
|
case DW_EH_PE_udata4:
|
|
result = unw_get32(addr);
|
|
p += 4;
|
|
break;
|
|
case DW_EH_PE_udata8:
|
|
result = (uintptr_t)unw_get64(addr);
|
|
p += 8;
|
|
break;
|
|
case DW_EH_PE_sleb128:
|
|
result = (uintptr_t)unw_getSLEB128(&addr);
|
|
p = (const unsigned char *)addr;
|
|
break;
|
|
case DW_EH_PE_sdata2:
|
|
// Sign extend from signed 16-bit value.
|
|
result = (uintptr_t)(int16_t)unw_get16(addr);
|
|
p += 2;
|
|
break;
|
|
case DW_EH_PE_sdata4:
|
|
// Sign extend from signed 32-bit value.
|
|
result = (uintptr_t)(int32_t)unw_get32(addr);
|
|
p += 4;
|
|
break;
|
|
case DW_EH_PE_sdata8:
|
|
result = (uintptr_t)unw_get64(addr);
|
|
p += 8;
|
|
break;
|
|
default:
|
|
assert(!"unknown pointer encoding");
|
|
}
|
|
|
|
// then add relative offset
|
|
switch (encoding & 0x70) {
|
|
case DW_EH_PE_absptr:
|
|
// do nothing
|
|
break;
|
|
case DW_EH_PE_pcrel:
|
|
result += startAddr;
|
|
break;
|
|
case DW_EH_PE_textrel:
|
|
assert(!"DW_EH_PE_textrel pointer encoding not supported");
|
|
break;
|
|
case DW_EH_PE_datarel:
|
|
assert(!"DW_EH_PE_datarel pointer encoding not supported");
|
|
break;
|
|
case DW_EH_PE_funcrel:
|
|
assert(!"DW_EH_PE_funcrel pointer encoding not supported");
|
|
break;
|
|
case DW_EH_PE_aligned:
|
|
assert(!"DW_EH_PE_aligned pointer encoding not supported");
|
|
break;
|
|
default:
|
|
assert(!"unknown pointer encoding");
|
|
break;
|
|
}
|
|
|
|
if (encoding & DW_EH_PE_indirect)
|
|
result = unw_getP(result);
|
|
|
|
*ret = result;
|
|
return p;
|
|
}
|
|
|
|
#endif // UNWIND_PE_H
|