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