1 /* GDC -- D front-end for GCC
2    Copyright (C) 2004 David Friedman
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8  
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13  
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18 /* GNU/GCC unwind interface declarations for D.  This must match unwind-pe.h */
19 
20 module rt.compiler.gdc.gcc.unwind_pe;
21 
22 private import rt.compiler.gdc.gcc.unwind;
23 private import tango.stdc.stdlib : abort;
24 
25 /* @@@ Really this should be out of line, but this also causes link
26    compatibility problems with the base ABI.  This is slightly better
27    than duplicating code, however.  */
28 
29 /* Pointer encodings, from dwarf2.h.  */
30 enum {
31     DW_EH_PE_absptr = 0x00,
32     DW_EH_PE_omit = 0xff,
33 
34     DW_EH_PE_uleb128 = 0x01,
35     DW_EH_PE_udata2 = 0x02,
36     DW_EH_PE_udata4 = 0x03,
37     DW_EH_PE_udata8 = 0x04,
38     DW_EH_PE_sleb128 = 0x09,
39     DW_EH_PE_sdata2 = 0x0A,
40     DW_EH_PE_sdata4 = 0x0B,
41     DW_EH_PE_sdata8 = 0x0C,
42     DW_EH_PE_signed = 0x08,
43 
44     DW_EH_PE_pcrel = 0x10,
45     DW_EH_PE_textrel = 0x20,
46     DW_EH_PE_datarel = 0x30,
47     DW_EH_PE_funcrel = 0x40,
48     DW_EH_PE_aligned = 0x50,
49 
50     DW_EH_PE_indirect = 0x80
51 }
52 
53 version (NO_SIZE_OF_ENCODED_VALUE) {
54 } else {
55     /* Given an encoding, return the number of bytes the format occupies.
56        This is only defined for fixed-size encodings, and so does not
57        include leb128.  */
58 
59     uint
60     size_of_encoded_value (ubyte encoding)
61     {
62       if (encoding == DW_EH_PE_omit)
63         return 0;
64 
65       switch (encoding & 0x07)
66         {
67         case DW_EH_PE_absptr:
68           return (void *).sizeof;
69         case DW_EH_PE_udata2:
70           return 2;
71         case DW_EH_PE_udata4:
72           return 4;
73         case DW_EH_PE_udata8:
74           return 8;
75         }
76       abort ();
77     }
78 }
79 
80 version (NO_BASE_OF_ENCODED_VALUE) {
81 } else {
82     /* Given an encoding and an _Unwind_Context, return the base to which
83        the encoding is relative.  This base may then be passed to
84        read_encoded_value_with_base for use when the _Unwind_Context is
85        not available.  */
86 
87     _Unwind_Ptr
88     base_of_encoded_value (ubyte encoding, _Unwind_Context *context)
89     {
90       if (encoding == DW_EH_PE_omit)
91         return cast(_Unwind_Ptr) 0;
92 
93       switch (encoding & 0x70)
94         {
95         case DW_EH_PE_absptr:
96         case DW_EH_PE_pcrel:
97         case DW_EH_PE_aligned:
98           return cast(_Unwind_Ptr) 0;
99 
100         case DW_EH_PE_textrel:
101           return _Unwind_GetTextRelBase (context);
102         case DW_EH_PE_datarel:
103           return _Unwind_GetDataRelBase (context);
104         case DW_EH_PE_funcrel:
105           return _Unwind_GetRegionStart (context);
106         }
107       abort ();
108     }
109 }
110 
111 /* Read an unsigned leb128 value from P, store the value in VAL, return
112    P incremented past the value.  We assume that a word is large enough to
113    hold any value so encoded; if it is smaller than a pointer on some target,
114    pointers should not be leb128 encoded on that target.  */
115 
116 ubyte *
117 read_uleb128 (ubyte *p, _Unwind_Word *val)
118 {
119   uint shift = 0;
120   ubyte a_byte;
121   _Unwind_Word result;
122 
123   result = cast(_Unwind_Word) 0;
124   do
125     {
126       a_byte = *p++;
127       result |= (cast(_Unwind_Word)a_byte & 0x7f) << shift;
128       shift += 7;
129     }
130   while (a_byte & 0x80);
131 
132   *val = result;
133   return p;
134 }
135 
136 
137 /* Similar, but read a signed leb128 value.  */
138 
139 ubyte *
140 read_sleb128 (ubyte *p, _Unwind_Sword *val)
141 {
142   uint shift = 0;
143   ubyte a_byte;
144   _Unwind_Word result;
145 
146   result = cast(_Unwind_Word) 0;
147   do
148     {
149       a_byte = *p++;
150       result |= (cast(_Unwind_Word)a_byte & 0x7f) << shift;
151       shift += 7;
152     }
153   while (a_byte & 0x80);
154 
155   /* Sign-extend a negative value.  */
156   if (shift < 8 * result.sizeof && (a_byte & 0x40) != 0)
157     result |= -((cast(_Unwind_Word)1L) << shift);
158 
159   *val = cast(_Unwind_Sword) result;
160   return p;
161 }
162 
163 /* Load an encoded value from memory at P.  The value is returned in VAL;
164    The function returns P incremented past the value.  BASE is as given
165    by base_of_encoded_value for this encoding in the appropriate context.  */
166 
167 ubyte *
168 read_encoded_value_with_base (ubyte encoding, _Unwind_Ptr base,
169                               ubyte *p, _Unwind_Ptr *val)
170 {
171     // D Notes: Todo -- packed!
172   union unaligned
173     {
174       align(1) void *ptr;
175       align(1) ushort u2 ;
176       align(1) uint u4 ;
177       align(1) ulong u8 ;
178       align(1) short s2 ;
179       align(1) int s4 ;
180       align(1) long s8 ;
181     }
182 
183   unaligned *u = cast(unaligned *) p;
184   _Unwind_Internal_Ptr result;
185 
186   if (encoding == DW_EH_PE_aligned)
187     {
188       _Unwind_Internal_Ptr a = cast(_Unwind_Internal_Ptr) p;
189       a = cast(_Unwind_Internal_Ptr)( (a + (void *).sizeof - 1) & - (void *).sizeof );
190       result = * cast(_Unwind_Internal_Ptr *) a;
191       p = cast(ubyte *) cast(_Unwind_Internal_Ptr) (a + (void *).sizeof);
192     }
193   else
194     {
195       switch (encoding & 0x0f)
196         {
197         case DW_EH_PE_absptr:
198           result = cast(_Unwind_Internal_Ptr) u.ptr;
199           p += (void *).sizeof;
200           break;
201 
202         case DW_EH_PE_uleb128:
203           {
204             _Unwind_Word tmp;
205             p = read_uleb128 (p, &tmp);
206             result = cast(_Unwind_Internal_Ptr) tmp;
207           }
208           break;
209 
210         case DW_EH_PE_sleb128:
211           {
212             _Unwind_Sword tmp;
213             p = read_sleb128 (p, &tmp);
214             result = cast(_Unwind_Internal_Ptr) tmp;
215           }
216           break;
217 
218         case DW_EH_PE_udata2:
219           result = cast(_Unwind_Internal_Ptr) u.u2;
220           p += 2;
221           break;
222         case DW_EH_PE_udata4:
223           result = cast(_Unwind_Internal_Ptr) u.u4;
224           p += 4;
225           break;
226         case DW_EH_PE_udata8:
227           result = cast(_Unwind_Internal_Ptr) u.u8;
228           p += 8;
229           break;
230 
231         case DW_EH_PE_sdata2:
232           result = cast(_Unwind_Internal_Ptr) u.s2;
233           p += 2;
234           break;
235         case DW_EH_PE_sdata4:
236           result = cast(_Unwind_Internal_Ptr) u.s4;
237           p += 4;
238           break;
239         case DW_EH_PE_sdata8:
240           result = cast(_Unwind_Internal_Ptr) u.s8;
241           p += 8;
242           break;
243 
244         default:
245           abort ();
246         }
247 
248       if (result != 0)
249         {
250           result += ((encoding & 0x70) == DW_EH_PE_pcrel
251                      ? cast(_Unwind_Internal_Ptr) u : base);
252           if (encoding & DW_EH_PE_indirect)
253             result = *cast(_Unwind_Internal_Ptr *) result;
254         }
255     }
256 
257   *val = result;
258   return p;
259 }
260 
261 version (NO_BASE_OF_ENCODED_VALUE) {
262 } else {
263     /* Like read_encoded_value_with_base, but get the base from the context
264        rather than providing it directly.  */
265 
266     ubyte *
267     read_encoded_value (_Unwind_Context *context, ubyte encoding,
268                         ubyte *p, _Unwind_Ptr *val)
269     {
270       return read_encoded_value_with_base (encoding,
271                     base_of_encoded_value (encoding, context),
272                     p, val);
273     }
274 }
275