]> git.ipfire.org Git - thirdparty/gcc.git/blame - libphobos/libdruntime/gcc/unwind/pe.d
Update copyright years.
[thirdparty/gcc.git] / libphobos / libdruntime / gcc / unwind / pe.d
CommitLineData
b4c522fa 1// Exception handling and frame unwind runtime interface routines.
83ffe9cd 2// Copyright (C) 2011-2023 Free Software Foundation, Inc.
b4c522fa
IB
3
4// GCC is free software; you can redistribute it and/or modify it under
5// the terms of the GNU General Public License as published by the Free
6// Software Foundation; either version 3, or (at your option) any later
7// version.
8
9// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
10// WARRANTY; without even the implied warranty of MERCHANTABILITY or
11// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12// for more details.
13
14// Under Section 7 of GPL version 3, you are granted additional
15// permissions described in the GCC Runtime Library Exception, version
16// 3.1, as published by the Free Software Foundation.
17
18// You should have received a copy of the GNU General Public License and
19// a copy of the GCC Runtime Library Exception along with this program;
20// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
21// <http://www.gnu.org/licenses/>.
22
23// extern(C) interface for the GNU/GCC pointer encoding library.
24// This corresponds to unwind-pe.h
25
26module gcc.unwind.pe;
27
28import gcc.unwind;
29import gcc.builtins;
30
31@nogc:
32
33// Pointer encodings, from dwarf2.h.
34enum
35{
36 DW_EH_PE_absptr = 0x00,
37 DW_EH_PE_omit = 0xff,
38
39 DW_EH_PE_uleb128 = 0x01,
40 DW_EH_PE_udata2 = 0x02,
41 DW_EH_PE_udata4 = 0x03,
42 DW_EH_PE_udata8 = 0x04,
43 DW_EH_PE_sleb128 = 0x09,
44 DW_EH_PE_sdata2 = 0x0A,
45 DW_EH_PE_sdata4 = 0x0B,
46 DW_EH_PE_sdata8 = 0x0C,
47 DW_EH_PE_signed = 0x08,
48
49 DW_EH_PE_pcrel = 0x10,
50 DW_EH_PE_textrel = 0x20,
51 DW_EH_PE_datarel = 0x30,
52 DW_EH_PE_funcrel = 0x40,
53 DW_EH_PE_aligned = 0x50,
54
55 DW_EH_PE_indirect = 0x80
56}
57
58// Given an encoding, return the number of bytes the format occupies.
59// This is only defined for fixed-size encodings, and so does not
60// include leb128.
61uint size_of_encoded_value(ubyte encoding)
62{
63 if (encoding == DW_EH_PE_omit)
64 return 0;
65
66 final switch (encoding & 0x07)
67 {
68 case DW_EH_PE_absptr:
69 return (void*).sizeof;
70 case DW_EH_PE_udata2:
71 return 2;
72 case DW_EH_PE_udata4:
73 return 4;
74 case DW_EH_PE_udata8:
75 return 8;
76 }
77 assert(0);
78}
79
80// Given an encoding and an _Unwind_Context, return the base to which
81// the encoding is relative. This base may then be passed to
82// read_encoded_value_with_base for use when the _Unwind_Context is
83// not available.
84_Unwind_Ptr base_of_encoded_value(ubyte encoding, _Unwind_Context* context)
85{
86 if (encoding == DW_EH_PE_omit)
87 return cast(_Unwind_Ptr) 0;
88
89 final switch (encoding & 0x70)
90 {
91 case DW_EH_PE_absptr:
92 case DW_EH_PE_pcrel:
93 case DW_EH_PE_aligned:
94 return cast(_Unwind_Ptr) 0;
95
96 case DW_EH_PE_textrel:
97 return _Unwind_GetTextRelBase(context);
98 case DW_EH_PE_datarel:
99 return _Unwind_GetDataRelBase(context);
100 case DW_EH_PE_funcrel:
101 return _Unwind_GetRegionStart(context);
102 }
103 assert(0);
104}
105
30b11d8d 106// Read an unsigned leb128 value from P, P is incremented past the value.
b4c522fa
IB
107// We assume that a word is large enough to hold any value so encoded;
108// if it is smaller than a pointer on some target, pointers should not be
109// leb128 encoded on that target.
30b11d8d 110_uleb128_t read_uleb128(ref const(ubyte)* p)
b4c522fa 111{
b4c522fa
IB
112 _uleb128_t result = 0;
113 uint shift = 0;
114
115 while (1)
116 {
30b11d8d 117 ubyte b = *p++;
b4c522fa
IB
118 result |= cast(_uleb128_t)(b & 0x7F) << shift;
119 if ((b & 0x80) == 0)
120 break;
121 shift += 7;
122 }
123
b4c522fa
IB
124 return result;
125}
126
127// Similar, but read a signed leb128 value.
30b11d8d 128_sleb128_t read_sleb128(ref const(ubyte)* p)
b4c522fa 129{
b4c522fa
IB
130 _sleb128_t result = 0;
131 uint shift = 0;
132 ubyte b = void;
133
134 while (1)
135 {
30b11d8d 136 b = *p++;
b4c522fa
IB
137 result |= cast(_sleb128_t)(b & 0x7F) << shift;
138 shift += 7;
139 if ((b & 0x80) == 0)
140 break;
141 }
142
143 // Sign-extend a negative value.
144 if (shift < result.sizeof * 8 && (b & 0x40))
145 result |= -(cast(_sleb128_t)1 << shift);
146
b4c522fa
IB
147 return result;
148}
149
30b11d8d
IB
150// Similar, but read an unaligned value of type T.
151pragma(inline, true)
152private T read_unaligned(T)(ref const(ubyte)* p)
153{
154 version (X86) enum hasUnalignedLoads = true;
155 else version (X86_64) enum hasUnalignedLoads = true;
156 else enum hasUnalignedLoads = false;
157
158 static if (hasUnalignedLoads)
159 {
160 T result = *cast(T*)p;
161 }
162 else
163 {
164 import core.stdc.string : memcpy;
165 T result = void;
166 memcpy(&result, p, T.sizeof);
167 }
168 p += T.sizeof;
169 return result;
170}
171
172// Load an encoded value from memory at P. The function returns the
173// encoded value. P is incremented past the value. BASE is as given
b4c522fa
IB
174// by base_of_encoded_value for this encoding in the appropriate context.
175_Unwind_Ptr read_encoded_value_with_base(ubyte encoding, _Unwind_Ptr base,
30b11d8d 176 ref const(ubyte)* p)
b4c522fa 177{
30b11d8d 178 auto psave = p;
b4c522fa
IB
179 _Unwind_Internal_Ptr result;
180
181 if (encoding == DW_EH_PE_aligned)
182 {
30b11d8d 183 _Unwind_Internal_Ptr a = cast(_Unwind_Internal_Ptr)p;
b4c522fa
IB
184 a = cast(_Unwind_Internal_Ptr)((a + (void*).sizeof - 1) & - (void*).sizeof);
185 result = *cast(_Unwind_Internal_Ptr*)a;
30b11d8d 186 p = cast(ubyte*) cast(_Unwind_Internal_Ptr)(a + (void*).sizeof);
b4c522fa
IB
187 }
188 else
189 {
190 switch (encoding & 0x0f)
191 {
192 case DW_EH_PE_uleb128:
30b11d8d 193 result = cast(_Unwind_Internal_Ptr)read_uleb128(p);
b4c522fa
IB
194 break;
195
196 case DW_EH_PE_sleb128:
30b11d8d 197 result = cast(_Unwind_Internal_Ptr)read_sleb128(p);
b4c522fa
IB
198 break;
199
200 case DW_EH_PE_udata2:
30b11d8d 201 result = cast(_Unwind_Internal_Ptr)read_unaligned!ushort(p);
b4c522fa
IB
202 break;
203 case DW_EH_PE_udata4:
30b11d8d 204 result = cast(_Unwind_Internal_Ptr)read_unaligned!uint(p);
b4c522fa
IB
205 break;
206 case DW_EH_PE_udata8:
30b11d8d 207 result = cast(_Unwind_Internal_Ptr)read_unaligned!ulong(p);
b4c522fa
IB
208 break;
209
210 case DW_EH_PE_sdata2:
30b11d8d 211 result = cast(_Unwind_Internal_Ptr)read_unaligned!short(p);
b4c522fa
IB
212 break;
213 case DW_EH_PE_sdata4:
30b11d8d 214 result = cast(_Unwind_Internal_Ptr)read_unaligned!int(p);
b4c522fa
IB
215 break;
216 case DW_EH_PE_sdata8:
30b11d8d 217 result = cast(_Unwind_Internal_Ptr)read_unaligned!long(p);
b4c522fa
IB
218 break;
219
220 case DW_EH_PE_absptr:
30b11d8d
IB
221 result = cast(_Unwind_Internal_Ptr)read_unaligned!(size_t)(p);
222 break;
b4c522fa
IB
223
224 default:
225 __builtin_abort();
226 }
227
228 if (result != 0)
229 {
230 result += ((encoding & 0x70) == DW_EH_PE_pcrel
30b11d8d 231 ? cast(_Unwind_Internal_Ptr)psave : base);
b4c522fa
IB
232 if (encoding & DW_EH_PE_indirect)
233 result = *cast(_Unwind_Internal_Ptr*)result;
234 }
235 }
236
b4c522fa
IB
237 return result;
238}
239
240// Like read_encoded_value_with_base, but get the base from the context
241// rather than providing it directly.
242_Unwind_Ptr read_encoded_value(_Unwind_Context* context, ubyte encoding,
30b11d8d 243 ref const(ubyte)* p)
b4c522fa
IB
244{
245 auto base = base_of_encoded_value(encoding, context);
246 return read_encoded_value_with_base(encoding, base, p);
247}