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;