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