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