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