1251881Speter/* Exception handling and frame unwind runtime interface routines. 2251881Speter Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. 3251881Speter 4251881Speter This file is part of GCC. 5251881Speter 6251881Speter GCC is free software; you can redistribute it and/or modify it 7251881Speter under the terms of the GNU General Public License as published by 8251881Speter the Free Software Foundation; either version 2, or (at your option) 9251881Speter any later version. 10251881Speter 11251881Speter In addition to the permissions in the GNU General Public License, the 12251881Speter Free Software Foundation gives you unlimited permission to link the 13251881Speter compiled version of this file into combinations with other programs, 14251881Speter and to distribute those combinations without any restriction coming 15251881Speter from the use of this file. (The General Public License restrictions 16251881Speter do apply in other respects; for example, they cover modification of 17251881Speter the file, and distribution when not linked into a combined 18251881Speter executable.) 19251881Speter 20251881Speter GCC is distributed in the hope that it will be useful, but WITHOUT 21251881Speter ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 22251881Speter or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 23251881Speter License for more details. 24251881Speter 25251881Speter You should have received a copy of the GNU General Public License 26251881Speter along with GCC; see the file COPYING. If not, write to the Free 27251881Speter Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 28251881Speter 02110-1301, USA. */ 29251881Speter 30251881Speter/* @@@ Really this should be out of line, but this also causes link 31251881Speter compatibility problems with the base ABI. This is slightly better 32251881Speter than duplicating code, however. */ 33251881Speter 34251881Speter#ifndef GCC_UNWIND_PE_H 35251881Speter#define GCC_UNWIND_PE_H 36251881Speter 37251881Speter/* If using C++, references to abort have to be qualified with std::. */ 38251881Speter#if __cplusplus 39251881Speter#define __gxx_abort std::abort 40251881Speter#else 41251881Speter#define __gxx_abort abort 42251881Speter#endif 43251881Speter 44251881Speter/* Pointer encodings, from dwarf2.h. */ 45251881Speter#define DW_EH_PE_absptr 0x00 46251881Speter#define DW_EH_PE_omit 0xff 47251881Speter 48251881Speter#define DW_EH_PE_uleb128 0x01 49251881Speter#define DW_EH_PE_udata2 0x02 50251881Speter#define DW_EH_PE_udata4 0x03 51251881Speter#define DW_EH_PE_udata8 0x04 52251881Speter#define DW_EH_PE_sleb128 0x09 53251881Speter#define DW_EH_PE_sdata2 0x0A 54251881Speter#define DW_EH_PE_sdata4 0x0B 55251881Speter#define DW_EH_PE_sdata8 0x0C 56251881Speter#define DW_EH_PE_signed 0x08 57251881Speter 58251881Speter#define DW_EH_PE_pcrel 0x10 59251881Speter#define DW_EH_PE_textrel 0x20 60251881Speter#define DW_EH_PE_datarel 0x30 61251881Speter#define DW_EH_PE_funcrel 0x40 62251881Speter#define DW_EH_PE_aligned 0x50 63251881Speter 64251881Speter#define DW_EH_PE_indirect 0x80 65251881Speter 66251881Speter 67251881Speter#ifndef NO_SIZE_OF_ENCODED_VALUE 68251881Speter 69251881Speter/* Given an encoding, return the number of bytes the format occupies. 70251881Speter This is only defined for fixed-size encodings, and so does not 71251881Speter include leb128. */ 72251881Speter 73251881Speterstatic unsigned int 74251881Spetersize_of_encoded_value (unsigned char encoding) 75251881Speter{ 76251881Speter if (encoding == DW_EH_PE_omit) 77251881Speter return 0; 78251881Speter 79251881Speter switch (encoding & 0x07) 80251881Speter { 81251881Speter case DW_EH_PE_absptr: 82251881Speter return sizeof (void *); 83251881Speter case DW_EH_PE_udata2: 84251881Speter return 2; 85251881Speter case DW_EH_PE_udata4: 86251881Speter return 4; 87251881Speter case DW_EH_PE_udata8: 88251881Speter return 8; 89251881Speter } 90251881Speter __gxx_abort (); 91251881Speter} 92251881Speter 93251881Speter#endif 94251881Speter 95251881Speter#ifndef NO_BASE_OF_ENCODED_VALUE 96251881Speter 97251881Speter/* Given an encoding and an _Unwind_Context, return the base to which 98251881Speter the encoding is relative. This base may then be passed to 99251881Speter read_encoded_value_with_base for use when the _Unwind_Context is 100251881Speter not available. */ 101251881Speter 102251881Speterstatic _Unwind_Ptr 103251881Speterbase_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context) 104251881Speter{ 105251881Speter if (encoding == DW_EH_PE_omit) 106251881Speter return 0; 107251881Speter 108251881Speter switch (encoding & 0x70) 109251881Speter { 110251881Speter case DW_EH_PE_absptr: 111251881Speter case DW_EH_PE_pcrel: 112251881Speter case DW_EH_PE_aligned: 113251881Speter return 0; 114251881Speter 115251881Speter case DW_EH_PE_textrel: 116251881Speter return _Unwind_GetTextRelBase (context); 117251881Speter case DW_EH_PE_datarel: 118251881Speter return _Unwind_GetDataRelBase (context); 119251881Speter case DW_EH_PE_funcrel: 120251881Speter return _Unwind_GetRegionStart (context); 121251881Speter } 122251881Speter __gxx_abort (); 123251881Speter} 124251881Speter 125251881Speter#endif 126251881Speter 127251881Speter/* Read an unsigned leb128 value from P, store the value in VAL, return 128251881Speter P incremented past the value. We assume that a word is large enough to 129251881Speter hold any value so encoded; if it is smaller than a pointer on some target, 130251881Speter pointers should not be leb128 encoded on that target. */ 131251881Speter 132251881Speterstatic const unsigned char * 133251881Speterread_uleb128 (const unsigned char *p, _Unwind_Word *val) 134251881Speter{ 135251881Speter unsigned int shift = 0; 136251881Speter unsigned char byte; 137251881Speter _Unwind_Word result; 138251881Speter 139251881Speter result = 0; 140251881Speter do 141251881Speter { 142251881Speter byte = *p++; 143251881Speter result |= ((_Unwind_Word)byte & 0x7f) << shift; 144251881Speter shift += 7; 145251881Speter } 146251881Speter while (byte & 0x80); 147251881Speter 148251881Speter *val = result; 149251881Speter return p; 150251881Speter} 151251881Speter 152251881Speter/* Similar, but read a signed leb128 value. */ 153251881Speter 154251881Speterstatic const unsigned char * 155251881Speterread_sleb128 (const unsigned char *p, _Unwind_Sword *val) 156251881Speter{ 157251881Speter unsigned int shift = 0; 158251881Speter unsigned char byte; 159251881Speter _Unwind_Word result; 160251881Speter 161251881Speter result = 0; 162251881Speter do 163251881Speter { 164251881Speter byte = *p++; 165251881Speter result |= ((_Unwind_Word)byte & 0x7f) << shift; 166251881Speter shift += 7; 167251881Speter } 168251881Speter while (byte & 0x80); 169251881Speter 170251881Speter /* Sign-extend a negative value. */ 171251881Speter if (shift < 8 * sizeof(result) && (byte & 0x40) != 0) 172251881Speter result |= -(((_Unwind_Word)1L) << shift); 173251881Speter 174251881Speter *val = (_Unwind_Sword) result; 175251881Speter return p; 176251881Speter} 177251881Speter 178251881Speter/* Load an encoded value from memory at P. The value is returned in VAL; 179251881Speter The function returns P incremented past the value. BASE is as given 180251881Speter by base_of_encoded_value for this encoding in the appropriate context. */ 181251881Speter 182251881Speterstatic const unsigned char * 183251881Speterread_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base, 184251881Speter const unsigned char *p, _Unwind_Ptr *val) 185251881Speter{ 186251881Speter union unaligned 187251881Speter { 188251881Speter void *ptr; 189251881Speter unsigned u2 __attribute__ ((mode (HI))); 190251881Speter unsigned u4 __attribute__ ((mode (SI))); 191251881Speter unsigned u8 __attribute__ ((mode (DI))); 192251881Speter signed s2 __attribute__ ((mode (HI))); 193251881Speter signed s4 __attribute__ ((mode (SI))); 194251881Speter signed s8 __attribute__ ((mode (DI))); 195251881Speter } __attribute__((__packed__)); 196251881Speter 197251881Speter const union unaligned *u = (const union unaligned *) p; 198251881Speter _Unwind_Internal_Ptr result; 199251881Speter 200251881Speter if (encoding == DW_EH_PE_aligned) 201251881Speter { 202251881Speter _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p; 203251881Speter a = (a + sizeof (void *) - 1) & - sizeof(void *); 204251881Speter result = *(_Unwind_Internal_Ptr *) a; 205251881Speter p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *)); 206251881Speter } 207251881Speter else 208251881Speter { 209251881Speter switch (encoding & 0x0f) 210251881Speter { 211251881Speter case DW_EH_PE_absptr: 212251881Speter result = (_Unwind_Internal_Ptr) u->ptr; 213251881Speter p += sizeof (void *); 214251881Speter break; 215251881Speter 216251881Speter case DW_EH_PE_uleb128: 217251881Speter { 218251881Speter _Unwind_Word tmp; 219251881Speter p = read_uleb128 (p, &tmp); 220251881Speter result = (_Unwind_Internal_Ptr) tmp; 221251881Speter } 222251881Speter break; 223251881Speter 224251881Speter case DW_EH_PE_sleb128: 225251881Speter { 226251881Speter _Unwind_Sword tmp; 227251881Speter p = read_sleb128 (p, &tmp); 228251881Speter result = (_Unwind_Internal_Ptr) tmp; 229251881Speter } 230251881Speter break; 231251881Speter 232251881Speter case DW_EH_PE_udata2: 233251881Speter result = u->u2; 234251881Speter p += 2; 235251881Speter break; 236251881Speter case DW_EH_PE_udata4: 237251881Speter result = u->u4; 238251881Speter p += 4; 239251881Speter break; 240251881Speter case DW_EH_PE_udata8: 241251881Speter result = u->u8; 242251881Speter p += 8; 243251881Speter break; 244251881Speter 245251881Speter case DW_EH_PE_sdata2: 246251881Speter result = u->s2; 247251881Speter p += 2; 248251881Speter break; 249251881Speter case DW_EH_PE_sdata4: 250251881Speter result = u->s4; 251251881Speter p += 4; 252251881Speter break; 253251881Speter case DW_EH_PE_sdata8: 254251881Speter result = u->s8; 255251881Speter p += 8; 256251881Speter break; 257251881Speter 258251881Speter default: 259251881Speter __gxx_abort (); 260251881Speter } 261251881Speter 262251881Speter if (result != 0) 263251881Speter { 264251881Speter result += ((encoding & 0x70) == DW_EH_PE_pcrel 265251881Speter ? (_Unwind_Internal_Ptr) u : base); 266251881Speter if (encoding & DW_EH_PE_indirect) 267251881Speter result = *(_Unwind_Internal_Ptr *) result; 268251881Speter } 269251881Speter } 270251881Speter 271251881Speter *val = result; 272251881Speter return p; 273251881Speter} 274251881Speter 275251881Speter#ifndef NO_BASE_OF_ENCODED_VALUE 276251881Speter 277251881Speter/* Like read_encoded_value_with_base, but get the base from the context 278251881Speter rather than providing it directly. */ 279251881Speter 280251881Speterstatic inline const unsigned char * 281251881Speterread_encoded_value (struct _Unwind_Context *context, unsigned char encoding, 282251881Speter const unsigned char *p, _Unwind_Ptr *val) 283251881Speter{ 284251881Speter return read_encoded_value_with_base (encoding, 285251881Speter base_of_encoded_value (encoding, context), 286251881Speter p, val); 287251881Speter} 288251881Speter 289251881Speter#endif 290251881Speter 291251881Speter#endif /* unwind-pe.h */ 292251881Speter