diff options
Diffstat (limited to 'usr/src/lib/libc/amd64')
| -rw-r--r-- | usr/src/lib/libc/amd64/Makefile | 4 | ||||
| -rw-r--r-- | usr/src/lib/libc/amd64/unwind/call_frame_inst.c | 41 |
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); } |
