1 /* Exception handling and frame unwind runtime interface routines. 2 Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. 3 4 This file is part of GCC. 5 6 GCC is free software; you can redistribute it and/or modify it 7 under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 In addition to the permissions in the GNU General Public License, the 12 Free Software Foundation gives you unlimited permission to link the 13 compiled version of this file into combinations with other programs, 14 and to distribute those combinations without any restriction coming 15 from the use of this file. (The General Public License restrictions 16 do apply in other respects; for example, they cover modification of 17 the file, and distribution when not linked into a combined 18 executable.) 19 20 GCC is distributed in the hope that it will be useful, but WITHOUT 21 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 23 License for more details. 24 25 You should have received a copy of the GNU General Public License 26 along with GCC; see the file COPYING. If not, write to the Free 27 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 28 02110-1301, USA. */ 29 30 /* @@@ Really this should be out of line, but this also causes link 31 compatibility problems with the base ABI. This is slightly better 32 than duplicating code, however. */ 33 34 #ifndef GCC_UNWIND_PE_H 35 #define GCC_UNWIND_PE_H 36 37 /* If using C++, references to abort have to be qualified with std::. */ 38 #if __cplusplus 39 #define __gxx_abort std::abort 40 #else 41 #define __gxx_abort abort 42 #endif 43 44 /* Pointer encodings, from dwarf2.h. */ 45 #define DW_EH_PE_absptr 0x00 46 #define DW_EH_PE_omit 0xff 47 48 #define DW_EH_PE_uleb128 0x01 49 #define DW_EH_PE_udata2 0x02 50 #define DW_EH_PE_udata4 0x03 51 #define DW_EH_PE_udata8 0x04 52 #define DW_EH_PE_sleb128 0x09 53 #define DW_EH_PE_sdata2 0x0A 54 #define DW_EH_PE_sdata4 0x0B 55 #define DW_EH_PE_sdata8 0x0C 56 #define DW_EH_PE_signed 0x08 57 58 #define DW_EH_PE_pcrel 0x10 59 #define DW_EH_PE_textrel 0x20 60 #define DW_EH_PE_datarel 0x30 61 #define DW_EH_PE_funcrel 0x40 62 #define DW_EH_PE_aligned 0x50 63 64 #define DW_EH_PE_indirect 0x80 65 66 67 #ifndef NO_SIZE_OF_ENCODED_VALUE 68 69 /* Given an encoding, return the number of bytes the format occupies. 70 This is only defined for fixed-size encodings, and so does not 71 include leb128. */ 72 73 static unsigned int 74 size_of_encoded_value (unsigned char encoding) 75 { 76 if (encoding == DW_EH_PE_omit) 77 return 0; 78 79 switch (encoding & 0x07) 80 { 81 case DW_EH_PE_absptr: 82 return sizeof (void *); 83 case DW_EH_PE_udata2: 84 return 2; 85 case DW_EH_PE_udata4: 86 return 4; 87 case DW_EH_PE_udata8: 88 return 8; 89 } 90 __gxx_abort (); 91 } 92 93 #endif 94 95 #ifndef NO_BASE_OF_ENCODED_VALUE 96 97 /* Given an encoding and an _Unwind_Context, return the base to which 98 the encoding is relative. This base may then be passed to 99 read_encoded_value_with_base for use when the _Unwind_Context is 100 not available. */ 101 102 static _Unwind_Ptr 103 base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context) 104 { 105 if (encoding == DW_EH_PE_omit) 106 return 0; 107 108 switch (encoding & 0x70) 109 { 110 case DW_EH_PE_absptr: 111 case DW_EH_PE_pcrel: 112 case DW_EH_PE_aligned: 113 return 0; 114 115 case DW_EH_PE_textrel: 116 return _Unwind_GetTextRelBase (context); 117 case DW_EH_PE_datarel: 118 return _Unwind_GetDataRelBase (context); 119 case DW_EH_PE_funcrel: 120 return _Unwind_GetRegionStart (context); 121 } 122 __gxx_abort (); 123 } 124 125 #endif 126 127 /* Read an unsigned leb128 value from P, store the value in VAL, return 128 P incremented past the value. We assume that a word is large enough to 129 hold any value so encoded; if it is smaller than a pointer on some target, 130 pointers should not be leb128 encoded on that target. */ 131 132 static const unsigned char * 133 read_uleb128 (const unsigned char *p, _Unwind_Word *val) 134 { 135 unsigned int shift = 0; 136 unsigned char byte; 137 _Unwind_Word result; 138 139 result = 0; 140 do 141 { 142 byte = *p++; 143 result |= ((_Unwind_Word)byte & 0x7f) << shift; 144 shift += 7; 145 } 146 while (byte & 0x80); 147 148 *val = result; 149 return p; 150 } 151 152 /* Similar, but read a signed leb128 value. */ 153 154 static const unsigned char * 155 read_sleb128 (const unsigned char *p, _Unwind_Sword *val) 156 { 157 unsigned int shift = 0; 158 unsigned char byte; 159 _Unwind_Word result; 160 161 result = 0; 162 do 163 { 164 byte = *p++; 165 result |= ((_Unwind_Word)byte & 0x7f) << shift; 166 shift += 7; 167 } 168 while (byte & 0x80); 169 170 /* Sign-extend a negative value. */ 171 if (shift < 8 * sizeof(result) && (byte & 0x40) != 0) 172 result |= -(((_Unwind_Word)1L) << shift); 173 174 *val = (_Unwind_Sword) result; 175 return p; 176 } 177 178 /* Load an encoded value from memory at P. The value is returned in VAL; 179 The function returns P incremented past the value. BASE is as given 180 by base_of_encoded_value for this encoding in the appropriate context. */ 181 182 static const unsigned char * 183 read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base, 184 const unsigned char *p, _Unwind_Ptr *val) 185 { 186 union unaligned 187 { 188 void *ptr; 189 unsigned u2 __attribute__ ((mode (HI))); 190 unsigned u4 __attribute__ ((mode (SI))); 191 unsigned u8 __attribute__ ((mode (DI))); 192 signed s2 __attribute__ ((mode (HI))); 193 signed s4 __attribute__ ((mode (SI))); 194 signed s8 __attribute__ ((mode (DI))); 195 } __attribute__((__packed__)); 196 197 const union unaligned *u = (const union unaligned *) p; 198 _Unwind_Internal_Ptr result; 199 200 if (encoding == DW_EH_PE_aligned) 201 { 202 _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p; 203 a = (a + sizeof (void *) - 1) & - sizeof(void *); 204 result = *(_Unwind_Internal_Ptr *) a; 205 p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *)); 206 } 207 else 208 { 209 switch (encoding & 0x0f) 210 { 211 case DW_EH_PE_absptr: 212 result = (_Unwind_Internal_Ptr) u->ptr; 213 p += sizeof (void *); 214 break; 215 216 case DW_EH_PE_uleb128: 217 { 218 _Unwind_Word tmp; 219 p = read_uleb128 (p, &tmp); 220 result = (_Unwind_Internal_Ptr) tmp; 221 } 222 break; 223 224 case DW_EH_PE_sleb128: 225 { 226 _Unwind_Sword tmp; 227 p = read_sleb128 (p, &tmp); 228 result = (_Unwind_Internal_Ptr) tmp; 229 } 230 break; 231 232 case DW_EH_PE_udata2: 233 result = u->u2; 234 p += 2; 235 break; 236 case DW_EH_PE_udata4: 237 result = u->u4; 238 p += 4; 239 break; 240 case DW_EH_PE_udata8: 241 result = u->u8; 242 p += 8; 243 break; 244 245 case DW_EH_PE_sdata2: 246 result = u->s2; 247 p += 2; 248 break; 249 case DW_EH_PE_sdata4: 250 result = u->s4; 251 p += 4; 252 break; 253 case DW_EH_PE_sdata8: 254 result = u->s8; 255 p += 8; 256 break; 257 258 default: 259 __gxx_abort (); 260 } 261 262 if (result != 0) 263 { 264 result += ((encoding & 0x70) == DW_EH_PE_pcrel 265 ? (_Unwind_Internal_Ptr) u : base); 266 if (encoding & DW_EH_PE_indirect) 267 result = *(_Unwind_Internal_Ptr *) result; 268 } 269 } 270 271 *val = result; 272 return p; 273 } 274 275 #ifndef NO_BASE_OF_ENCODED_VALUE 276 277 /* Like read_encoded_value_with_base, but get the base from the context 278 rather than providing it directly. */ 279 280 static inline const unsigned char * 281 read_encoded_value (struct _Unwind_Context *context, unsigned char encoding, 282 const unsigned char *p, _Unwind_Ptr *val) 283 { 284 return read_encoded_value_with_base (encoding, 285 base_of_encoded_value (encoding, context), 286 p, val); 287 } 288 289 #endif 290 291 #endif /* unwind-pe.h */ 292