libgo: break dependence on libgcc unwind-pe.h
authorIan Lance Taylor <ian@gcc.gnu.org>
Wed, 2 May 2018 21:53:30 +0000 (21:53 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 2 May 2018 21:53:30 +0000 (21:53 +0000)
    The C portion of the Go runtime includes the header "unwind-pe.h" from
    libgcc, which contains some constants and a few small routines for
    decoding pointer values within unwind info. This patch gets rid of
    that include and instead adds a re-implementation of that
    functionality in the single file that uses it. The intent is to allow
    the C runtime portion of libgo to be built without a companion GCC
    installation.

    Reviewed-on: https://go-review.googlesource.com/90235

From-SVN: r259861

libgo/runtime/go-unwind.c

index 4c9fb49c9942e5ff3c0aa394585a25e4ca59c024..536a619d2987fc08d80fc54a93b21d78cf493915 100644 (file)
 #include <unistd.h>
 
 #include "unwind.h"
-#define NO_SIZE_OF_ENCODED_VALUE
-#include "unwind-pe.h"
 
 #include "runtime.h"
 
+/* These constants are documented here:
+   https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/dwarfext.html
+ */
+
+#define DW_EH_PE_omit     0xff
+#define DW_EH_PE_absptr   0x00
+#define DW_EH_PE_uleb128  0x01
+#define DW_EH_PE_udata2   0x02
+#define DW_EH_PE_udata4   0x03
+#define DW_EH_PE_udata8   0x04
+#define DW_EH_PE_sleb128  0x09
+#define DW_EH_PE_sdata2   0x0A
+#define DW_EH_PE_sdata4   0x0B
+#define DW_EH_PE_sdata8   0x0C
+#define DW_EH_PE_pcrel    0x10
+#define DW_EH_PE_textrel  0x20
+#define DW_EH_PE_datarel  0x30
+#define DW_EH_PE_funcrel  0x40
+#define DW_EH_PE_aligned  0x50
+#define DW_EH_PE_indirect 0x80
+
 /* The code for a Go exception.  */
 
 #ifdef __ARM_EABI_UNWINDER__
@@ -109,6 +128,150 @@ throwException ()
   abort ();
 }
 
+static inline _Unwind_Ptr
+encoded_value_base (uint8_t encoding, struct _Unwind_Context *context)
+{
+  if (encoding == DW_EH_PE_omit)
+    return 0;
+  switch (encoding & 0x70)
+    {
+      case DW_EH_PE_absptr:
+      case DW_EH_PE_pcrel:
+      case DW_EH_PE_aligned:
+        return 0;
+      case DW_EH_PE_textrel:
+        return _Unwind_GetTextRelBase(context);
+      case DW_EH_PE_datarel:
+        return _Unwind_GetDataRelBase(context);
+      case DW_EH_PE_funcrel:
+        return _Unwind_GetRegionStart(context);
+    }
+  abort ();
+}
+
+/* Read an unsigned leb128 value.  */
+
+static inline const uint8_t *
+read_uleb128 (const uint8_t *p, _uleb128_t *val)
+{
+  unsigned int shift = 0;
+  _uleb128_t result = 0;
+  uint8_t byte;
+
+  do
+    {
+      byte = *p++;
+      result |= ((_uleb128_t)byte & 0x7f) << shift;
+      shift += 7;
+    }
+  while (byte & 0x80);
+
+  *val = result;
+  return p;
+}
+
+/* Similar, but read a signed leb128 value.  */
+
+static inline const uint8_t *
+read_sleb128 (const uint8_t *p, _sleb128_t *val)
+{
+  unsigned int shift = 0;
+  _uleb128_t result = 0;
+  uint8_t byte;
+
+  do
+    {
+      byte = *p++;
+      result |= ((_uleb128_t)byte & 0x7f) << shift;
+      shift += 7;
+    }
+  while (byte & 0x80);
+
+  /* sign extension */
+  if (shift < (8 * sizeof(result)) && (byte & 0x40) != 0)
+    result |= (((_uleb128_t)~0) << shift);
+
+  *val = (_sleb128_t)result;
+  return p;
+}
+
+#define ROUND_UP_TO_PVB(x) (x + sizeof(void *) - 1) &- sizeof(void *)
+
+#define COPY_AND_ADVANCE(dst, ptr, typ) \
+  (dst = *((const typ*)ptr),            \
+   ptr += sizeof(typ))
+
+static inline const uint8_t *
+read_encoded_value (struct _Unwind_Context *context, uint8_t encoding,
+                    const uint8_t *p, _Unwind_Ptr *val)
+{
+  _Unwind_Ptr base = encoded_value_base (encoding, context);
+  _Unwind_Internal_Ptr decoded = 0;
+  const uint8_t *origp = p;
+
+  if (encoding == DW_EH_PE_aligned)
+    {
+      _Unwind_Internal_Ptr uip = (_Unwind_Internal_Ptr)p;
+      uip = ROUND_UP_TO_PVB (uip);
+      decoded = *(_Unwind_Internal_Ptr *)uip;
+      p = (const uint8_t *)(uip + sizeof(void *));
+    }
+  else
+    {
+      switch (encoding & 0x0f)
+        {
+          case DW_EH_PE_sdata2:
+          case DW_EH_PE_udata2:
+            COPY_AND_ADVANCE (decoded, p, uint16_t);
+            break;
+          case DW_EH_PE_sdata4:
+          case DW_EH_PE_udata4:
+            COPY_AND_ADVANCE (decoded, p, uint32_t);
+            break;
+          case DW_EH_PE_sdata8:
+          case DW_EH_PE_udata8:
+            COPY_AND_ADVANCE (decoded, p, uint64_t);
+            break;
+          case DW_EH_PE_uleb128:
+            {
+              _uleb128_t value;
+              p = read_uleb128 (p, &value);
+              decoded = (_Unwind_Internal_Ptr)value;
+              break;
+            }
+          case DW_EH_PE_sleb128:
+            {
+              _sleb128_t value;
+              p = read_sleb128 (p, &value);
+              decoded = (_Unwind_Internal_Ptr)value;
+              break;
+            }
+          case DW_EH_PE_absptr:
+            decoded = (_Unwind_Internal_Ptr)(*(const void *const *)p);
+            p += sizeof(void *);
+            break;
+          default:
+            abort ();
+        }
+
+      if (decoded == 0)
+        {
+          *val = decoded;
+          return p;
+        }
+
+      if ((encoding & 0x70) == DW_EH_PE_pcrel)
+        decoded += ((_Unwind_Internal_Ptr)origp);
+      else
+        decoded += base;
+
+      if ((encoding & DW_EH_PE_indirect) != 0)
+        decoded = *(_Unwind_Internal_Ptr *)decoded;
+    }
+  *val = decoded;
+  return p;
+}
+
 /* The rest of this code is really similar to gcc/unwind-c.c and
    libjava/exception.cc.  */