mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-10-24 13:33:08 +03:00 
			
		
		
		
	* sysdeps/generic/unwind.h: Change copyright terms from GCC GPL to standard glibc LGPL. * sysdeps/generic/unwind-dw2.c: Likewise. * sysdeps/generic/unwind-dw2-fde.c: Likewise. * sysdeps/generic/unwind-dw2-fde.h: Likewise. * sysdeps/generic/unwind-pe.h: Likewise.
		
			
				
	
	
		
			307 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			307 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Exception handling and frame unwind runtime interface routines.
 | ||
|    Copyright (C) 2001, 2002 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, write to the Free
 | ||
|    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 | ||
|    02111-1307 USA.  */
 | ||
| 
 | ||
| /* @@@ 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::.  */
 | ||
| #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
 | ||
| 
 | ||
| 
 | ||
| #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 */
 |