mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			290 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			290 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* Exception handling and frame unwind runtime interface routines.
 | ||
|    Copyright (C) 2001-2014 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
 | ||
|    <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.  */
 | ||
| 
 | ||
| #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 (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)
 | ||
| {
 | ||
|   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__));
 | ||
| 
 | ||
|   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 *);
 | ||
|       result = *(_Unwind_Internal_Ptr *) a;
 | ||
|       p = (const unsigned char *) (_Unwind_Internal_Ptr) (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:
 | ||
| 	  {
 | ||
| 	    _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 (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 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 */
 |