Blame sysdeps/generic/unwind-pe.h

Packit 6c4009
/* Exception handling and frame unwind runtime interface routines.
Packit 6c4009
   Copyright (C) 2001-2018 Free Software Foundation, Inc.
Packit 6c4009
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* @@@ Really this should be out of line, but this also causes link
Packit 6c4009
   compatibility problems with the base ABI.  This is slightly better
Packit 6c4009
   than duplicating code, however.  */
Packit 6c4009
Packit 6c4009
/* If using C++, references to abort have to be qualified with std::.  */
Packit 6c4009
#ifdef __cplusplus
Packit 6c4009
#define __gxx_abort std::abort
Packit 6c4009
#else
Packit 6c4009
#define __gxx_abort abort
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Pointer encodings, from dwarf2.h.  */
Packit 6c4009
#define DW_EH_PE_absptr         0x00
Packit 6c4009
#define DW_EH_PE_omit           0xff
Packit 6c4009
Packit 6c4009
#define DW_EH_PE_uleb128        0x01
Packit 6c4009
#define DW_EH_PE_udata2         0x02
Packit 6c4009
#define DW_EH_PE_udata4         0x03
Packit 6c4009
#define DW_EH_PE_udata8         0x04
Packit 6c4009
#define DW_EH_PE_sleb128        0x09
Packit 6c4009
#define DW_EH_PE_sdata2         0x0A
Packit 6c4009
#define DW_EH_PE_sdata4         0x0B
Packit 6c4009
#define DW_EH_PE_sdata8         0x0C
Packit 6c4009
#define DW_EH_PE_signed         0x08
Packit 6c4009
Packit 6c4009
#define DW_EH_PE_pcrel          0x10
Packit 6c4009
#define DW_EH_PE_textrel        0x20
Packit 6c4009
#define DW_EH_PE_datarel        0x30
Packit 6c4009
#define DW_EH_PE_funcrel        0x40
Packit 6c4009
#define DW_EH_PE_aligned        0x50
Packit 6c4009
Packit 6c4009
#define DW_EH_PE_indirect	0x80
Packit 6c4009

Packit 6c4009
Packit 6c4009
#if defined(_LIBC)
Packit 6c4009
Packit 6c4009
/* Prototypes.  */
Packit 6c4009
extern unsigned int size_of_encoded_value (unsigned char encoding)
Packit 6c4009
  attribute_hidden;
Packit 6c4009
Packit 6c4009
extern const unsigned char *read_encoded_value_with_base
Packit 6c4009
  (unsigned char encoding, _Unwind_Ptr base,
Packit 6c4009
   const unsigned char *p, _Unwind_Ptr *val)
Packit 6c4009
  attribute_hidden;
Packit 6c4009
Packit 6c4009
extern const unsigned char * read_encoded_value
Packit 6c4009
  (struct _Unwind_Context *context, unsigned char encoding,
Packit 6c4009
   const unsigned char *p, _Unwind_Ptr *val)
Packit 6c4009
  attribute_hidden;
Packit 6c4009
Packit 6c4009
extern const unsigned char * read_uleb128 (const unsigned char *p,
Packit 6c4009
					   _Unwind_Word *val)
Packit 6c4009
  attribute_hidden;
Packit 6c4009
extern const unsigned char * read_sleb128 (const unsigned char *p,
Packit 6c4009
					   _Unwind_Sword *val)
Packit 6c4009
  attribute_hidden;
Packit 6c4009
Packit 6c4009
#endif
Packit 6c4009
#if defined(_LIBC) && defined(_LIBC_DEFINITIONS)
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
#define STATIC
Packit 6c4009
#else
Packit 6c4009
#define STATIC static
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Given an encoding, return the number of bytes the format occupies.
Packit 6c4009
   This is only defined for fixed-size encodings, and so does not
Packit 6c4009
   include leb128.  */
