1 /* GDC -- D front-end for GCC 2 Copyright (C) 2004 David Friedman 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software 16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 /* GNU/GCC unwind interface declarations for D. This must match unwind-pe.h */ 19 20 module rt.compiler.gdc.gcc.unwind_pe; 21 22 private import rt.compiler.gdc.gcc.unwind; 23 private import tango.stdc.stdlib : abort; 24 25 /* @@@ Really this should be out of line, but this also causes link 26 compatibility problems with the base ABI. This is slightly better 27 than duplicating code, however. */ 28 29 /* Pointer encodings, from dwarf2.h. */ 30 enum { 31 DW_EH_PE_absptr = 0x00, 32 DW_EH_PE_omit = 0xff, 33 34 DW_EH_PE_uleb128 = 0x01, 35 DW_EH_PE_udata2 = 0x02, 36 DW_EH_PE_udata4 = 0x03, 37 DW_EH_PE_udata8 = 0x04, 38 DW_EH_PE_sleb128 = 0x09, 39 DW_EH_PE_sdata2 = 0x0A, 40 DW_EH_PE_sdata4 = 0x0B, 41 DW_EH_PE_sdata8 = 0x0C, 42 DW_EH_PE_signed = 0x08, 43 44 DW_EH_PE_pcrel = 0x10, 45 DW_EH_PE_textrel = 0x20, 46 DW_EH_PE_datarel = 0x30, 47 DW_EH_PE_funcrel = 0x40, 48 DW_EH_PE_aligned = 0x50, 49 50 DW_EH_PE_indirect = 0x80 51 } 52 53 version (NO_SIZE_OF_ENCODED_VALUE) { 54 } else { 55 /* Given an encoding, return the number of bytes the format occupies. 56 This is only defined for fixed-size encodings, and so does not 57 include leb128. */ 58 59 uint 60 size_of_encoded_value (ubyte encoding) 61 { 62 if (encoding == DW_EH_PE_omit) 63 return 0; 64 65 switch (encoding & 0x07) 66 { 67 case DW_EH_PE_absptr: 68 return (void *).sizeof; 69 case DW_EH_PE_udata2: 70 return 2; 71 case DW_EH_PE_udata4: 72 return 4; 73 case DW_EH_PE_udata8: 74 return 8; 75 } 76 abort (); 77 } 78 } 79 80 version (NO_BASE_OF_ENCODED_VALUE) { 81 } else { 82 /* Given an encoding and an _Unwind_Context, return the base to which 83 the encoding is relative. This base may then be passed to 84 read_encoded_value_with_base for use when the _Unwind_Context is 85 not available. */ 86 87 _Unwind_Ptr 88 base_of_encoded_value (ubyte encoding, _Unwind_Context *context) 89 { 90 if (encoding == DW_EH_PE_omit) 91 return cast(_Unwind_Ptr) 0; 92 93 switch (encoding & 0x70) 94 { 95 case DW_EH_PE_absptr: 96 case DW_EH_PE_pcrel: 97 case DW_EH_PE_aligned: 98 return cast(_Unwind_Ptr) 0; 99 100 case DW_EH_PE_textrel: 101 return _Unwind_GetTextRelBase (context); 102 case DW_EH_PE_datarel: 103 return _Unwind_GetDataRelBase (context); 104 case DW_EH_PE_funcrel: 105 return _Unwind_GetRegionStart (context); 106 } 107 abort (); 108 } 109 } 110 111 /* Read an unsigned leb128 value from P, store the value in VAL, return 112 P incremented past the value. We assume that a word is large enough to 113 hold any value so encoded; if it is smaller than a pointer on some target, 114 pointers should not be leb128 encoded on that target. */ 115 116 ubyte * 117 read_uleb128 (ubyte *p, _Unwind_Word *val) 118 { 119 uint shift = 0; 120 ubyte a_byte; 121 _Unwind_Word result; 122 123 result = cast(_Unwind_Word) 0; 124 do 125 { 126 a_byte = *p++; 127 result |= (cast(_Unwind_Word)a_byte & 0x7f) << shift; 128 shift += 7; 129 } 130 while (a_byte & 0x80); 131 132 *val = result; 133 return p; 134 } 135 136 137 /* Similar, but read a signed leb128 value. */ 138 139 ubyte * 140 read_sleb128 (ubyte *p, _Unwind_Sword *val) 141 { 142 uint shift = 0; 143 ubyte a_byte; 144 _Unwind_Word result; 145 146 result = cast(_Unwind_Word) 0; 147 do 148 { 149 a_byte = *p++; 150 result |= (cast(_Unwind_Word)a_byte & 0x7f) << shift; 151 shift += 7; 152 } 153 while (a_byte & 0x80); 154 155 /* Sign-extend a negative value. */ 156 if (shift < 8 * result.sizeof && (a_byte & 0x40) != 0) 157 result |= -((cast(_Unwind_Word)1L) << shift); 158 159 *val = cast(_Unwind_Sword) result; 160 return p; 161 } 162 163 /* Load an encoded value from memory at P. The value is returned in VAL; 164 The function returns P incremented past the value. BASE is as given 165 by base_of_encoded_value for this encoding in the appropriate context. */ 166 167 ubyte * 168 read_encoded_value_with_base (ubyte encoding, _Unwind_Ptr base, 169 ubyte *p, _Unwind_Ptr *val) 170 { 171 // D Notes: Todo -- packed! 172 union unaligned 173 { 174 align(1) void *ptr; 175 align(1) ushort u2 ; 176 align(1) uint u4 ; 177 align(1) ulong u8 ; 178 align(1) short s2 ; 179 align(1) int s4 ; 180 align(1) long s8 ; 181 } 182 183 unaligned *u = cast(unaligned *) p; 184 _Unwind_Internal_Ptr result; 185 186 if (encoding == DW_EH_PE_aligned) 187 { 188 _Unwind_Internal_Ptr a = cast(_Unwind_Internal_Ptr) p; 189 a = cast(_Unwind_Internal_Ptr)( (a + (void *).sizeof - 1) & - (void *).sizeof ); 190 result = * cast(_Unwind_Internal_Ptr *) a; 191 p = cast(ubyte *) cast(_Unwind_Internal_Ptr) (a + (void *).sizeof); 192 } 193 else 194 { 195 switch (encoding & 0x0f) 196 { 197 case DW_EH_PE_absptr: 198 result = cast(_Unwind_Internal_Ptr) u.ptr; 199 p += (void *).sizeof; 200 break; 201 202 case DW_EH_PE_uleb128: 203 { 204 _Unwind_Word tmp; 205 p = read_uleb128 (p, &tmp); 206 result = cast(_Unwind_Internal_Ptr) tmp; 207 } 208 break; 209 210 case DW_EH_PE_sleb128: 211 { 212 _Unwind_Sword tmp; 213 p = read_sleb128 (p, &tmp); 214 result = cast(_Unwind_Internal_Ptr) tmp; 215 } 216 break; 217 218 case DW_EH_PE_udata2: 219 result = cast(_Unwind_Internal_Ptr) u.u2; 220 p += 2; 221 break; 222 case DW_EH_PE_udata4: 223 result = cast(_Unwind_Internal_Ptr) u.u4; 224 p += 4; 225 break; 226 case DW_EH_PE_udata8: 227 result = cast(_Unwind_Internal_Ptr) u.u8; 228 p += 8; 229 break; 230 231 case DW_EH_PE_sdata2: 232 result = cast(_Unwind_Internal_Ptr) u.s2; 233 p += 2; 234 break; 235 case DW_EH_PE_sdata4: 236 result = cast(_Unwind_Internal_Ptr) u.s4; 237 p += 4; 238 break; 239 case DW_EH_PE_sdata8: 240 result = cast(_Unwind_Internal_Ptr) u.s8; 241 p += 8; 242 break; 243 244 default: 245 abort (); 246 } 247 248 if (result != 0) 249 { 250 result += ((encoding & 0x70) == DW_EH_PE_pcrel 251 ? cast(_Unwind_Internal_Ptr) u : base); 252 if (encoding & DW_EH_PE_indirect) 253 result = *cast(_Unwind_Internal_Ptr *) result; 254 } 255 } 256 257 *val = result; 258 return p; 259 } 260 261 version (NO_BASE_OF_ENCODED_VALUE) { 262 } else { 263 /* Like read_encoded_value_with_base, but get the base from the context 264 rather than providing it directly. */ 265 266 ubyte * 267 read_encoded_value (_Unwind_Context *context, ubyte encoding, 268 ubyte *p, _Unwind_Ptr *val) 269 { 270 return read_encoded_value_with_base (encoding, 271 base_of_encoded_value (encoding, context), 272 p, val); 273 } 274 } 275