summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog7
-rw-r--r--gdb/fbsd-tdep.c68
2 files changed, 75 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 02397dfd581..42fdda6f591 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,12 @@
2017-07-07 John Baldwin <jhb@FreeBSD.org>
+ * fbsd-tdep.c (LWPINFO_OFFSET, LWPINFO_PL_FLAGS)
+ (LWPINFO64_PL_SIGINFO, LWPINFO32_PL_SIGINFO, PL_FLAG_SI)
+ (SIZE64_SIGINFO_T, SIZE32_SIGINFO_T, fbsd_core_xfer_siginfo): New.
+ (fbsd_init_abi): Install gdbarch "core_xfer_siginfo" method.
+
+2017-07-07 John Baldwin <jhb@FreeBSD.org>
+
* fbsd-tdep.c (fbsd_core_thread_name): Use thread_section_name.
2017-07-07 John Baldwin <jhb@FreeBSD.org>
diff --git a/gdb/fbsd-tdep.c b/gdb/fbsd-tdep.c
index 32df1042080..6f30197a836 100644
--- a/gdb/fbsd-tdep.c
+++ b/gdb/fbsd-tdep.c
@@ -30,6 +30,28 @@
#include "fbsd-tdep.h"
+/* FreeBSD kernels 12.0 and later include a copy of the
+ 'ptrace_lwpinfo' structure returned by the PT_LWPINFO ptrace
+ operation in an ELF core note (NT_FREEBSD_PTLWPINFO) for each LWP.
+ The constants below define the offset of field members and flags in
+ this structure used by methods in this file. Note that the
+ 'ptrace_lwpinfo' struct in the note is preceded by a 4 byte integer
+ containing the size of the structure. */
+
+#define LWPINFO_OFFSET 0x4
+
+/* Offsets in ptrace_lwpinfo. */
+#define LWPINFO_PL_FLAGS 0x8
+#define LWPINFO64_PL_SIGINFO 0x30
+#define LWPINFO32_PL_SIGINFO 0x2c
+
+/* Flags in pl_flags. */
+#define PL_FLAG_SI 0x20 /* siginfo is valid */
+
+/* Sizes of siginfo_t. */
+#define SIZE64_SIGINFO_T 80
+#define SIZE32_SIGINFO_T 64
+
static struct gdbarch_data *fbsd_gdbarch_data_handle;
struct fbsd_gdbarch_data
@@ -113,6 +135,51 @@ fbsd_core_thread_name (struct gdbarch *gdbarch, struct thread_info *thr)
return NULL;
}
+/* Implement the "core_xfer_siginfo" gdbarch method. */
+
+static LONGEST
+fbsd_core_xfer_siginfo (struct gdbarch *gdbarch, gdb_byte *readbuf,
+ ULONGEST offset, ULONGEST len)
+{
+ size_t siginfo_size;
+
+ if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+ siginfo_size = SIZE32_SIGINFO_T;
+ else
+ siginfo_size = SIZE64_SIGINFO_T;
+ if (offset > siginfo_size)
+ return -1;
+
+ thread_section_name section_name (".note.freebsdcore.lwpinfo", inferior_ptid);
+ asection *section = bfd_get_section_by_name (core_bfd, section_name.c_str ());
+ if (section == NULL)
+ return -1;
+
+ gdb_byte buf[4];
+ if (!bfd_get_section_contents (core_bfd, section, buf,
+ LWPINFO_OFFSET + LWPINFO_PL_FLAGS, 4))
+ return -1;
+
+ int pl_flags = extract_signed_integer (buf, 4, gdbarch_byte_order (gdbarch));
+ if (!(pl_flags & PL_FLAG_SI))
+ return -1;
+
+ if (offset + len > siginfo_size)
+ len = siginfo_size - offset;
+
+ ULONGEST siginfo_offset;
+ if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
+ siginfo_offset = LWPINFO_OFFSET + LWPINFO32_PL_SIGINFO;
+ else
+ siginfo_offset = LWPINFO_OFFSET + LWPINFO64_PL_SIGINFO;
+
+ if (!bfd_get_section_contents (core_bfd, section, readbuf,
+ siginfo_offset + offset, len))
+ return -1;
+
+ return len;
+}
+
static int
find_signalled_thread (struct thread_info *info, void *data)
{
@@ -447,6 +514,7 @@ fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_core_pid_to_str (gdbarch, fbsd_core_pid_to_str);
set_gdbarch_core_thread_name (gdbarch, fbsd_core_thread_name);
+ set_gdbarch_core_xfer_siginfo (gdbarch, fbsd_core_xfer_siginfo);
set_gdbarch_make_corefile_notes (gdbarch, fbsd_make_corefile_notes);
set_gdbarch_print_auxv_entry (gdbarch, fbsd_print_auxv_entry);
set_gdbarch_get_siginfo_type (gdbarch, fbsd_get_siginfo_type);