Packit 6c4009
Packit 6c4009
STATIC unsigned int
Packit 6c4009
size_of_encoded_value (unsigned char encoding)
Packit 6c4009
{
Packit 6c4009
  if (encoding == DW_EH_PE_omit)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  switch (encoding & 0x07)
Packit 6c4009
    {
Packit 6c4009
    case DW_EH_PE_absptr:
Packit 6c4009
      return sizeof (void *);
Packit 6c4009
    case DW_EH_PE_udata2:
Packit 6c4009
      return 2;
Packit 6c4009
    case DW_EH_PE_udata4:
Packit 6c4009
      return 4;
Packit 6c4009
    case DW_EH_PE_udata8:
Packit 6c4009
      return 8;
Packit 6c4009
    }
Packit 6c4009
  __gxx_abort ();
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifndef NO_BASE_OF_ENCODED_VALUE
Packit 6c4009
Packit 6c4009
/* Given an encoding and an _Unwind_Context, return the base to which
Packit 6c4009
   the encoding is relative.  This base may then be passed to
Packit 6c4009
   read_encoded_value_with_base for use when the _Unwind_Context is
Packit 6c4009
   not available.  */
Packit 6c4009
Packit 6c4009
STATIC _Unwind_Ptr
Packit 6c4009
base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
Packit 6c4009
{
Packit 6c4009
  if (encoding == DW_EH_PE_omit)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  switch (encoding & 0x70)
Packit 6c4009
    {
Packit 6c4009
    case DW_EH_PE_absptr:
Packit 6c4009
    case DW_EH_PE_pcrel:
Packit 6c4009
    case DW_EH_PE_aligned:
Packit 6c4009
      return 0;
Packit 6c4009
Packit 6c4009
    case DW_EH_PE_textrel:
Packit 6c4009
      return _Unwind_GetTextRelBase (context);
Packit 6c4009
    case DW_EH_PE_datarel:
Packit 6c4009
      return _Unwind_GetDataRelBase (context);
Packit 6c4009
    case DW_EH_PE_funcrel:
Packit 6c4009
      return _Unwind_GetRegionStart (context);
Packit 6c4009
    }
Packit 6c4009
  __gxx_abort ();
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Read an unsigned leb128 value from P, store the value in VAL, return
Packit 6c4009
   P incremented past the value.  We assume that a word is large enough to
Packit 6c4009
   hold any value so encoded; if it is smaller than a pointer on some target,
Packit 6c4009
   pointers should not be leb128 encoded on that target.  */
Packit 6c4009
Packit 6c4009
STATIC const unsigned char *
Packit 6c4009
read_uleb128 (const unsigned char *p, _Unwind_Word *val)
Packit 6c4009
{
Packit 6c4009
  unsigned int shift = 0;
Packit 6c4009
  unsigned char byte;
Packit 6c4009
  _Unwind_Word result;
Packit 6c4009
Packit 6c4009
  result = 0;
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      byte = *p++;
Packit 6c4009
      result |= (byte & 0x7f) << shift;
Packit 6c4009
      shift += 7;
Packit 6c4009
    }
Packit 6c4009
  while (byte & 0x80);
Packit 6c4009
Packit 6c4009
  *val = result;
Packit 6c4009
  return p;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Similar, but read a signed leb128 value.  */
Packit 6c4009
Packit 6c4009
STATIC const unsigned char *
Packit 6c4009
read_sleb128 (const unsigned char *p, _Unwind_Sword *val)
Packit 6c4009
{
Packit 6c4009
  unsigned int shift = 0;
Packit 6c4009
  unsigned char byte;
Packit 6c4009
  _Unwind_Word result;
Packit 6c4009
Packit 6c4009
  result = 0;
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      byte = *p++;
Packit 6c4009
      result |= (byte & 0x7f) << shift;
Packit 6c4009
      shift += 7;
Packit 6c4009
    }
Packit 6c4009
  while (byte & 0x80);
Packit 6c4009
Packit 6c4009
  /* Sign-extend a negative value.  */
Packit 6c4009
  if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
Packit 6c4009
    result |= -(1L << shift);
Packit 6c4009
Packit 6c4009
  *val = (_Unwind_Sword) result;
Packit 6c4009
  return p;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Load an encoded value from memory at P.  The value is returned in VAL;
Packit 6c4009
   The function returns P incremented past the value.  BASE is as given
Packit 6c4009
   by base_of_encoded_value for this encoding in the appropriate context.  */
Packit 6c4009
Packit 6c4009
STATIC const unsigned char *
Packit 6c4009
read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
Packit 6c4009
			      const unsigned char *p, _Unwind_Ptr *val)
Packit 6c4009
{
Packit 6c4009
  union unaligned
Packit 6c4009
    {
Packit 6c4009
      void *ptr;
Packit 6c4009
      unsigned u2 __attribute__ ((mode (HI)));
Packit 6c4009
      unsigned u4 __attribute__ ((mode (SI)));
Packit 6c4009
      unsigned u8 __attribute__ ((mode (DI)));
Packit 6c4009
      signed s2 __attribute__ ((mode (HI)));
Packit 6c4009
      signed s4 __attribute__ ((mode (SI)));
Packit 6c4009
      signed s8 __attribute__ ((mode (DI)));
Packit 6c4009
    } __attribute__((__packed__));
Packit 6c4009
Packit 6c4009
  union unaligned *u = (union unaligned *) p;
Packit 6c4009
  _Unwind_Internal_Ptr result;
Packit 6c4009
Packit 6c4009
  if (encoding == DW_EH_PE_aligned)
Packit 6c4009
    {
Packit 6c4009
      _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p;
Packit 6c4009
      a = (a + sizeof (void *) - 1) & - sizeof(void *);
Packit 6c4009
      result = *(_Unwind_Internal_Ptr *) a;
Packit 6c4009
      p = (const unsigned char *) (a + sizeof (void *));
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      switch (encoding & 0x0f)
Packit 6c4009
	{
Packit 6c4009
	case DW_EH_PE_absptr:
Packit 6c4009
	  result = (_Unwind_Internal_Ptr) u->ptr;
Packit 6c4009
	  p += sizeof (void *);
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_EH_PE_uleb128:
Packit 6c4009
	  {
Packit 6c4009
	    _Unwind_Word tmp;
Packit 6c4009
	    p = read_uleb128 (p, &tmp);
Packit 6c4009
	    result = (_Unwind_Internal_Ptr) tmp;
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_EH_PE_sleb128:
Packit 6c4009
	  {
Packit 6c4009
	    _Unwind_Sword tmp;
Packit 6c4009
	    p = read_sleb128 (p, &tmp);
Packit 6c4009
	    result = (_Unwind_Internal_Ptr) tmp;
Packit 6c4009
	  }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_EH_PE_udata2:
Packit 6c4009
	  result = u->u2;
Packit 6c4009
	  p += 2;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_EH_PE_udata4:
Packit 6c4009
	  result = u->u4;
Packit 6c4009
	  p += 4;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_EH_PE_udata8:
Packit 6c4009
	  result = u->u8;
Packit 6c4009
	  p += 8;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case DW_EH_PE_sdata2:
Packit 6c4009
	  result = u->s2;
Packit 6c4009
	  p += 2;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_EH_PE_sdata4:
Packit 6c4009
	  result = u->s4;
Packit 6c4009
	  p += 4;
Packit 6c4009
	  break;
Packit 6c4009
	case DW_EH_PE_sdata8:
Packit 6c4009
	  result = u->s8;
Packit 6c4009
	  p += 8;
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	default:
Packit 6c4009
	  __gxx_abort ();
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (result != 0)
Packit 6c4009
	{
Packit 6c4009
	  result += ((encoding & 0x70) == DW_EH_PE_pcrel
Packit 6c4009
		     ? (_Unwind_Internal_Ptr) u : base);
Packit 6c4009
	  if (encoding & DW_EH_PE_indirect)
Packit 6c4009
	    result = *(_Unwind_Internal_Ptr *) result;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  *val = result;
Packit 6c4009
  return p;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#ifndef NO_BASE_OF_ENCODED_VALUE
Packit 6c4009
Packit 6c4009
/* Like read_encoded_value_with_base, but get the base from the context
Packit 6c4009
   rather than providing it directly.  */
Packit 6c4009
Packit 6c4009
STATIC const unsigned char *
Packit 6c4009
read_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
Packit 6c4009
		    const unsigned char *p, _Unwind_Ptr *val)
Packit 6c4009
{
Packit 6c4009
  return read_encoded_value_with_base (encoding,
Packit 6c4009
		base_of_encoded_value (encoding, context),
Packit 6c4009
		p, val);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#endif
Packit 6c4009
#endif /* _LIBC */