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