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 }