github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/include/unwind-pe.h (about) 1 //===----------------------------- unwind-pe.h ----------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 // Pointer-Encoding decoder. Derived from: 9 // - libcxxabi/src/Unwind/dwarf2.h 10 // - libcxxabi/src/Unwind/AddressSpace.h 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef UNWIND_PE_H 15 #define UNWIND_PE_H 16 17 #include <assert.h> 18 #include <stdint.h> 19 #include <string.h> 20 21 // FSF exception handling Pointer-Encoding constants 22 // Used in CFI augmentation by GCC 23 enum { 24 DW_EH_PE_ptr = 0x00, 25 DW_EH_PE_uleb128 = 0x01, 26 DW_EH_PE_udata2 = 0x02, 27 DW_EH_PE_udata4 = 0x03, 28 DW_EH_PE_udata8 = 0x04, 29 DW_EH_PE_signed = 0x08, 30 DW_EH_PE_sleb128 = 0x09, 31 DW_EH_PE_sdata2 = 0x0A, 32 DW_EH_PE_sdata4 = 0x0B, 33 DW_EH_PE_sdata8 = 0x0C, 34 DW_EH_PE_absptr = 0x00, 35 DW_EH_PE_pcrel = 0x10, 36 DW_EH_PE_textrel = 0x20, 37 DW_EH_PE_datarel = 0x30, 38 DW_EH_PE_funcrel = 0x40, 39 DW_EH_PE_aligned = 0x50, 40 DW_EH_PE_indirect = 0x80, 41 DW_EH_PE_omit = 0xFF 42 }; 43 44 /// Read a ULEB128 into a 64-bit word. 45 static uint64_t unw_getULEB128(uintptr_t *addr) { 46 const uint8_t *p = (uint8_t *)*addr; 47 uint64_t result = 0; 48 int bit = 0; 49 do { 50 uint64_t b; 51 52 b = *p & 0x7f; 53 54 if (bit >= 64 || b << bit >> bit != b) { 55 assert(!"malformed uleb128 expression"); 56 } else { 57 result |= b << bit; 58 bit += 7; 59 } 60 } while (*p++ >= 0x80); 61 *addr = (uintptr_t) p; 62 return result; 63 } 64 65 /// Read a SLEB128 into a 64-bit word. 66 static int64_t unw_getSLEB128(uintptr_t *addr) { 67 const uint8_t *p = (uint8_t *)addr; 68 int64_t result = 0; 69 int bit = 0; 70 uint8_t byte; 71 do { 72 byte = *p++; 73 result |= ((byte & 0x7f) << bit); 74 bit += 7; 75 } while (byte & 0x80); 76 // sign extend negative numbers 77 if ((byte & 0x40) != 0) 78 result |= (-1LL) << bit; 79 *addr = (uintptr_t) p; 80 return result; 81 } 82 83 static uint16_t unw_get16(uintptr_t addr) { 84 uint16_t val; 85 memcpy(&val, (void *)addr, sizeof(val)); 86 return val; 87 } 88 89 static uint32_t unw_get32(uintptr_t addr) { 90 uint32_t val; 91 memcpy(&val, (void *)addr, sizeof(val)); 92 return val; 93 } 94 95 static uint64_t unw_get64(uintptr_t addr) { 96 uint64_t val; 97 memcpy(&val, (void *)addr, sizeof(val)); 98 return val; 99 } 100 101 static uintptr_t unw_getP(uintptr_t addr) { 102 if (sizeof(uintptr_t) == 8) 103 return unw_get64(addr); 104 else 105 return unw_get32(addr); 106 } 107 108 static const unsigned char *read_uleb128(const unsigned char *p, 109 _uleb128_t *ret) { 110 uintptr_t addr = (uintptr_t)p; 111 *ret = unw_getULEB128(&addr); 112 return (unsigned char *)addr; 113 } 114 115 static const unsigned char *read_encoded_value(struct _Unwind_Context *ctx, 116 unsigned char encoding, 117 const unsigned char *p, 118 _Unwind_Ptr *ret) { 119 uintptr_t addr = (uintptr_t)p; 120 uintptr_t startAddr = addr; 121 uintptr_t result; 122 123 (void)ctx; 124 125 // first get value 126 switch (encoding & 0x0F) { 127 case DW_EH_PE_ptr: 128 result = unw_getP(addr); 129 p += sizeof(uintptr_t); 130 break; 131 case DW_EH_PE_uleb128: 132 result = (uintptr_t)unw_getULEB128(&addr); 133 p = (const unsigned char *)addr; 134 break; 135 case DW_EH_PE_udata2: 136 result = unw_get16(addr); 137 p += 2; 138 break; 139 case DW_EH_PE_udata4: 140 result = unw_get32(addr); 141 p += 4; 142 break; 143 case DW_EH_PE_udata8: 144 result = (uintptr_t)unw_get64(addr); 145 p += 8; 146 break; 147 case DW_EH_PE_sleb128: 148 result = (uintptr_t)unw_getSLEB128(&addr); 149 p = (const unsigned char *)addr; 150 break; 151 case DW_EH_PE_sdata2: 152 // Sign extend from signed 16-bit value. 153 result = (uintptr_t)(int16_t)unw_get16(addr); 154 p += 2; 155 break; 156 case DW_EH_PE_sdata4: 157 // Sign extend from signed 32-bit value. 158 result = (uintptr_t)(int32_t)unw_get32(addr); 159 p += 4; 160 break; 161 case DW_EH_PE_sdata8: 162 result = (uintptr_t)unw_get64(addr); 163 p += 8; 164 break; 165 default: 166 assert(!"unknown pointer encoding"); 167 } 168 169 // then add relative offset 170 switch (encoding & 0x70) { 171 case DW_EH_PE_absptr: 172 // do nothing 173 break; 174 case DW_EH_PE_pcrel: 175 result += startAddr; 176 break; 177 case DW_EH_PE_textrel: 178 assert(!"DW_EH_PE_textrel pointer encoding not supported"); 179 break; 180 case DW_EH_PE_datarel: 181 assert(!"DW_EH_PE_datarel pointer encoding not supported"); 182 break; 183 case DW_EH_PE_funcrel: 184 assert(!"DW_EH_PE_funcrel pointer encoding not supported"); 185 break; 186 case DW_EH_PE_aligned: 187 assert(!"DW_EH_PE_aligned pointer encoding not supported"); 188 break; 189 default: 190 assert(!"unknown pointer encoding"); 191 break; 192 } 193 194 if (encoding & DW_EH_PE_indirect) 195 result = unw_getP(result); 196 197 *ret = result; 198 return p; 199 } 200 201 #endif // UNWIND_PE_H