From: John Baldwin Date: Thu, 13 Dec 2018 00:27:46 +0000 (-0800) Subject: Add support for siginfo with CHERI. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=41176549f22ee853a11450752731460bb8e2f602;p=thirdparty%2Fbinutils-gdb.git Add support for siginfo with CHERI. - Add siginfo sizes and offsets to support $_siginfo in core dumps. - Align the si_addr and si_value fields in siginfo which fixes the layout of $_siginfo for CHERI. - Add the new si_capreg field for SIGPROT to the siginfo type. - Support CHERI siginfo in the live FreeBSD target. --- diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c index 8b1f0054096..32e8f77ead7 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -440,7 +440,96 @@ fbsd_nat_target::info_proc (const char *args, enum info_proc_what what) /* Return the size of siginfo for the current inferior. */ -#ifdef __LP64__ +#if __has_feature(capabilities) +#ifdef __CHERI_PURE_CAPABILITY__ +union sigval64 { + int sival_int; + uint64_t sival_ptr; +}; + +struct siginfo64 +{ + int si_signo; + int si_errno; + int si_code; + __pid_t si_pid; + __uid_t si_uid; + int si_status; + uint64_t si_addr; + union sigval64 si_value; + union + { + struct + { + int _trapno; + int _capreg; + } _fault; + struct + { + int _timerid; + int _overrun; + } _timer; + struct + { + int _mqd; + } _mesgq; + struct + { + int64_t _band; + } _poll; + struct + { + int64_t __spare1__; + int __spare2__[7]; + } __spare__; + } _reason; +}; +#else +union sigval_c { + int sival_int; + void * __capability sival_ptr; +}; + +struct siginfo_c { + int si_signo; + int si_errno; + int si_code; + __pid_t si_pid; + __uid_t si_uid; + int si_status; + void * __capability si_addr; + union sigval_c si_value; + union + { + struct + { + int _trapno; + int _capreg; + } _fault; + struct + { + int _timerid; + int _overrun; + } _timer; + struct + { + int _mqd; + } _mesgq; + struct + { + int64_t _band; + } _poll; + struct + { + int64_t __spare1__; + int __spare2__[7]; + } __spare__; + } _reason; +}; +#endif +#endif + +#if defined(__LP64__) || __has_feature(capabilities) union sigval32 { int sival_int; uint32_t sival_ptr; @@ -466,6 +555,7 @@ struct siginfo32 struct { int _trapno; + int _capreg; } _fault; struct { @@ -492,12 +582,22 @@ struct siginfo32 static size_t fbsd_siginfo_size () { -#ifdef __LP64__ +#if defined(__LP64__) || __has_feature(capabilities) struct gdbarch *gdbarch = get_frame_arch (get_current_frame ()); /* Is the inferior 32-bit? If so, use the 32-bit siginfo size. */ if (gdbarch_long_bit (gdbarch) == 32) return sizeof (struct siginfo32); +#endif +#if __has_feature(capabilities) +#ifdef __CHERI_PURE_CAPABILITY__ + if (gdbarch_ptr_bit (gdbarch) == 64) + return sizeof (struct siginfo64); +#else + if (gdbarch_ptr_bit (gdbarch) + == sizeof(void * __capability) * TARGET_CHAR_BIT) + return sizeof (struct siginfo_c); +#endif #endif return sizeof (siginfo_t); } @@ -506,63 +606,188 @@ fbsd_siginfo_size () that FreeBSD doesn't support writing to $_siginfo, so this only needs to convert one way. */ +#if defined(__LP64__) || __has_feature(capabilities) static void -fbsd_convert_siginfo (siginfo_t *si) +fbsd_convert_siginfo32 (siginfo_t *si, struct siginfo32 *si32) { -#ifdef __LP64__ - struct gdbarch *gdbarch = get_frame_arch (get_current_frame ()); - - /* Is the inferior 32-bit? If not, nothing to do. */ - if (gdbarch_long_bit (gdbarch) != 32) - return; - - struct siginfo32 si32; - - si32.si_signo = si->si_signo; - si32.si_errno = si->si_errno; - si32.si_code = si->si_code; - si32.si_pid = si->si_pid; - si32.si_uid = si->si_uid; - si32.si_status = si->si_status; - si32.si_addr = (uintptr_t) si->si_addr; + si32->si_signo = si->si_signo; + si32->si_errno = si->si_errno; + si32->si_code = si->si_code; + si32->si_pid = si->si_pid; + si32->si_uid = si->si_uid; + si32->si_status = si->si_status; + si32->si_addr = (uintptr_t) si->si_addr; /* If sival_ptr is being used instead of sival_int on a big-endian platform, then sival_int will be zero since it holds the upper 32-bits of the pointer value. */ #if _BYTE_ORDER == _BIG_ENDIAN if (si->si_value.sival_int == 0) - si32.si_value.sival_ptr = (uintptr_t) si->si_value.sival_ptr; + si32->si_value.sival_ptr = (uintptr_t) si->si_value.sival_ptr; else - si32.si_value.sival_int = si->si_value.sival_int; + si32->si_value.sival_int = si->si_value.sival_int; #else - si32.si_value.sival_int = si->si_value.sival_int; + si32->si_value.sival_int = si->si_value.sival_int; +#endif + + /* Always copy the spare fields and then possibly overwrite them for + signal-specific or code-specific fields. */ + si32->_reason.__spare__.__spare1__ = si->_reason.__spare__.__spare1__; + for (int i = 0; i < 7; i++) + si32->_reason.__spare__.__spare2__[i] = si->_reason.__spare__.__spare2__[i]; + switch (si->si_signo) { +#ifdef SIGPROT + case SIGPROT: + si32->si_capreg = si->si_capreg; + /* FALLTHROUGH */ +#endif + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + si32->si_trapno = si->si_trapno; + break; + } + switch (si->si_code) { + case SI_TIMER: + si32->si_timerid = si->si_timerid; + si32->si_overrun = si->si_overrun; + break; + case SI_MESGQ: + si32->si_mqd = si->si_mqd; + break; + } +} #endif +#if __has_feature(capabilities) +#ifdef __CHERI_PURE_CAPABILITY__ +static void +fbsd_convert_siginfo64 (siginfo_t *si, struct siginfo64 *si64) +{ + si64->si_signo = si->si_signo; + si64->si_errno = si->si_errno; + si64->si_code = si->si_code; + si64->si_pid = si->si_pid; + si64->si_uid = si->si_uid; + si64->si_status = si->si_status; + si64->si_addr = (__cheri_addr uint64_t)si->si_addr; + + /* XXX: Just copy the int for now as I'm not sure how a 64-bit + sival_ptr is stored in freebsd64. */ + si64->si_value.sival_ptr = 0; + si64->si_value.sival_int = si->si_value.sival_int; + + /* Always copy the spare fields and then possibly overwrite them for + signal-specific or code-specific fields. */ + si64->_reason.__spare__.__spare1__ = si->_reason.__spare__.__spare1__; + for (int i = 0; i < 7; i++) + si64->_reason.__spare__.__spare2__[i] = si->_reason.__spare__.__spare2__[i]; + switch (si->si_signo) { + case SIGPROT: + si64->si_capreg = si->si_capreg; + /* FALLTHROUGH */ + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + si64->si_trapno = si->si_trapno; + break; + } + switch (si->si_code) { + case SI_TIMER: + si64->si_timerid = si->si_timerid; + si64->si_overrun = si->si_overrun; + break; + case SI_MESGQ: + si64->si_mqd = si->si_mqd; + break; + } +} +#else +static void +fbsd_convert_siginfo_c (siginfo_t *si, struct siginfo_c *si_c) +{ + si_c->si_signo = si->si_signo; + si_c->si_errno = si->si_errno; + si_c->si_code = si->si_code; + si_c->si_pid = si->si_pid; + si_c->si_uid = si->si_uid; + si_c->si_status = si->si_status; + si_c->si_addr = (void * __capability)(uintcap_t)si->si_addr; + + /* It doesn't make sense to try to copy a 64-bit sival_ptr to a + capability pointer, so just copy the integer always. */ + si_c->si_value.sival_ptr = NULL; + si_c->si_value.sival_int = si->si_value.sival_int; + /* Always copy the spare fields and then possibly overwrite them for signal-specific or code-specific fields. */ - si32._reason.__spare__.__spare1__ = si->_reason.__spare__.__spare1__; + si_c->_reason.__spare__.__spare1__ = si->_reason.__spare__.__spare1__; for (int i = 0; i < 7; i++) - si32._reason.__spare__.__spare2__[i] = si->_reason.__spare__.__spare2__[i]; + si_c->_reason.__spare__.__spare2__[i] = si->_reason.__spare__.__spare2__[i]; switch (si->si_signo) { + case SIGPROT: + si_c->si_capreg = si->si_capreg; + /* FALLTHROUGH */ case SIGILL: case SIGFPE: case SIGSEGV: case SIGBUS: - si32.si_trapno = si->si_trapno; + si_c->si_trapno = si->si_trapno; break; } switch (si->si_code) { case SI_TIMER: - si32.si_timerid = si->si_timerid; - si32.si_overrun = si->si_overrun; + si_c->si_timerid = si->si_timerid; + si_c->si_overrun = si->si_overrun; break; case SI_MESGQ: - si32.si_mqd = si->si_mqd; + si_c->si_mqd = si->si_mqd; break; } +} +#endif +#endif - memcpy(si, &si32, sizeof (si32)); +union siginfo_buffer { + siginfo_t si; +#if defined(__LP64__) || __has_feature(capabilities) + struct siginfo32 si32; +#endif +#if __has_feature(capabilities) +#ifdef __CHERI_PURE_CAPABILITY__ + struct siginfo64 si64; +#else + struct siginfo_c si_c; +#endif +#endif +}; + +static void +fbsd_convert_siginfo (siginfo_t *si, union siginfo_buffer *dst) +{ +#if defined(__LP64__) || __has_feature(capabilities) + struct gdbarch *gdbarch = get_frame_arch (get_current_frame ()); + + /* Is the inferior 32-bit? If so, convert to si32. */ + if (gdbarch_long_bit (gdbarch) == 32) + fbsd_convert_siginfo32(si, &dst->si32); + else +#endif +#if __has_feature(capabilities) +#ifdef __CHERI_PURE_CAPABILITY__ + if (gdbarch_ptr_bit (gdbarch) == 64) + fbsd_convert_siginfo64(si, &dst->si64); + else +#else + if (gdbarch_ptr_bit (gdbarch) + == sizeof(void * __capability) * TARGET_CHAR_BIT) + fbsd_convert_siginfo_c(si, &dst->si_c); + else +#endif #endif + dst->si = *si; } /* Implement the "xfer_partial" target_ops method. */ @@ -600,11 +825,12 @@ fbsd_nat_target::xfer_partial (enum target_object object, if (!(pl.pl_flags & PL_FLAG_SI)) return TARGET_XFER_E_IO; - fbsd_convert_siginfo (&pl.pl_siginfo); + union siginfo_buffer si_buf; + fbsd_convert_siginfo (&pl.pl_siginfo, &si_buf); if (offset + len > siginfo_size) len = siginfo_size - offset; - memcpy (readbuf, ((gdb_byte *) &pl.pl_siginfo) + offset, len); + memcpy (readbuf, ((gdb_byte *) &si_buf) + offset, len); *xfered_len = len; return TARGET_XFER_OK; } diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c index 677f229e52b..6392600ca84 100644 --- a/gdb/fbsd-tdep.c +++ b/gdb/fbsd-tdep.c @@ -145,6 +145,7 @@ enum /* Offsets in ptrace_lwpinfo. */ #define LWPINFO_PL_FLAGS 0x8 +#define LWPINFOC128_PL_SIGINFO 0x30 #define LWPINFO64_PL_SIGINFO 0x30 #define LWPINFO32_PL_SIGINFO 0x2c @@ -152,6 +153,7 @@ enum #define PL_FLAG_SI 0x20 /* siginfo is valid */ /* Sizes of siginfo_t. */ +#define SIZEC128_SIGINFO_T 112 #define SIZE64_SIGINFO_T 80 #define SIZE32_SIGINFO_T 64 @@ -602,7 +604,9 @@ fbsd_core_xfer_siginfo (struct gdbarch *gdbarch, gdb_byte *readbuf, { size_t siginfo_size; - if (gdbarch_long_bit (gdbarch) == 32) + if (gdbarch_ptr_bit (gdbarch) == 128) + siginfo_size = SIZEC128_SIGINFO_T; + else if (gdbarch_long_bit (gdbarch) == 32) siginfo_size = SIZE32_SIGINFO_T; else siginfo_size = SIZE64_SIGINFO_T; @@ -627,7 +631,9 @@ fbsd_core_xfer_siginfo (struct gdbarch *gdbarch, gdb_byte *readbuf, len = siginfo_size - offset; ULONGEST siginfo_offset; - if (gdbarch_long_bit (gdbarch) == 32) + if (gdbarch_ptr_bit (gdbarch) == 128) + siginfo_offset = LWPINFO_OFFSET + LWPINFOC128_PL_SIGINFO; + else if (gdbarch_long_bit (gdbarch) == 32) siginfo_offset = LWPINFO_OFFSET + LWPINFO32_PL_SIGINFO; else siginfo_offset = LWPINFO_OFFSET + LWPINFO64_PL_SIGINFO; @@ -1629,6 +1635,7 @@ fbsd_get_siginfo_type (struct gdbarch *gdbarch) /* _fault */ type = arch_composite_type (gdbarch, NULL, TYPE_CODE_STRUCT); append_composite_type_field (type, "si_trapno", int_type); + append_composite_type_field (type, "si_capreg", int_type); append_composite_type_field (reason_type, "_fault", type); /* _timer */ @@ -1663,8 +1670,10 @@ fbsd_get_siginfo_type (struct gdbarch *gdbarch) append_composite_type_field (siginfo_type, "si_pid", pid_type); append_composite_type_field (siginfo_type, "si_uid", uid_type); append_composite_type_field (siginfo_type, "si_status", int_type); - append_composite_type_field (siginfo_type, "si_addr", void_ptr_type); - append_composite_type_field (siginfo_type, "si_value", sigval_type); + append_composite_type_field_aligned (siginfo_type, "si_addr", void_ptr_type, + type_align (void_ptr_type)); + append_composite_type_field_aligned (siginfo_type, "si_value", sigval_type, + type_align (sigval_type)); append_composite_type_field (siginfo_type, "_reason", reason_type); fbsd_gdbarch_data->siginfo_type = siginfo_type;