190075Sobrien/* Exception handling and frame unwind runtime interface routines.
2132718Skan   Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
390075Sobrien
490075Sobrien   This file is part of GCC.
590075Sobrien
690075Sobrien   GCC is free software; you can redistribute it and/or modify it
790075Sobrien   under the terms of the GNU General Public License as published by
890075Sobrien   the Free Software Foundation; either version 2, or (at your option)
990075Sobrien   any later version.
1090075Sobrien
11132718Skan   In addition to the permissions in the GNU General Public License, the
12132718Skan   Free Software Foundation gives you unlimited permission to link the
13132718Skan   compiled version of this file into combinations with other programs,
14132718Skan   and to distribute those combinations without any restriction coming
15132718Skan   from the use of this file.  (The General Public License restrictions
16132718Skan   do apply in other respects; for example, they cover modification of
17132718Skan   the file, and distribution when not linked into a combined
18132718Skan   executable.)
19132718Skan
2090075Sobrien   GCC is distributed in the hope that it will be useful, but WITHOUT
2190075Sobrien   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
2290075Sobrien   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
2390075Sobrien   License for more details.
2490075Sobrien
2590075Sobrien   You should have received a copy of the GNU General Public License
2690075Sobrien   along with GCC; see the file COPYING.  If not, write to the Free
27169689Skan   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
28169689Skan   02110-1301, USA.  */
2990075Sobrien
3090075Sobrien/* @@@ Really this should be out of line, but this also causes link
3190075Sobrien   compatibility problems with the base ABI.  This is slightly better
3290075Sobrien   than duplicating code, however.  */
3390075Sobrien
34132718Skan#ifndef GCC_UNWIND_PE_H
35132718Skan#define GCC_UNWIND_PE_H
36132718Skan
3790075Sobrien/* If using C++, references to abort have to be qualified with std::.  */
3890075Sobrien#if __cplusplus
3990075Sobrien#define __gxx_abort std::abort
4090075Sobrien#else
4190075Sobrien#define __gxx_abort abort
4290075Sobrien#endif
4390075Sobrien
4490075Sobrien/* Pointer encodings, from dwarf2.h.  */
4590075Sobrien#define DW_EH_PE_absptr         0x00
4690075Sobrien#define DW_EH_PE_omit           0xff
4790075Sobrien
4890075Sobrien#define DW_EH_PE_uleb128        0x01
4990075Sobrien#define DW_EH_PE_udata2         0x02
5090075Sobrien#define DW_EH_PE_udata4         0x03
5190075Sobrien#define DW_EH_PE_udata8         0x04
5290075Sobrien#define DW_EH_PE_sleb128        0x09
5390075Sobrien#define DW_EH_PE_sdata2         0x0A
5490075Sobrien#define DW_EH_PE_sdata4         0x0B
5590075Sobrien#define DW_EH_PE_sdata8         0x0C
5690075Sobrien#define DW_EH_PE_signed         0x08
5790075Sobrien
5890075Sobrien#define DW_EH_PE_pcrel          0x10
5990075Sobrien#define DW_EH_PE_textrel        0x20
6090075Sobrien#define DW_EH_PE_datarel        0x30
6190075Sobrien#define DW_EH_PE_funcrel        0x40
6290075Sobrien#define DW_EH_PE_aligned        0x50
6390075Sobrien
6490075Sobrien#define DW_EH_PE_indirect	0x80
6590075Sobrien
6690075Sobrien
67132718Skan#ifndef NO_SIZE_OF_ENCODED_VALUE
68132718Skan
6990075Sobrien/* Given an encoding, return the number of bytes the format occupies.
7090075Sobrien   This is only defined for fixed-size encodings, and so does not
7190075Sobrien   include leb128.  */
7290075Sobrien
7390075Sobrienstatic unsigned int
7490075Sobriensize_of_encoded_value (unsigned char encoding)
7590075Sobrien{
7690075Sobrien  if (encoding == DW_EH_PE_omit)
7790075Sobrien    return 0;
7890075Sobrien
7990075Sobrien  switch (encoding & 0x07)
8090075Sobrien    {
8190075Sobrien    case DW_EH_PE_absptr:
8290075Sobrien      return sizeof (void *);
8390075Sobrien    case DW_EH_PE_udata2:
8490075Sobrien      return 2;
8590075Sobrien    case DW_EH_PE_udata4:
8690075Sobrien      return 4;
8790075Sobrien    case DW_EH_PE_udata8:
8890075Sobrien      return 8;
8990075Sobrien    }
9090075Sobrien  __gxx_abort ();
9190075Sobrien}
9290075Sobrien
93132718Skan#endif
94132718Skan
9590075Sobrien#ifndef NO_BASE_OF_ENCODED_VALUE
9690075Sobrien
9790075Sobrien/* Given an encoding and an _Unwind_Context, return the base to which
9890075Sobrien   the encoding is relative.  This base may then be passed to
9990075Sobrien   read_encoded_value_with_base for use when the _Unwind_Context is
10090075Sobrien   not available.  */
10190075Sobrien
10290075Sobrienstatic _Unwind_Ptr
10390075Sobrienbase_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
10490075Sobrien{
10590075Sobrien  if (encoding == DW_EH_PE_omit)
10690075Sobrien    return 0;
10790075Sobrien
10890075Sobrien  switch (encoding & 0x70)
10990075Sobrien    {
11090075Sobrien    case DW_EH_PE_absptr:
11190075Sobrien    case DW_EH_PE_pcrel:
11290075Sobrien    case DW_EH_PE_aligned:
11390075Sobrien      return 0;
11490075Sobrien
11590075Sobrien    case DW_EH_PE_textrel:
11690075Sobrien      return _Unwind_GetTextRelBase (context);
11790075Sobrien    case DW_EH_PE_datarel:
11890075Sobrien      return _Unwind_GetDataRelBase (context);
11990075Sobrien    case DW_EH_PE_funcrel:
12090075Sobrien      return _Unwind_GetRegionStart (context);
12190075Sobrien    }
12290075Sobrien  __gxx_abort ();
12390075Sobrien}
12490075Sobrien
12590075Sobrien#endif
12690075Sobrien
12790075Sobrien/* Read an unsigned leb128 value from P, store the value in VAL, return
12890075Sobrien   P incremented past the value.  We assume that a word is large enough to
12990075Sobrien   hold any value so encoded; if it is smaller than a pointer on some target,
13090075Sobrien   pointers should not be leb128 encoded on that target.  */
13190075Sobrien
13290075Sobrienstatic const unsigned char *
13390075Sobrienread_uleb128 (const unsigned char *p, _Unwind_Word *val)
13490075Sobrien{
13590075Sobrien  unsigned int shift = 0;
13690075Sobrien  unsigned char byte;
13790075Sobrien  _Unwind_Word result;
13890075Sobrien
13990075Sobrien  result = 0;
14090075Sobrien  do
14190075Sobrien    {
14290075Sobrien      byte = *p++;
143132718Skan      result |= ((_Unwind_Word)byte & 0x7f) << shift;
14490075Sobrien      shift += 7;
14590075Sobrien    }
14690075Sobrien  while (byte & 0x80);
14790075Sobrien
14890075Sobrien  *val = result;
14990075Sobrien  return p;
15090075Sobrien}
15190075Sobrien
15290075Sobrien/* Similar, but read a signed leb128 value.  */
15390075Sobrien
15490075Sobrienstatic const unsigned char *
15590075Sobrienread_sleb128 (const unsigned char *p, _Unwind_Sword *val)
15690075Sobrien{
15790075Sobrien  unsigned int shift = 0;
15890075Sobrien  unsigned char byte;
15990075Sobrien  _Unwind_Word result;
16090075Sobrien
16190075Sobrien  result = 0;
16290075Sobrien  do
16390075Sobrien    {
16490075Sobrien      byte = *p++;
165132718Skan      result |= ((_Unwind_Word)byte & 0x7f) << shift;
16690075Sobrien      shift += 7;
16790075Sobrien    }
16890075Sobrien  while (byte & 0x80);
16990075Sobrien
17090075Sobrien  /* Sign-extend a negative value.  */
17190075Sobrien  if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
172132718Skan    result |= -(((_Unwind_Word)1L) << shift);
17390075Sobrien
17490075Sobrien  *val = (_Unwind_Sword) result;
17590075Sobrien  return p;
17690075Sobrien}
17790075Sobrien
17890075Sobrien/* Load an encoded value from memory at P.  The value is returned in VAL;
17990075Sobrien   The function returns P incremented past the value.  BASE is as given
18090075Sobrien   by base_of_encoded_value for this encoding in the appropriate context.  */
18190075Sobrien
18290075Sobrienstatic const unsigned char *
18390075Sobrienread_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
18490075Sobrien			      const unsigned char *p, _Unwind_Ptr *val)
18590075Sobrien{
18690075Sobrien  union unaligned
18790075Sobrien    {
18890075Sobrien      void *ptr;
18990075Sobrien      unsigned u2 __attribute__ ((mode (HI)));
19090075Sobrien      unsigned u4 __attribute__ ((mode (SI)));
19190075Sobrien      unsigned u8 __attribute__ ((mode (DI)));
19290075Sobrien      signed s2 __attribute__ ((mode (HI)));
19390075Sobrien      signed s4 __attribute__ ((mode (SI)));
19490075Sobrien      signed s8 __attribute__ ((mode (DI)));
19590075Sobrien    } __attribute__((__packed__));
19690075Sobrien
197132718Skan  const union unaligned *u = (const union unaligned *) p;
198117395Skan  _Unwind_Internal_Ptr result;
19990075Sobrien
20090075Sobrien  if (encoding == DW_EH_PE_aligned)
20190075Sobrien    {
202117395Skan      _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p;
20390075Sobrien      a = (a + sizeof (void *) - 1) & - sizeof(void *);
204117395Skan      result = *(_Unwind_Internal_Ptr *) a;
205132718Skan      p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *));
20690075Sobrien    }
20790075Sobrien  else
20890075Sobrien    {
20990075Sobrien      switch (encoding & 0x0f)
21090075Sobrien	{
21190075Sobrien	case DW_EH_PE_absptr:
212117395Skan	  result = (_Unwind_Internal_Ptr) u->ptr;
21390075Sobrien	  p += sizeof (void *);
21490075Sobrien	  break;
21590075Sobrien
21690075Sobrien	case DW_EH_PE_uleb128:
21790075Sobrien	  {
21890075Sobrien	    _Unwind_Word tmp;
21990075Sobrien	    p = read_uleb128 (p, &tmp);
220117395Skan	    result = (_Unwind_Internal_Ptr) tmp;
22190075Sobrien	  }
22290075Sobrien	  break;
22390075Sobrien
22490075Sobrien	case DW_EH_PE_sleb128:
22590075Sobrien	  {
22690075Sobrien	    _Unwind_Sword tmp;
22790075Sobrien	    p = read_sleb128 (p, &tmp);
228117395Skan	    result = (_Unwind_Internal_Ptr) tmp;
22990075Sobrien	  }
23090075Sobrien	  break;
23190075Sobrien
23290075Sobrien	case DW_EH_PE_udata2:
23390075Sobrien	  result = u->u2;
23490075Sobrien	  p += 2;
23590075Sobrien	  break;
23690075Sobrien	case DW_EH_PE_udata4:
23790075Sobrien	  result = u->u4;
23890075Sobrien	  p += 4;
23990075Sobrien	  break;
24090075Sobrien	case DW_EH_PE_udata8:
24190075Sobrien	  result = u->u8;
24290075Sobrien	  p += 8;
24390075Sobrien	  break;
24490075Sobrien
24590075Sobrien	case DW_EH_PE_sdata2:
24690075Sobrien	  result = u->s2;
24790075Sobrien	  p += 2;
24890075Sobrien	  break;
24990075Sobrien	case DW_EH_PE_sdata4:
25090075Sobrien	  result = u->s4;
25190075Sobrien	  p += 4;
25290075Sobrien	  break;
25390075Sobrien	case DW_EH_PE_sdata8:
25490075Sobrien	  result = u->s8;
25590075Sobrien	  p += 8;
25690075Sobrien	  break;
25790075Sobrien
25890075Sobrien	default:
25990075Sobrien	  __gxx_abort ();
26090075Sobrien	}
26190075Sobrien
26290075Sobrien      if (result != 0)
26390075Sobrien	{
26490075Sobrien	  result += ((encoding & 0x70) == DW_EH_PE_pcrel
265117395Skan		     ? (_Unwind_Internal_Ptr) u : base);
26690075Sobrien	  if (encoding & DW_EH_PE_indirect)
267117395Skan	    result = *(_Unwind_Internal_Ptr *) result;
26890075Sobrien	}
26990075Sobrien    }
27090075Sobrien
27190075Sobrien  *val = result;
27290075Sobrien  return p;
27390075Sobrien}
27490075Sobrien
27590075Sobrien#ifndef NO_BASE_OF_ENCODED_VALUE
27690075Sobrien
27790075Sobrien/* Like read_encoded_value_with_base, but get the base from the context
27890075Sobrien   rather than providing it directly.  */
27990075Sobrien
28090075Sobrienstatic inline const unsigned char *
28190075Sobrienread_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
28290075Sobrien		    const unsigned char *p, _Unwind_Ptr *val)
28390075Sobrien{
28490075Sobrien  return read_encoded_value_with_base (encoding,
28590075Sobrien		base_of_encoded_value (encoding, context),
28690075Sobrien		p, val);
28790075Sobrien}
28890075Sobrien
28990075Sobrien#endif
290132718Skan
291132718Skan#endif /* unwind-pe.h */
292