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 }