Changeset View
Changeset View
Standalone View
Standalone View
head/devel/gdb/files/commit-929edea98d
Property | Old Value | New Value |
---|---|---|
fbsd:nokeywords | null | yes \ No newline at end of property |
svn:eol-style | null | native \ No newline at end of property |
svn:mime-type | null | text/plain \ No newline at end of property |
commit 929edea98d27cf9d72305c1584ee77627da7fa96 | |||||
Author: John Baldwin <jhb@FreeBSD.org> | |||||
Date: Wed Jun 28 09:53:06 2017 -0700 | |||||
Fetch signal information for native FreeBSD processes. | |||||
Use the `pl_siginfo' field in the `struct ptrace_lwpinfo' object returned | |||||
by the PT_LWPINFO ptrace() request to supply the current contents of | |||||
$_siginfo for each thread. Note that FreeBSD does not supply a way to | |||||
modify the signal information for a thread, so $_siginfo is read-only for | |||||
FreeBSD. | |||||
To handle 32-bit processes on a 64-bit host, define types for 32-bit | |||||
compatible siginfo_t and convert the 64-bit siginfo_t to the 32-bit | |||||
equivalent when supplying information for a 32-bit process. | |||||
gdb/ChangeLog: | |||||
* fbsd-nat.c [PT_LWPINFO && __LP64__] (union sigval32) | |||||
(struct siginfo32): New. | |||||
[PT_LWPINFO] (fbsd_siginfo_size, fbsd_convert_siginfo): New. | |||||
(fbsd_xfer_partial) [PT_LWPINFO]: Handle TARGET_OBJECT_SIGNAL_INFO | |||||
via ptrace(PT_LWPINFO). | |||||
diff --git gdb/fbsd-nat.c gdb/fbsd-nat.c | |||||
index ef5ad1ec92..85f56059bd 100644 | |||||
--- gdb/fbsd-nat.c | |||||
+++ gdb/fbsd-nat.c | |||||
@@ -28,6 +28,7 @@ | |||||
#include <sys/types.h> | |||||
#include <sys/procfs.h> | |||||
#include <sys/ptrace.h> | |||||
+#include <sys/signal.h> | |||||
#include <sys/sysctl.h> | |||||
#ifdef HAVE_KINFO_GETVMMAP | |||||
#include <sys/user.h> | |||||
@@ -216,6 +217,135 @@ static enum target_xfer_status (*super_xfer_partial) (struct target_ops *ops, | |||||
ULONGEST len, | |||||
ULONGEST *xfered_len); | |||||
+#ifdef PT_LWPINFO | |||||
+/* Return the size of siginfo for the current inferior. */ | |||||
+ | |||||
+#ifdef __LP64__ | |||||
+union sigval32 { | |||||
+ int sival_int; | |||||
+ uint32_t sival_ptr; | |||||
+}; | |||||
+ | |||||
+/* This structure matches the naming and layout of `siginfo_t' in | |||||
+ <sys/signal.h>. In particular, the `si_foo' macros defined in that | |||||
+ header can be used with both types to copy fields in the `_reason' | |||||
+ union. */ | |||||
+ | |||||
+struct siginfo32 | |||||
+{ | |||||
+ int si_signo; | |||||
+ int si_errno; | |||||
+ int si_code; | |||||
+ __pid_t si_pid; | |||||
+ __uid_t si_uid; | |||||
+ int si_status; | |||||
+ uint32_t si_addr; | |||||
+ union sigval32 si_value; | |||||
+ union | |||||
+ { | |||||
+ struct | |||||
+ { | |||||
+ int _trapno; | |||||
+ } _fault; | |||||
+ struct | |||||
+ { | |||||
+ int _timerid; | |||||
+ int _overrun; | |||||
+ } _timer; | |||||
+ struct | |||||
+ { | |||||
+ int _mqd; | |||||
+ } _mesgq; | |||||
+ struct | |||||
+ { | |||||
+ int32_t _band; | |||||
+ } _poll; | |||||
+ struct | |||||
+ { | |||||
+ int32_t __spare1__; | |||||
+ int __spare2__[7]; | |||||
+ } __spare__; | |||||
+ } _reason; | |||||
+}; | |||||
+#endif | |||||
+ | |||||
+static size_t | |||||
+fbsd_siginfo_size () | |||||
+{ | |||||
+#ifdef __LP64__ | |||||
+ struct gdbarch *gdbarch = get_frame_arch (get_current_frame ()); | |||||
+ | |||||
+ /* Is the inferior 32-bit? If so, use the 32-bit siginfo size. */ | |||||
+ if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) | |||||
+ return sizeof (struct siginfo32); | |||||
+#endif | |||||
+ return sizeof (siginfo_t); | |||||
+} | |||||
+ | |||||
+/* Convert a native 64-bit siginfo object to a 32-bit object. Note | |||||
+ that FreeBSD doesn't support writing to $_siginfo, so this only | |||||
+ needs to convert one way. */ | |||||
+ | |||||
+static void | |||||
+fbsd_convert_siginfo (siginfo_t *si) | |||||
+{ | |||||
+#ifdef __LP64__ | |||||
+ struct gdbarch *gdbarch = get_frame_arch (get_current_frame ()); | |||||
+ | |||||
+ /* Is the inferior 32-bit? If not, nothing to do. */ | |||||
+ if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word != 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; | |||||
+ | |||||
+ /* 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; | |||||
+ else | |||||
+ si32.si_value.sival_int = si->si_value.sival_int; | |||||
+#else | |||||
+ 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) { | |||||
+ 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; | |||||
+ } | |||||
+ | |||||
+ memcpy(si, &si32, sizeof (si32)); | |||||
+#endif | |||||
+} | |||||
+#endif | |||||
+ | |||||
/* Implement the "to_xfer_partial target_ops" method. */ | |||||
static enum target_xfer_status | |||||
@@ -228,6 +358,38 @@ fbsd_xfer_partial (struct target_ops *ops, enum target_object object, | |||||
switch (object) | |||||
{ | |||||
+#ifdef PT_LWPINFO | |||||
+ case TARGET_OBJECT_SIGNAL_INFO: | |||||
+ { | |||||
+ struct ptrace_lwpinfo pl; | |||||
+ size_t siginfo_size; | |||||
+ | |||||
+ /* FreeBSD doesn't support writing to $_siginfo. */ | |||||
+ if (writebuf != NULL) | |||||
+ return TARGET_XFER_E_IO; | |||||
+ | |||||
+ if (inferior_ptid.lwp_p ()) | |||||
+ pid = inferior_ptid.lwp (); | |||||
+ | |||||
+ siginfo_size = fbsd_siginfo_size (); | |||||
+ if (offset > siginfo_size) | |||||
+ return TARGET_XFER_E_IO; | |||||
+ | |||||
+ if (ptrace (PT_LWPINFO, pid, (PTRACE_TYPE_ARG3) &pl, sizeof (pl)) == -1) | |||||
+ return TARGET_XFER_E_IO; | |||||
+ | |||||
+ if (!(pl.pl_flags & PL_FLAG_SI)) | |||||
+ return TARGET_XFER_E_IO; | |||||
+ | |||||
+ fbsd_convert_siginfo (&pl.pl_siginfo); | |||||
+ if (offset + len > siginfo_size) | |||||
+ len = siginfo_size - offset; | |||||
+ | |||||
+ memcpy (readbuf, ((gdb_byte *) &pl.pl_siginfo) + offset, len); | |||||
+ *xfered_len = len; | |||||
+ return TARGET_XFER_OK; | |||||
+ } | |||||
+#endif | |||||
case TARGET_OBJECT_AUXV: | |||||
{ | |||||
struct cleanup *cleanup = make_cleanup (null_cleanup, NULL); |