unwind-pe.h revision 117395
190075Sobrien/* Exception handling and frame unwind runtime interface routines.
290075Sobrien   Copyright (C) 2001, 2002 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
1190075Sobrien   GCC is distributed in the hope that it will be useful, but WITHOUT
1290075Sobrien   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1390075Sobrien   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
1490075Sobrien   License for more details.
1590075Sobrien
1690075Sobrien   You should have received a copy of the GNU General Public License
1790075Sobrien   along with GCC; see the file COPYING.  If not, write to the Free
1890075Sobrien   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
1990075Sobrien   02111-1307, USA.  */
2090075Sobrien
2190075Sobrien/* @@@ Really this should be out of line, but this also causes link
2290075Sobrien   compatibility problems with the base ABI.  This is slightly better
2390075Sobrien   than duplicating code, however.  */
2490075Sobrien
2590075Sobrien/* If using C++, references to abort have to be qualified with std::.  */
2690075Sobrien#if __cplusplus
2790075Sobrien#define __gxx_abort std::abort
2890075Sobrien#else
2990075Sobrien#define __gxx_abort abort
3090075Sobrien#endif
3190075Sobrien
3290075Sobrien/* Pointer encodings, from dwarf2.h.  */
3390075Sobrien#define DW_EH_PE_absptr         0x00
3490075Sobrien#define DW_EH_PE_omit           0xff
3590075Sobrien
3690075Sobrien#define DW_EH_PE_uleb128        0x01
3790075Sobrien#define DW_EH_PE_udata2         0x02
3890075Sobrien#define DW_EH_PE_udata4         0x03
3990075Sobrien#define DW_EH_PE_udata8         0x04
4090075Sobrien#define DW_EH_PE_sleb128        0x09
4190075Sobrien#define DW_EH_PE_sdata2         0x0A
4290075Sobrien#define DW_EH_PE_sdata4         0x0B
4390075Sobrien#define DW_EH_PE_sdata8         0x0C
4490075Sobrien#define DW_EH_PE_signed         0x08
4590075Sobrien
4690075Sobrien#define DW_EH_PE_pcrel          0x10
4790075Sobrien#define DW_EH_PE_textrel        0x20
4890075Sobrien#define DW_EH_PE_datarel        0x30
4990075Sobrien#define DW_EH_PE_funcrel        0x40
5090075Sobrien#define DW_EH_PE_aligned        0x50
5190075Sobrien
5290075Sobrien#define DW_EH_PE_indirect	0x80
5390075Sobrien
5490075Sobrien
5590075Sobrien/* Given an encoding, return the number of bytes the format occupies.
5690075Sobrien   This is only defined for fixed-size encodings, and so does not
5790075Sobrien   include leb128.  */
5890075Sobrien
5990075Sobrienstatic unsigned int
6090075Sobriensize_of_encoded_value (unsigned char encoding)
6190075Sobrien{
6290075Sobrien  if (encoding == DW_EH_PE_omit)
6390075Sobrien    return 0;
6490075Sobrien
6590075Sobrien  switch (encoding & 0x07)
6690075Sobrien    {
6790075Sobrien    case DW_EH_PE_absptr:
6890075Sobrien      return sizeof (void *);
6990075Sobrien    case DW_EH_PE_udata2:
7090075Sobrien      return 2;
7190075Sobrien    case DW_EH_PE_udata4:
7290075Sobrien      return 4;
7390075Sobrien    case DW_EH_PE_udata8:
7490075Sobrien      return 8;
7590075Sobrien    }
7690075Sobrien  __gxx_abort ();
7790075Sobrien}
7890075Sobrien
7990075Sobrien#ifndef NO_BASE_OF_ENCODED_VALUE
8090075Sobrien
8190075Sobrien/* Given an encoding and an _Unwind_Context, return the base to which
8290075Sobrien   the encoding is relative.  This base may then be passed to
8390075Sobrien   read_encoded_value_with_base for use when the _Unwind_Context is
8490075Sobrien   not available.  */
8590075Sobrien
8690075Sobrienstatic _Unwind_Ptr
8790075Sobrienbase_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
8890075Sobrien{
8990075Sobrien  if (encoding == DW_EH_PE_omit)
9090075Sobrien    return 0;
9190075Sobrien
9290075Sobrien  switch (encoding & 0x70)
9390075Sobrien    {
9490075Sobrien    case DW_EH_PE_absptr:
9590075Sobrien    case DW_EH_PE_pcrel:
9690075Sobrien    case DW_EH_PE_aligned:
9790075Sobrien      return 0;
9890075Sobrien
9990075Sobrien    case DW_EH_PE_textrel:
10090075Sobrien      return _Unwind_GetTextRelBase (context);
10190075Sobrien    case DW_EH_PE_datarel:
10290075Sobrien      return _Unwind_GetDataRelBase (context);
10390075Sobrien    case DW_EH_PE_funcrel:
10490075Sobrien      return _Unwind_GetRegionStart (context);
10590075Sobrien    }
10690075Sobrien  __gxx_abort ();
10790075Sobrien}
10890075Sobrien
10990075Sobrien#endif
11090075Sobrien
11190075Sobrien/* Read an unsigned leb128 value from P, store the value in VAL, return
11290075Sobrien   P incremented past the value.  We assume that a word is large enough to
11390075Sobrien   hold any value so encoded; if it is smaller than a pointer on some target,
11490075Sobrien   pointers should not be leb128 encoded on that target.  */
11590075Sobrien
11690075Sobrienstatic const unsigned char *
11790075Sobrienread_uleb128 (const unsigned char *p, _Unwind_Word *val)
11890075Sobrien{
11990075Sobrien  unsigned int shift = 0;
12090075Sobrien  unsigned char byte;
12190075Sobrien  _Unwind_Word result;
12290075Sobrien
12390075Sobrien  result = 0;
12490075Sobrien  do
12590075Sobrien    {
12690075Sobrien      byte = *p++;
12790075Sobrien      result |= (byte & 0x7f) << shift;
12890075Sobrien      shift += 7;
12990075Sobrien    }
13090075Sobrien  while (byte & 0x80);
13190075Sobrien
13290075Sobrien  *val = result;
13390075Sobrien  return p;
13490075Sobrien}
13590075Sobrien
13690075Sobrien/* Similar, but read a signed leb128 value.  */
13790075Sobrien
13890075Sobrienstatic const unsigned char *
13990075Sobrienread_sleb128 (const unsigned char *p, _Unwind_Sword *val)
14090075Sobrien{
14190075Sobrien  unsigned int shift = 0;
14290075Sobrien  unsigned char byte;
14390075Sobrien  _Unwind_Word result;
14490075Sobrien
14590075Sobrien  result = 0;
14690075Sobrien  do
14790075Sobrien    {
14890075Sobrien      byte = *p++;
14990075Sobrien      result |= (byte & 0x7f) << shift;
15090075Sobrien      shift += 7;
15190075Sobrien    }
15290075Sobrien  while (byte & 0x80);
15390075Sobrien
15490075Sobrien  /* Sign-extend a negative value.  */
15590075Sobrien  if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
15690075Sobrien    result |= -(1L << shift);
15790075Sobrien
15890075Sobrien  *val = (_Unwind_Sword) result;
15990075Sobrien  return p;
16090075Sobrien}
16190075Sobrien
16290075Sobrien/* Load an encoded value from memory at P.  The value is returned in VAL;
16390075Sobrien   The function returns P incremented past the value.  BASE is as given
16490075Sobrien   by base_of_encoded_value for this encoding in the appropriate context.  */
16590075Sobrien
16690075Sobrienstatic const unsigned char *
16790075Sobrienread_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
16890075Sobrien			      const unsigned char *p, _Unwind_Ptr *val)
16990075Sobrien{
17090075Sobrien  union unaligned
17190075Sobrien    {
17290075Sobrien      void *ptr;
17390075Sobrien      unsigned u2 __attribute__ ((mode (HI)));
17490075Sobrien      unsigned u4 __attribute__ ((mode (SI)));
17590075Sobrien      unsigned u8 __attribute__ ((mode (DI)));
17690075Sobrien      signed s2 __attribute__ ((mode (HI)));
17790075Sobrien      signed s4 __attribute__ ((mode (SI)));
17890075Sobrien      signed s8 __attribute__ ((mode (DI)));
17990075Sobrien    } __attribute__((__packed__));
18090075Sobrien
18190075Sobrien  union unaligned *u = (union unaligned *) p;
182117395Skan  _Unwind_Internal_Ptr result;
18390075Sobrien
18490075Sobrien  if (encoding == DW_EH_PE_aligned)
18590075Sobrien    {
186117395Skan      _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p;
18790075Sobrien      a = (a + sizeof (void *) - 1) & - sizeof(void *);
188117395Skan      result = *(_Unwind_Internal_Ptr *) a;
18990075Sobrien      p = (const unsigned char *) (a + sizeof (void *));
19090075Sobrien    }
19190075Sobrien  else
19290075Sobrien    {
19390075Sobrien      switch (encoding & 0x0f)
19490075Sobrien	{
19590075Sobrien	case DW_EH_PE_absptr:
196117395Skan	  result = (_Unwind_Internal_Ptr) u->ptr;
19790075Sobrien	  p += sizeof (void *);
19890075Sobrien	  break;
19990075Sobrien
20090075Sobrien	case DW_EH_PE_uleb128:
20190075Sobrien	  {
20290075Sobrien	    _Unwind_Word tmp;
20390075Sobrien	    p = read_uleb128 (p, &tmp);
204117395Skan	    result = (_Unwind_Internal_Ptr) tmp;
20590075Sobrien	  }
20690075Sobrien	  break;
20790075Sobrien
20890075Sobrien	case DW_EH_PE_sleb128:
20990075Sobrien	  {
21090075Sobrien	    _Unwind_Sword tmp;
21190075Sobrien	    p = read_sleb128 (p, &tmp);
212117395Skan	    result = (_Unwind_Internal_Ptr) tmp;
21390075Sobrien	  }
21490075Sobrien	  break;
21590075Sobrien
21690075Sobrien	case DW_EH_PE_udata2:
21790075Sobrien	  result = u->u2;
21890075Sobrien	  p += 2;
21990075Sobrien	  break;
22090075Sobrien	case DW_EH_PE_udata4:
22190075Sobrien	  result = u->u4;
22290075Sobrien	  p += 4;
22390075Sobrien	  break;
22490075Sobrien	case DW_EH_PE_udata8:
22590075Sobrien	  result = u->u8;
22690075Sobrien	  p += 8;
22790075Sobrien	  break;
22890075Sobrien
22990075Sobrien	case DW_EH_PE_sdata2:
23090075Sobrien	  result = u->s2;
23190075Sobrien	  p += 2;
23290075Sobrien	  break;
23390075Sobrien	case DW_EH_PE_sdata4:
23490075Sobrien	  result = u->s4;
23590075Sobrien	  p += 4;
23690075Sobrien	  break;
23790075Sobrien	case DW_EH_PE_sdata8:
23890075Sobrien	  result = u->s8;
23990075Sobrien	  p += 8;
24090075Sobrien	  break;
24190075Sobrien
24290075Sobrien	default:
24390075Sobrien	  __gxx_abort ();
24490075Sobrien	}
24590075Sobrien
24690075Sobrien      if (result != 0)
24790075Sobrien	{
24890075Sobrien	  result += ((encoding & 0x70) == DW_EH_PE_pcrel
249117395Skan		     ? (_Unwind_Internal_Ptr) u : base);
25090075Sobrien	  if (encoding & DW_EH_PE_indirect)
251117395Skan	    result = *(_Unwind_Internal_Ptr *) result;
25290075Sobrien	}
25390075Sobrien    }
25490075Sobrien
25590075Sobrien  *val = result;
25690075Sobrien  return p;
25790075Sobrien}
25890075Sobrien
25990075Sobrien#ifndef NO_BASE_OF_ENCODED_VALUE
26090075Sobrien
26190075Sobrien/* Like read_encoded_value_with_base, but get the base from the context
26290075Sobrien   rather than providing it directly.  */
26390075Sobrien
26490075Sobrienstatic inline const unsigned char *
26590075Sobrienread_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
26690075Sobrien		    const unsigned char *p, _Unwind_Ptr *val)
26790075Sobrien{
26890075Sobrien  return read_encoded_value_with_base (encoding,
26990075Sobrien		base_of_encoded_value (encoding, context),
27090075Sobrien		p, val);
27190075Sobrien}
27290075Sobrien
27390075Sobrien#endif
274