github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/include/unwind-pe.h (about)

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