/* Exception handling and frame unwind runtime interface routines. Copyright (C) 2001-2017 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation. You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ /* @@@ Really this should be out of line, but this also causes link compatibility problems with the base ABI. This is slightly better than duplicating code, however. */ #ifndef GCC_UNWIND_PE_H #define GCC_UNWIND_PE_H /* If using C++, references to abort have to be qualified with std::. */ #if __cplusplus #define __gxx_abort std::abort #else #define __gxx_abort abort #endif /* Pointer encodings, from dwarf2.h. */ #define DW_EH_PE_absptr 0x00 #define DW_EH_PE_omit 0xff #define DW_EH_PE_uleb128 0x01 #define DW_EH_PE_udata2 0x02 #define DW_EH_PE_udata4 0x03 #define DW_EH_PE_udata8 0x04 #define DW_EH_PE_sleb128 0x09 #define DW_EH_PE_sdata2 0x0A #define DW_EH_PE_sdata4 0x0B #define DW_EH_PE_sdata8 0x0C #define DW_EH_PE_signed 0x08 #define DW_EH_PE_pcrel 0x10 #define DW_EH_PE_textrel 0x20 #define DW_EH_PE_datarel 0x30 #define DW_EH_PE_funcrel 0x40 #define DW_EH_PE_aligned 0x50 #define DW_EH_PE_indirect 0x80 #ifndef NO_SIZE_OF_ENCODED_VALUE /* Given an encoding, return the number of bytes the format occupies. This is only defined for fixed-size encodings, and so does not include leb128. */ static unsigned int size_of_encoded_value (unsigned char encoding) __attribute__ ((unused)); static unsigned int size_of_encoded_value (unsigned char encoding) { #if defined (__e2k__) && defined (__ptr128__) if (encoding == DW_EH_PE_aligned) return 16; #endif /* defined (__e2k__) && defined (__ptr128__) */ if (encoding == DW_EH_PE_omit) return 0; switch (encoding & 0x07) { case DW_EH_PE_absptr: return sizeof (void *); case DW_EH_PE_udata2: return 2; case DW_EH_PE_udata4: return 4; case DW_EH_PE_udata8: return 8; } __gxx_abort (); } #endif #ifndef NO_BASE_OF_ENCODED_VALUE /* Given an encoding and an _Unwind_Context, return the base to which the encoding is relative. This base may then be passed to read_encoded_value_with_base for use when the _Unwind_Context is not available. */ static _Unwind_Ptr base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context) { if (encoding == DW_EH_PE_omit) return 0; switch (encoding & 0x70) { case DW_EH_PE_absptr: case DW_EH_PE_pcrel: case DW_EH_PE_aligned: return 0; case DW_EH_PE_textrel: return _Unwind_GetTextRelBase (context); case DW_EH_PE_datarel: return _Unwind_GetDataRelBase (context); case DW_EH_PE_funcrel: return _Unwind_GetRegionStart (context); } __gxx_abort (); } #endif /* Read an unsigned leb128 value from P, store the value in VAL, return P incremented past the value. We assume that a word is large enough to hold any value so encoded; if it is smaller than a pointer on some target, pointers should not be leb128 encoded on that target. */ static const unsigned char * read_uleb128 (const unsigned char *p, _uleb128_t *val) { unsigned int shift = 0; unsigned char byte; _uleb128_t result; result = 0; do { byte = *p++; result |= ((_uleb128_t)byte & 0x7f) << shift; shift += 7; } while (byte & 0x80); *val = result; return p; } /* Similar, but read a signed leb128 value. */ static const unsigned char * read_sleb128 (const unsigned char *p, _sleb128_t *val) { unsigned int shift = 0; unsigned char byte; _uleb128_t result; result = 0; do { byte = *p++; result |= ((_uleb128_t)byte & 0x7f) << shift; shift += 7; } while (byte & 0x80); /* Sign-extend a negative value. */ if (shift < 8 * sizeof(result) && (byte & 0x40) != 0) result |= -(((_uleb128_t)1L) << shift); *val = (_sleb128_t) result; return p; } /* Load an encoded value from memory at P. The value is returned in VAL; The function returns P incremented past the value. BASE is as given by base_of_encoded_value for this encoding in the appropriate context. */ static const unsigned char * read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base, const unsigned char *p, _Unwind_Ptr *val #if defined (__e2k__) && defined (__ptr128__) , void **pval #endif /* defined (__e2k__) && defined (__ptr128__) */ ) { union unaligned { #if ! (defined (__e2k__) && defined (__ptr128__)) void *ptr; #else /* (defined (__e2k__) && defined (__ptr128__) */ _Unwind_Ptr ptr; #endif /* (defined (__e2k__) && defined (__ptr128__) */ unsigned u2 __attribute__ ((mode (HI))); unsigned u4 __attribute__ ((mode (SI))); unsigned u8 __attribute__ ((mode (DI))); signed s2 __attribute__ ((mode (HI))); signed s4 __attribute__ ((mode (SI))); signed s8 __attribute__ ((mode (DI))); } __attribute__((__packed__)); const union unaligned *u = (const union unaligned *) p; _Unwind_Internal_Ptr result; if (encoding == DW_EH_PE_aligned) { _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p; a = (a + sizeof (void *) - 1) & - sizeof(void *); #if ! (defined (__e2k__) && defined (__ptr128__)) result = *(_Unwind_Internal_Ptr *) a; p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *)); #else /* defined (__e2k__) && defined (__ptr128__) */ /* Do without conversion of an integer into a pointer when calculating an aligned pointer in PM. */ p += a - (_Unwind_Internal_Ptr) p; result = *(_Unwind_Internal_Ptr *) (void *) p; *pval = *(void **) (void *) p; p += sizeof (void *); #endif /* defined (__e2k__) && defined (__ptr128__) */ } else { switch (encoding & 0x0f) { case DW_EH_PE_absptr: result = (_Unwind_Internal_Ptr) u->ptr; #if ! (defined (__e2k__) && defined (__ptr128__)) p += sizeof (void *); #else /* defined (__e2k__) && defined (__ptr128__) */ p += sizeof (_Unwind_Ptr); #endif /* defined (__e2k__) && defined (__ptr128__) */ break; case DW_EH_PE_uleb128: { _uleb128_t tmp; p = read_uleb128 (p, &tmp); result = (_Unwind_Internal_Ptr) tmp; } break; case DW_EH_PE_sleb128: { _sleb128_t tmp; p = read_sleb128 (p, &tmp); result = (_Unwind_Internal_Ptr) tmp; } break; case DW_EH_PE_udata2: result = u->u2; p += 2; break; case DW_EH_PE_udata4: result = u->u4; p += 4; break; case DW_EH_PE_udata8: result = u->u8; p += 8; break; case DW_EH_PE_sdata2: result = u->s2; p += 2; break; case DW_EH_PE_sdata4: result = u->s4; p += 4; break; case DW_EH_PE_sdata8: result = u->s8; p += 8; break; default: __gxx_abort (); } if (result != 0) { result += ((encoding & 0x70) == DW_EH_PE_pcrel ? (_Unwind_Internal_Ptr) u : base); #if defined (__e2k__) && defined (__ptr128__) /* In Protected Mode U belongs to the data segment, while PC, being evaluated by means of DW_EH_PE_pcrel, to the text one. BASE takes into account the difference between the bases of these segments. */ if ((encoding & 0x70) == DW_EH_PE_pcrel) result += base; #endif /* defined (__e2k__) && defined (__ptr128__) */ if (encoding & DW_EH_PE_indirect) result = *(_Unwind_Internal_Ptr *) result; } } #if defined (__e2k__) && defined (__ptr128__) /* In PM VAL is of an inappropriate type for returning a pointer, which is why the user may pass NULL for it. */ if (val) #endif /* defined (__e2k__) && defined (__ptr128__) */ *val = result; return p; } #if defined (__e2k__) && defined (__ptr128__) static const unsigned char * read_encoded_ptr_with_base (unsigned char encoding, _Unwind_Ptr base, const unsigned char *p, void **pval) { return read_encoded_value_with_base (encoding, base, p, NULL, pval); } # ifndef NO_BASE_OF_ENCODED_VALUE static inline const unsigned char * read_encoded_ptr (struct _Unwind_Context *context, unsigned char encoding, const unsigned char *p, void **pval) { return read_encoded_ptr_with_base (encoding, base_of_encoded_value (encoding, context), p, pval); } # endif /* ! defined NO_BASE_OF_ENCODED_VALUE */ # define read_encoded_value_with_base(a, b, c, d) \ read_encoded_value_with_base (a, b, c, d, NULL) #endif /* defined (__e2k__) && defined (__ptr128__) */ #ifndef NO_BASE_OF_ENCODED_VALUE /* Like read_encoded_value_with_base, but get the base from the context rather than providing it directly. */ static inline const unsigned char * read_encoded_value (struct _Unwind_Context *context, unsigned char encoding, const unsigned char *p, _Unwind_Ptr *val) { return read_encoded_value_with_base (encoding, base_of_encoded_value (encoding, context), p, val); } #endif #endif /* unwind-pe.h */