|  | /* Exception handling and frame unwind runtime interface routines. | 
|  | Copyright (C) 2001-2016 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of the GNU C Library. | 
|  |  | 
|  | The GNU C Library is free software; you can redistribute it and/or | 
|  | modify it under the terms of the GNU Lesser General Public | 
|  | License as published by the Free Software Foundation; either | 
|  | version 2.1 of the License, or (at your option) any later version. | 
|  |  | 
|  | The GNU C Library 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 | 
|  | Lesser General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU Lesser General Public | 
|  | License along with the GNU C Library; if not, see | 
|  | <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | /* @@@ 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.  */ | 
|  |  | 
|  | /* If using C++, references to abort have to be qualified with std::.  */ | 
|  | #ifdef __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 | 
|  |  | 
|  |  | 
|  | #if defined(_LIBC) | 
|  |  | 
|  | /* Prototypes.  */ | 
|  | extern unsigned int size_of_encoded_value (unsigned char encoding) | 
|  | attribute_hidden; | 
|  |  | 
|  | extern const unsigned char *read_encoded_value_with_base | 
|  | (unsigned char encoding, _Unwind_Ptr base, | 
|  | const unsigned char *p, _Unwind_Ptr *val) | 
|  | attribute_hidden; | 
|  |  | 
|  | extern const unsigned char * read_encoded_value | 
|  | (struct _Unwind_Context *context, unsigned char encoding, | 
|  | const unsigned char *p, _Unwind_Ptr *val) | 
|  | attribute_hidden; | 
|  |  | 
|  | extern const unsigned char * read_uleb128 (const unsigned char *p, | 
|  | _Unwind_Word *val) | 
|  | attribute_hidden; | 
|  | extern const unsigned char * read_sleb128 (const unsigned char *p, | 
|  | _Unwind_Sword *val) | 
|  | attribute_hidden; | 
|  |  | 
|  | #endif | 
|  | #if defined(_LIBC) && defined(_LIBC_DEFINITIONS) | 
|  |  | 
|  | #ifdef _LIBC | 
|  | #define STATIC | 
|  | #else | 
|  | #define STATIC static | 
|  | #endif | 
|  |  | 
|  | /* 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) | 
|  | { | 
|  | 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 (); | 
|  | } | 
|  |  | 
|  | #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, _Unwind_Word *val) | 
|  | { | 
|  | unsigned int shift = 0; | 
|  | unsigned char byte; | 
|  | _Unwind_Word result; | 
|  |  | 
|  | result = 0; | 
|  | do | 
|  | { | 
|  | byte = *p++; | 
|  | result |= (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, _Unwind_Sword *val) | 
|  | { | 
|  | unsigned int shift = 0; | 
|  | unsigned char byte; | 
|  | _Unwind_Word result; | 
|  |  | 
|  | result = 0; | 
|  | do | 
|  | { | 
|  | byte = *p++; | 
|  | result |= (byte & 0x7f) << shift; | 
|  | shift += 7; | 
|  | } | 
|  | while (byte & 0x80); | 
|  |  | 
|  | /* Sign-extend a negative value.  */ | 
|  | if (shift < 8 * sizeof(result) && (byte & 0x40) != 0) | 
|  | result |= -(1L << shift); | 
|  |  | 
|  | *val = (_Unwind_Sword) 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) | 
|  | { | 
|  | union unaligned | 
|  | { | 
|  | void *ptr; | 
|  | 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__)); | 
|  |  | 
|  | union unaligned *u = (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 *); | 
|  | result = *(_Unwind_Internal_Ptr *) a; | 
|  | p = (const unsigned char *) (a + sizeof (void *)); | 
|  | } | 
|  | else | 
|  | { | 
|  | switch (encoding & 0x0f) | 
|  | { | 
|  | case DW_EH_PE_absptr: | 
|  | result = (_Unwind_Internal_Ptr) u->ptr; | 
|  | p += sizeof (void *); | 
|  | break; | 
|  |  | 
|  | case DW_EH_PE_uleb128: | 
|  | { | 
|  | _Unwind_Word tmp; | 
|  | p = read_uleb128 (p, &tmp); | 
|  | result = (_Unwind_Internal_Ptr) tmp; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case DW_EH_PE_sleb128: | 
|  | { | 
|  | _Unwind_Sword 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 (encoding & DW_EH_PE_indirect) | 
|  | result = *(_Unwind_Internal_Ptr *) result; | 
|  | } | 
|  | } | 
|  |  | 
|  | *val = result; | 
|  | return p; | 
|  | } | 
|  |  | 
|  | #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 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 /* _LIBC */ |