aboutsummaryrefslogtreecommitdiff
path: root/libgo/runtime/go-unwind.c
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2018-05-02 21:53:30 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2018-05-02 21:53:30 +0000
commit019808c95c540a830a64c132257bde018abf6a1e (patch)
treeb635fa4c3ee82a3c372d5ef01531c276fd59559f /libgo/runtime/go-unwind.c
parent27db01d8039a1a1664bcd1ebd1f66cedcfe72398 (diff)
downloadgcc-019808c95c540a830a64c132257bde018abf6a1e.zip
gcc-019808c95c540a830a64c132257bde018abf6a1e.tar.gz
gcc-019808c95c540a830a64c132257bde018abf6a1e.tar.bz2
libgo: break dependence on libgcc unwind-pe.h
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
Diffstat (limited to 'libgo/runtime/go-unwind.c')
-rw-r--r--libgo/runtime/go-unwind.c167
1 files changed, 165 insertions, 2 deletions
diff --git a/libgo/runtime/go-unwind.c b/libgo/runtime/go-unwind.c
index 4c9fb49..536a619 100644
--- a/libgo/runtime/go-unwind.c
+++ b/libgo/runtime/go-unwind.c
@@ -10,11 +10,30 @@
#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. */