summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc/amd64
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libc/amd64')
-rw-r--r--usr/src/lib/libc/amd64/Makefile4
-rw-r--r--usr/src/lib/libc/amd64/unwind/call_frame_inst.c41
2 files changed, 38 insertions, 7 deletions
diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile
index c21ef76ee2..a134e08c87 100644
--- a/usr/src/lib/libc/amd64/Makefile
+++ b/usr/src/lib/libc/amd64/Makefile
@@ -747,6 +747,8 @@ PORTI18N_COND= \
PORTLOCALE= \
big5.o \
btowc.o \
+ c16rtomb.o \
+ c32rtomb.o \
collate.o \
collcmp.o \
euc.o \
@@ -772,6 +774,8 @@ PORTLOCALE= \
mbftowc.o \
mblen.o \
mbrlen.o \
+ mbrtoc16.o \
+ mbrtoc32.o \
mbrtowc.o \
mbsinit.o \
mbsnrtowcs.o \
diff --git a/usr/src/lib/libc/amd64/unwind/call_frame_inst.c b/usr/src/lib/libc/amd64/unwind/call_frame_inst.c
index 82d357fb0c..3e23a5e25b 100644
--- a/usr/src/lib/libc/amd64/unwind/call_frame_inst.c
+++ b/usr/src/lib/libc/amd64/unwind/call_frame_inst.c
@@ -23,6 +23,7 @@
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2012 Milan Jurik. All rights reserved.
+ * Copyright 2020 Oxide Computer Company
*/
/*
@@ -471,19 +472,25 @@ _Unw_get_val(void **datap, ptrdiff_t reloc,
static uint64_t
get_encoded_val(void **datap, ptrdiff_t reloc, int enc)
{
- int val = enc & 0xf;
- int rel = (enc >> 4) & 0xf;
+ const uint8_t val = enc & 0xf;
+ const uint8_t rel = enc & 0x70;
+ const boolean_t indirect = (enc & 0x80) != 0;
intptr_t loc = ((intptr_t)*datap) + reloc;
uint64_t res = 0;
+ /*
+ * Calculate the offset represented by the pointer encoding. These
+ * DWARF extensions are defined in the Core Generic document set of the
+ * LSB specification.
+ */
switch (val) {
case 0x01:
res = _Unw_get_val(datap, reloc, ULEB128, 1, 1, 0);
break;
- case 0x2:
+ case 0x02:
res = _Unw_get_val(datap, reloc, UNUM16, 1, 1, 0);
break;
- case 0x3:
+ case 0x03:
res = _Unw_get_val(datap, reloc, UNUM32, 1, 1, 0);
break;
case 0x04:
@@ -502,11 +509,11 @@ get_encoded_val(void **datap, ptrdiff_t reloc, int enc)
res = _Unw_get_val(datap, reloc, SNUM64, 1, 1, 0);
break;
}
-
switch (rel) {
- case 0:
+ case 0x00:
break;
- case 1:
+ case 0x10:
+ /* DW_EH_PE_pcrel */
if (res != 0)
res += loc;
break;
@@ -514,6 +521,26 @@ get_encoded_val(void **datap, ptrdiff_t reloc, int enc)
/* remainder not implemented */
break;
}
+
+ /*
+ * The high bit of the pointer encoding (DW_EH_PE_indirect = 0x80)
+ * indicates that a pointer-sized value should be read from the
+ * calculated address as the final result.
+ *
+ * Shockingly, this is not documented in any specification to date, but
+ * has been implemented in various unwind implementations through
+ * reverse-engineering of GCC.
+ */
+ if (indirect) {
+ void *addr = (void *)(uintptr_t)res;
+
+ /*
+ * Built only for amd64, we can count on a 64-bit pointer size
+ * for the indirect handling.
+ */
+ res = _Unw_get_val(&addr, reloc, UNUM64, 1, 1, 0);
+ }
+
return (res);
}