Read signal information from FreeBSD core dumps.
authorJohn Baldwin <jhb@FreeBSD.org>
Wed, 28 Jun 2017 19:50:56 +0000 (12:50 -0700)
committerJohn Baldwin <jhb@FreeBSD.org>
Fri, 7 Jul 2017 23:12:42 +0000 (16:12 -0700)
FreeBSD recently added a new ELF core note which dumps the entire LWP
info structure (the same structure returned by the ptrace PT_LWPINFO
operation) for each thread.  The plan is for this note to eventually
supplant the older "thrmisc" ELF core note as it contains more
information and it permits new information to be exported via both
ptrace() and core dumps using the same structure.

For signal information, the implementation is similar to the native
implementation for FreeBSD processes.  The PL_FLAG_SI flag must be
checked to determine if the embedded siginfo_t structure is valid, and
if so it is transferred into the caller's buffer.

gdb/ChangeLog:

* 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.

gdb/ChangeLog
gdb/fbsd-tdep.c

index 02397dfd581f42cabf60057e71b2592755d4a1ea..42fdda6f591eaa489876b3ce5a47ebb5130af8f3 100644 (file)
@@ -1,3 +1,10 @@
+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.
index 32df10420802b74ea3872ec0d7520bcdbddd96b9..6f30197a8366adf0f66bb63a723e47ac68ca21b2 100644 (file)
 #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);