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