Home | History | Annotate | Line # | Download | only in unwind
      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