github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/include/unwind-pe.h (about)

     1  //===----------------------------- unwind-pe.h ----------------------------===//
     2  //
     3  //                     The LLVM Compiler Infrastructure
     4  //
     5  // This file is dual licensed under the MIT and the University of Illinois Open
     6  // Source Licenses. See LICENSE.TXT for details.
     7  //
     8  // Pointer-Encoding decoder. Derived from:
     9  //   - libcxxabi/src/Unwind/dwarf2.h
    10  //   - libcxxabi/src/Unwind/AddressSpace.h
    11  //
    12  //===----------------------------------------------------------------------===//
    13  
    14  #ifndef UNWIND_PE_H
    15  #define UNWIND_PE_H
    16  
    17  #include <assert.h>
    18  #include <stdint.h>
    19  #include <string.h>
    20  
    21  // FSF exception handling Pointer-Encoding constants
    22  // Used in CFI augmentation by GCC
    23  enum {
    24    DW_EH_PE_ptr       = 0x00,
    25    DW_EH_PE_uleb128   = 0x01,
    26    DW_EH_PE_udata2    = 0x02,
    27    DW_EH_PE_udata4    = 0x03,
    28    DW_EH_PE_udata8    = 0x04,
    29    DW_EH_PE_signed    = 0x08,
    30    DW_EH_PE_sleb128   = 0x09,
    31    DW_EH_PE_sdata2    = 0x0A,
    32    DW_EH_PE_sdata4    = 0x0B,
    33    DW_EH_PE_sdata8    = 0x0C,
    34    DW_EH_PE_absptr    = 0x00,
    35    DW_EH_PE_pcrel     = 0x10,
    36    DW_EH_PE_textrel   = 0x20,
    37    DW_EH_PE_datarel   = 0x30,
    38    DW_EH_PE_funcrel   = 0x40,
    39    DW_EH_PE_aligned   = 0x50,
    40    DW_EH_PE_indirect  = 0x80,
    41    DW_EH_PE_omit      = 0xFF
    42  };
    43  
    44  /// Read a ULEB128 into a 64-bit word.
    45  static uint64_t unw_getULEB128(uintptr_t *addr) {
    46    const uint8_t *p = (uint8_t *)*addr;
    47    uint64_t result = 0;
    48    int bit = 0;
    49    do {
    50      uint64_t b;
    51  
    52      b = *p & 0x7f;
    53  
    54      if (bit >= 64 || b << bit >> bit != b) {
    55        assert(!"malformed uleb128 expression");
    56      } else {
    57        result |= b << bit;
    58        bit += 7;
    59      }
    60    } while (*p++ >= 0x80);
    61    *addr = (uintptr_t) p;
    62    return result;
    63  }
    64  
    65  /// Read a SLEB128 into a 64-bit word.
    66  static int64_t unw_getSLEB128(uintptr_t *addr) {
    67    const uint8_t *p = (uint8_t *)addr;
    68    int64_t result = 0;
    69    int bit = 0;
    70    uint8_t byte;
    71    do {
    72      byte = *p++;
    73      result |= ((byte & 0x7f) << bit);
    74      bit += 7;
    75    } while (byte & 0x80);
    76    // sign extend negative numbers
    77    if ((byte & 0x40) != 0)
    78      result |= (-1LL) << bit;
    79    *addr = (uintptr_t) p;
    80    return result;
    81  }
    82  
    83  static uint16_t unw_get16(uintptr_t addr) {
    84    uint16_t val;
    85    memcpy(&val, (void *)addr, sizeof(val));
    86    return val;
    87  }
    88  
    89  static uint32_t unw_get32(uintptr_t addr) {
    90    uint32_t val;
    91    memcpy(&val, (void *)addr, sizeof(val));
    92    return val;
    93  }
    94  
    95  static uint64_t unw_get64(uintptr_t addr) {
    96    uint64_t val;
    97    memcpy(&val, (void *)addr, sizeof(val));
    98    return val;
    99  }
   100  
   101  static uintptr_t unw_getP(uintptr_t addr) {
   102    if (sizeof(uintptr_t) == 8)
   103      return unw_get64(addr);
   104    else
   105      return unw_get32(addr);
   106  }
   107  
   108  static const unsigned char *read_uleb128(const unsigned char *p,
   109                                           _uleb128_t *ret) {
   110    uintptr_t addr = (uintptr_t)p;
   111    *ret = unw_getULEB128(&addr);
   112    return (unsigned char *)addr;
   113  }
   114  
   115  static const unsigned char *read_encoded_value(struct _Unwind_Context *ctx,
   116                                                 unsigned char encoding,
   117                                                 const unsigned char *p,
   118                                                 _Unwind_Ptr *ret) {
   119    uintptr_t addr = (uintptr_t)p;
   120    uintptr_t startAddr = addr;
   121    uintptr_t result;
   122  
   123    (void)ctx;
   124  
   125    // first get value
   126    switch (encoding & 0x0F) {
   127    case DW_EH_PE_ptr:
   128      result = unw_getP(addr);
   129      p += sizeof(uintptr_t);
   130      break;
   131    case DW_EH_PE_uleb128:
   132      result = (uintptr_t)unw_getULEB128(&addr);
   133      p = (const unsigned char *)addr;
   134      break;
   135    case DW_EH_PE_udata2:
   136      result = unw_get16(addr);
   137      p += 2;
   138      break;
   139    case DW_EH_PE_udata4:
   140      result = unw_get32(addr);
   141      p += 4;
   142      break;
   143    case DW_EH_PE_udata8:
   144      result = (uintptr_t)unw_get64(addr);
   145      p += 8;
   146      break;
   147    case DW_EH_PE_sleb128:
   148      result = (uintptr_t)unw_getSLEB128(&addr);
   149      p = (const unsigned char *)addr;
   150      break;
   151    case DW_EH_PE_sdata2:
   152      // Sign extend from signed 16-bit value.
   153      result = (uintptr_t)(int16_t)unw_get16(addr);
   154      p += 2;
   155      break;
   156    case DW_EH_PE_sdata4:
   157      // Sign extend from signed 32-bit value.
   158      result = (uintptr_t)(int32_t)unw_get32(addr);
   159      p += 4;
   160      break;
   161    case DW_EH_PE_sdata8:
   162      result = (uintptr_t)unw_get64(addr);
   163      p += 8;
   164      break;
   165    default:
   166      assert(!"unknown pointer encoding");
   167    }
   168  
   169    // then add relative offset
   170    switch (encoding & 0x70) {
   171    case DW_EH_PE_absptr:
   172      // do nothing
   173      break;
   174    case DW_EH_PE_pcrel:
   175      result += startAddr;
   176      break;
   177    case DW_EH_PE_textrel:
   178      assert(!"DW_EH_PE_textrel pointer encoding not supported");
   179      break;
   180    case DW_EH_PE_datarel:
   181      assert(!"DW_EH_PE_datarel pointer encoding not supported");
   182      break;
   183    case DW_EH_PE_funcrel:
   184      assert(!"DW_EH_PE_funcrel pointer encoding not supported");
   185      break;
   186    case DW_EH_PE_aligned:
   187      assert(!"DW_EH_PE_aligned pointer encoding not supported");
   188      break;
   189    default:
   190      assert(!"unknown pointer encoding");
   191      break;
   192    }
   193  
   194    if (encoding & DW_EH_PE_indirect)
   195      result = unw_getP(result);
   196  
   197    *ret = result;
   198    return p;
   199  }
   200  
   201  #endif  // UNWIND_PE_H