1 module unwind; 2 3 pragma(LDC_no_moduleinfo); 4 5 6 extern (C): 7 @nogc: 8 9 // Read an unsigned leb128 value from P, *P is incremented past the value. 10 // We assume that a word is large enough to hold any value so encoded; 11 // if it is smaller than a pointer on some target, pointers should not be 12 // leb128 encoded on that target. 13 _uleb128_t read_uleb128(const(ubyte)** p) 14 { 15 auto q = *p; 16 _uleb128_t result = 0; 17 uint shift = 0; 18 19 while (1) 20 { 21 ubyte b = *q++; 22 result |= cast(_uleb128_t)(b & 0x7F) << shift; 23 if ((b & 0x80) == 0) 24 break; 25 shift += 7; 26 } 27 28 *p = q; 29 return result; 30 } 31 32 // Similar, but read a signed leb128 value. 33 _sleb128_t read_sleb128(const(ubyte)** p) 34 { 35 auto q = *p; 36 _sleb128_t result = 0; 37 uint shift = 0; 38 ubyte b = void; 39 40 while (1) 41 { 42 b = *q++; 43 result |= cast(_sleb128_t)(b & 0x7F) << shift; 44 shift += 7; 45 if ((b & 0x80) == 0) 46 break; 47 } 48 49 // Sign-extend a negative value. 50 if (shift < result.sizeof * 8 && (b & 0x40)) 51 result |= -(cast(_sleb128_t)1 << shift); 52 53 *p = q; 54 return result; 55 } 56 57 // Load an encoded value from memory at P. The value is returned in VAL; 58 // The function returns P incremented past the value. BASE is as given 59 // by base_of_encoded_value for this encoding in the appropriate context. 60 _Unwind_Ptr read_encoded_value_with_base(ubyte encoding, _Unwind_Ptr base, 61 const(ubyte)** p) 62 { 63 auto q = *p; 64 _Unwind_Internal_Ptr result; 65 66 if (encoding == DW_EH_PE_aligned) 67 { 68 _Unwind_Internal_Ptr a = cast(_Unwind_Internal_Ptr)q; 69 a = cast(_Unwind_Internal_Ptr)((a + (void*).sizeof - 1) & - (void*).sizeof); 70 result = *cast(_Unwind_Internal_Ptr*)a; 71 q = cast(ubyte*) cast(_Unwind_Internal_Ptr)(a + (void*).sizeof); 72 } 73 else 74 { 75 switch (encoding & 0x0f) 76 { 77 case DW_EH_PE_uleb128: 78 result = cast(_Unwind_Internal_Ptr)read_uleb128(&q); 79 break; 80 81 case DW_EH_PE_sleb128: 82 result = cast(_Unwind_Internal_Ptr)read_sleb128(&q); 83 break; 84 85 case DW_EH_PE_udata2: 86 result = cast(_Unwind_Internal_Ptr) *cast(ushort*)q; 87 q += 2; 88 break; 89 case DW_EH_PE_udata4: 90 result = cast(_Unwind_Internal_Ptr) *cast(uint*)q; 91 q += 4; 92 break; 93 case DW_EH_PE_udata8: 94 result = cast(_Unwind_Internal_Ptr) *cast(ulong*)q; 95 q += 8; 96 break; 97 98 case DW_EH_PE_sdata2: 99 result = cast(_Unwind_Internal_Ptr) *cast(short*)q; 100 q += 2; 101 break; 102 case DW_EH_PE_sdata4: 103 result = cast(_Unwind_Internal_Ptr) *cast(int*)q; 104 q += 4; 105 break; 106 case DW_EH_PE_sdata8: 107 result = cast(_Unwind_Internal_Ptr) *cast(long*)q; 108 q += 8; 109 break; 110 111 case DW_EH_PE_absptr: 112 if (size_t.sizeof == 8) 113 goto case DW_EH_PE_udata8; 114 else 115 goto case DW_EH_PE_udata4; 116 117 default: break; 118 //__builtin_abort(); 119 } 120 121 if (result != 0) 122 { 123 result += ((encoding & 0x70) == DW_EH_PE_pcrel 124 ? cast(_Unwind_Internal_Ptr)*p : base); 125 if (encoding & DW_EH_PE_indirect) 126 result = *cast(_Unwind_Internal_Ptr*)result; 127 } 128 } 129 130 *p = q; 131 return result; 132 } 133 134 // Like read_encoded_value_with_base, but get the base from the context 135 // rather than providing it directly. 136 _Unwind_Ptr read_encoded_value(_Unwind_Context* context, ubyte encoding, 137 const(ubyte)** p) 138 { 139 auto base = base_of_encoded_value(encoding, context); 140 return read_encoded_value_with_base(encoding, base, p); 141 } 142 143 // Given an encoding and an _Unwind_Context, return the base to which 144 // the encoding is relative. This base may then be passed to 145 // read_encoded_value_with_base for use when the _Unwind_Context is 146 // not available. 147 _Unwind_Ptr base_of_encoded_value(ubyte encoding, _Unwind_Context* context) 148 { 149 if (encoding == DW_EH_PE_omit) 150 return cast(_Unwind_Ptr) 0; 151 152 switch (encoding & 0x70) 153 { 154 case DW_EH_PE_absptr: 155 case DW_EH_PE_pcrel: 156 case DW_EH_PE_aligned: 157 return cast(_Unwind_Ptr) 0; 158 159 case DW_EH_PE_textrel: 160 return _Unwind_GetTextRelBase(context); 161 case DW_EH_PE_datarel: 162 return _Unwind_GetDataRelBase(context); 163 case DW_EH_PE_funcrel: 164 return _Unwind_GetRegionStart(context); 165 default: break; 166 } 167 assert(0); 168 } 169 170 // Given an encoding, return the number of bytes the format occupies. 171 // This is only defined for fixed-size encodings, and so does not 172 // include leb128. 173 uint size_of_encoded_value(ubyte encoding) 174 { 175 if (encoding == DW_EH_PE_omit) 176 return 0; 177 178 switch (encoding & 0x07) 179 { 180 case DW_EH_PE_absptr: 181 return (void*).sizeof; 182 case DW_EH_PE_udata2: 183 return 2; 184 case DW_EH_PE_udata4: 185 return 4; 186 case DW_EH_PE_udata8: 187 return 8; 188 default: break; 189 } 190 assert(0); 191 } 192 193 enum { 194 DW_EH_PE_absptr = 0x00, 195 DW_EH_PE_omit = 0xff, 196 197 DW_EH_PE_uleb128 = 0x01, 198 DW_EH_PE_udata2 = 0x02, 199 DW_EH_PE_udata4 = 0x03, 200 DW_EH_PE_udata8 = 0x04, 201 DW_EH_PE_sleb128 = 0x09, 202 DW_EH_PE_sdata2 = 0x0A, 203 DW_EH_PE_sdata4 = 0x0B, 204 DW_EH_PE_sdata8 = 0x0C, 205 DW_EH_PE_signed = 0x08, 206 207 DW_EH_PE_pcrel = 0x10, 208 DW_EH_PE_textrel = 0x20, 209 DW_EH_PE_datarel = 0x30, 210 DW_EH_PE_funcrel = 0x40, 211 DW_EH_PE_aligned = 0x50, 212 213 DW_EH_PE_indirect = 0x80 214 } 215 216 enum int UNWIND_STACK_REG = 13; 217 // Use IP as a scratch register within the personality routine. 218 enum int UNWIND_POINTER_REG = 12; 219 220 version (linux) 221 enum _TTYPE_ENCODING = (DW_EH_PE_pcrel | DW_EH_PE_indirect); 222 else version (NetBSD) 223 enum _TTYPE_ENCODING = (DW_EH_PE_pcrel | DW_EH_PE_indirect); 224 else version (FreeBSD) 225 enum _TTYPE_ENCODING = (DW_EH_PE_pcrel | DW_EH_PE_indirect); 226 else version (Symbian) 227 enum _TTYPE_ENCODING = (DW_EH_PE_absptr); 228 else version (uClinux) 229 enum _TTYPE_ENCODING = (DW_EH_PE_absptr); 230 else 231 enum _TTYPE_ENCODING = (DW_EH_PE_pcrel); 232 233 // Return the address of the instruction, not the actual IP value. 234 _Unwind_Word _Unwind_GetIP(_Unwind_Context* context) 235 { 236 return _Unwind_GetGR(context, 15) & ~ cast(_Unwind_Word) 1; 237 } 238 239 void _Unwind_SetIP(_Unwind_Context* context, _Unwind_Word val) 240 { 241 return _Unwind_SetGR(context, 15, val | (_Unwind_GetGR(context, 15) & 1)); 242 } 243 244 _Unwind_Word _Unwind_GetIPInfo(_Unwind_Context* context, int* ip_before_insn) 245 { 246 *ip_before_insn = 0; 247 return _Unwind_GetIP(context); 248 } 249 250 extern (C): 251 252 // Placed outside @nogc in order to not constrain what the callback does. 253 // ??? Does this really need to be extern(C) alias? 254 extern(C) alias _Unwind_Exception_Cleanup_Fn 255 = void function(_Unwind_Reason_Code, _Unwind_Exception*); 256 257 extern(C) alias personality_routine 258 = _Unwind_Reason_Code function(_Unwind_State, 259 _Unwind_Control_Block*, 260 _Unwind_Context*); 261 262 extern(C) alias _Unwind_Stop_Fn 263 =_Unwind_Reason_Code function(int, _Unwind_Action, 264 _Unwind_Exception_Class, 265 _Unwind_Control_Block*, 266 _Unwind_Context*, void*); 267 268 extern(C) alias _Unwind_Trace_Fn 269 = _Unwind_Reason_Code function(_Unwind_Context*, void*); 270 271 @nogc: 272 273 alias _Unwind_Word = uint; 274 alias _Unwind_Sword = int; 275 alias _Unwind_Ptr = uint; 276 alias _Unwind_Internal_Ptr = uint; 277 alias _uw = _Unwind_Word; 278 alias _uw64 = ulong; 279 alias _uw16 = ushort; 280 alias _uw8 = ubyte; 281 282 alias _Unwind_Reason_Code = uint; 283 enum : _Unwind_Reason_Code 284 { 285 _URC_OK = 0, // operation completed successfully 286 _URC_FOREIGN_EXCEPTION_CAUGHT = 1, 287 _URC_END_OF_STACK = 5, 288 _URC_HANDLER_FOUND = 6, 289 _URC_INSTALL_CONTEXT = 7, 290 _URC_CONTINUE_UNWIND = 8, 291 _URC_FAILURE = 9 // unspecified failure of some kind 292 } 293 294 alias _Unwind_State = int; 295 enum : _Unwind_State 296 { 297 _US_VIRTUAL_UNWIND_FRAME = 0, 298 _US_UNWIND_FRAME_STARTING = 1, 299 _US_UNWIND_FRAME_RESUME = 2, 300 _US_ACTION_MASK = 3, 301 _US_FORCE_UNWIND = 8, 302 _US_END_OF_STACK = 16 303 } 304 305 // Provided only for for compatibility with existing code. 306 alias _Unwind_Action = int; 307 enum : _Unwind_Action 308 { 309 _UA_SEARCH_PHASE = 1, 310 _UA_CLEANUP_PHASE = 2, 311 _UA_HANDLER_FRAME = 4, 312 _UA_FORCE_UNWIND = 8, 313 _UA_END_OF_STACK = 16, 314 _URC_NO_REASON = _URC_OK 315 } 316 317 struct _Unwind_Context; 318 alias _Unwind_EHT_Header = _uw; 319 320 struct _Unwind_Control_Block 321 { 322 _Unwind_Exception_Class exception_class = '\0'; 323 _Unwind_Exception_Cleanup_Fn exception_cleanup; 324 // Unwinder cache, private fields for the unwinder's use 325 struct _unwinder_cache 326 { 327 _uw reserved1; // Forced unwind stop fn, 0 if not forced 328 _uw reserved2; // Personality routine address 329 _uw reserved3; // Saved callsite address 330 _uw reserved4; // Forced unwind stop arg 331 _uw reserved5; 332 } 333 _unwinder_cache unwinder_cache; 334 // Propagation barrier cache (valid after phase 1): 335 struct _barrier_cache 336 { 337 _uw sp; 338 _uw[5] bitpattern; 339 } 340 _barrier_cache barrier_cache; 341 // Cleanup cache (preserved over cleanup): 342 struct _cleanup_cache 343 { 344 _uw[4] bitpattern; 345 } 346 _cleanup_cache cleanup_cache; 347 // Pr cache (for pr's benefit): 348 struct _pr_cache 349 { 350 _uw fnstart; // function start address */ 351 _Unwind_EHT_Header* ehtp; // pointer to EHT entry header word 352 _uw additional; // additional data 353 _uw reserved1; 354 } 355 _pr_cache pr_cache; 356 long[0] _force_alignment; // Force alignment to 8-byte boundary 357 } 358 359 // Virtual Register Set 360 alias _Unwind_VRS_RegClass = int; 361 enum : _Unwind_VRS_RegClass 362 { 363 _UVRSC_CORE = 0, // integer register 364 _UVRSC_VFP = 1, // vfp 365 _UVRSC_FPA = 2, // fpa 366 _UVRSC_WMMXD = 3, // Intel WMMX data register 367 _UVRSC_WMMXC = 4 // Intel WMMX control register 368 } 369 370 alias _Unwind_VRS_DataRepresentation = int; 371 enum : _Unwind_VRS_DataRepresentation 372 { 373 _UVRSD_UINT32 = 0, 374 _UVRSD_VFPX = 1, 375 _UVRSD_FPAX = 2, 376 _UVRSD_UINT64 = 3, 377 _UVRSD_FLOAT = 4, 378 _UVRSD_DOUBLE = 5 379 } 380 381 alias _Unwind_VRS_Result = int; 382 enum : _Unwind_VRS_Result 383 { 384 _UVRSR_OK = 0, 385 _UVRSR_NOT_IMPLEMENTED = 1, 386 _UVRSR_FAILED = 2 387 } 388 389 // Frame unwinding state. 390 struct __gnu_unwind_state 391 { 392 _uw data; // The current word (bytes packed msb first). 393 _uw* next; // Pointer to the next word of data. 394 _uw8 bytes_left; // The number of bytes left in this word. 395 _uw8 words_left; // The number of words pointed to by ptr. 396 } 397 398 _Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context*, _Unwind_VRS_RegClass, 399 _uw, _Unwind_VRS_DataRepresentation, 400 void*); 401 402 _Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context*, _Unwind_VRS_RegClass, 403 _uw, _Unwind_VRS_DataRepresentation, 404 void*); 405 406 _Unwind_VRS_Result _Unwind_VRS_Pop(_Unwind_Context*, _Unwind_VRS_RegClass, 407 _uw, _Unwind_VRS_DataRepresentation); 408 409 410 // Support functions for the PR. 411 alias _Unwind_Exception = _Unwind_Control_Block; 412 alias _Unwind_Exception_Class = char[8]; 413 414 void* _Unwind_GetLanguageSpecificData(_Unwind_Context*); 415 _Unwind_Ptr _Unwind_GetRegionStart(_Unwind_Context*); 416 417 _Unwind_Ptr _Unwind_GetDataRelBase(_Unwind_Context*); 418 // This should never be used. 419 _Unwind_Ptr _Unwind_GetTextRelBase(_Unwind_Context*); 420 421 // Interface functions: 422 _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Control_Block*); 423 void _Unwind_Resume(_Unwind_Control_Block*); 424 _Unwind_Reason_Code _Unwind_Resume_or_Rethrow(_Unwind_Control_Block*); 425 426 _Unwind_Reason_Code _Unwind_ForcedUnwind(_Unwind_Control_Block*, 427 _Unwind_Stop_Fn, void*); 428 429 // @@@ Use unwind data to perform a stack backtrace. The trace callback 430 // is called for every stack frame in the call chain, but no cleanup 431 // actions are performed. 432 _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*); 433 434 _Unwind_Word _Unwind_GetCFA(_Unwind_Context*); 435 void _Unwind_Complete(_Unwind_Control_Block*); 436 void _Unwind_DeleteException(_Unwind_Exception*); 437 438 _Unwind_Reason_Code __gnu_unwind_frame(_Unwind_Control_Block*, 439 _Unwind_Context*); 440 _Unwind_Reason_Code __gnu_unwind_execute(_Unwind_Context*, 441 __gnu_unwind_state*); 442 443 _Unwind_Word _Unwind_GetGR(_Unwind_Context* context, int regno) 444 { 445 _uw val; 446 _Unwind_VRS_Get(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); 447 return val; 448 } 449 450 void _Unwind_SetGR(_Unwind_Context* context, int regno, _Unwind_Word val) 451 { 452 _Unwind_VRS_Set(context, _UVRSC_CORE, regno, _UVRSD_UINT32, &val); 453 } 454 455 // leb128 type numbers have a potentially unlimited size. 456 // The target of the following definitions of _sleb128_t and _uleb128_t 457 // is to have efficient data types large enough to hold the leb128 type 458 // numbers used in the unwind code. 459 alias _sleb128_t = int; 460 alias _uleb128_t = uint;