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