Linux core prstatus support

Message ID 20160121092432.GI17028@bubble.grove.modra.org
State New, archived
Headers

Commit Message

Alan Modra Jan. 21, 2016, 9:24 a.m. UTC
  This and the next patch are the first steps towards making gcore
support writing NT_PRSTATUS on remote/cross targets.  I'm not going to
commit this one and I'm hoping someone from the gdb camp will run with
it as I'm going to be busy with other things in the near future.
  

Patch

diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 6a04f04..b0f5026 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2435,6 +2435,35 @@  extern char *elfcore_write_linux_prpsinfo64
 extern char *elfcore_write_ppc_linux_prpsinfo32
   (bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *);
 
+struct elf_internal_linux_prstatus
+{
+  struct elf_internal_siginfo
+  {
+    int si_signo;
+    int si_code;
+    int si_errno;
+  } pr_info;
+  int pr_cursig;
+  bfd_uint64_t pr_sigpend, pr_sighold;
+  int pr_pid, pr_ppid, pr_pgrp, pr_sid;
+  struct elf_internal_timeval
+  {
+    long tv_sec;
+    long tv_usec;
+  } pr_utime, pr_stime, pr_cutime, pr_cstime;
+  void *pr_reg;
+  int pr_reg_size;
+  int pr_fpvalid;
+};
+
+/* Linux/most 32-bit archs.  */
+extern char *elfcore_write_linux_prstatus32
+  (bfd *, char *, int *, const struct elf_internal_linux_prstatus *);
+
+/* Linux/most 64-bit archs.  */
+extern char *elfcore_write_linux_prstatus64
+  (bfd *, char *, int *, const struct elf_internal_linux_prstatus *);
+
 extern bfd *_bfd_elf32_bfd_from_remote_memory
   (bfd *templ, bfd_vma ehdr_vma, bfd_size_type size, bfd_vma *loadbasep,
    int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type));
diff --git a/bfd/elf-linux-core.h b/bfd/elf-linux-core.h
index 48fd5ae..3838ad1 100644
--- a/bfd/elf-linux-core.h
+++ b/bfd/elf-linux-core.h
@@ -1,4 +1,4 @@ 
-/* Definitions for PRPSINFO structures under ELF on GNU/Linux.
+/* Definitions for PRPSINFO and PRSTATUS structures under ELF on GNU/Linux.
    Copyright (C) 2013-2016 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -120,4 +120,116 @@  swap_linux_prpsinfo64_out (bfd *obfd,
   strncpy (to->pr_psargs, from->pr_psargs, sizeof (to->pr_psargs));
 }
 
+/* PRSTATUS structs.  */
+
+struct elf_external_linux_prstatus32
+{
+  char pr_info[12];
+  char pr_cursig[2];
+  char pad[2];
+  char pr_sigpend[4];
+  char pr_sighold[4];
+  char pr_pid[4];
+  char pr_ppid[4];
+  char pr_pgrp[4];
+  char pr_sid[4];
+  char pr_utime[8];
+  char pr_stime[8];
+  char pr_cutime[8];
+  char pr_cstime[8];
+  /* Variable size "char pr_reg[]" goes here.  */
+  char pr_fpvalid[4];
+};
+
+struct elf_external_linux_prstatus64
+{
+  char pr_info[12];
+  char pr_cursig[2];
+  char pad[2];
+  char pr_sigpend[8];
+  char pr_sighold[8];
+  char pr_pid[4];
+  char pr_ppid[4];
+  char pr_pgrp[4];
+  char pr_sid[4];
+  char pr_utime[16];
+  char pr_stime[16];
+  char pr_cutime[16];
+  char pr_cstime[16];
+  /* Variable size "char pr_reg[]" goes here.  */
+  char pr_fpvalid[4];
+  char pad2[4];
+};
+
+/* Helper function to copy an elf_internal_linux_prpstatus
+   to an elf_external_linux_prpsinfo32 in target endian.
+   FROM->pr_reg is already in target endian.  */
+
+static inline void
+swap_linux_prstatus32_out (bfd *obfd,
+			   const struct elf_internal_linux_prstatus *from,
+			   void *to)
+{
+  struct elf_external_linux_prstatus32 *dest;
+
+  dest = (struct elf_external_linux_prstatus32 *) to;
+  bfd_put_32 (obfd, from->pr_info.si_signo, dest->pr_info + 0);
+  bfd_put_32 (obfd, from->pr_info.si_code, dest->pr_info + 4);
+  bfd_put_32 (obfd, from->pr_info.si_errno, dest->pr_info + 8);
+  bfd_put_16 (obfd, from->pr_cursig, dest->pr_cursig);
+  memset (dest->pad, 0, sizeof (dest->pad));
+  bfd_put_32 (obfd, from->pr_sigpend, dest->pr_sigpend);
+  bfd_put_32 (obfd, from->pr_sighold, dest->pr_sighold);
+  bfd_put_32 (obfd, from->pr_pid, dest->pr_pid);
+  bfd_put_32 (obfd, from->pr_ppid, dest->pr_ppid);
+  bfd_put_32 (obfd, from->pr_pgrp, dest->pr_pgrp);
+  bfd_put_32 (obfd, from->pr_sid, dest->pr_sid);
+  bfd_put_32 (obfd, from->pr_utime.tv_sec, dest->pr_utime + 0);
+  bfd_put_32 (obfd, from->pr_utime.tv_usec, dest->pr_utime + 4);
+  bfd_put_32 (obfd, from->pr_stime.tv_sec, dest->pr_stime + 0);
+  bfd_put_32 (obfd, from->pr_stime.tv_usec, dest->pr_stime + 4);
+  bfd_put_32 (obfd, from->pr_cutime.tv_sec, dest->pr_cutime + 0);
+  bfd_put_32 (obfd, from->pr_cutime.tv_usec, dest->pr_cutime + 4);
+  bfd_put_32 (obfd, from->pr_cstime.tv_sec, dest->pr_cstime + 0);
+  bfd_put_32 (obfd, from->pr_cstime.tv_usec, dest->pr_cstime + 4);
+  memcpy (dest->pr_fpvalid, from->pr_reg, from->pr_reg_size);
+  bfd_put_32 (obfd, from->pr_fpvalid, dest->pr_fpvalid + from->pr_reg_size);
+}
+
+/* Helper function to copy an elf_internal_linux_prpstatus
+   to an elf_external_linux_prpsinfo64 in target endian.
+   FROM->pr_reg is already in target endian.  */
+
+static inline void
+swap_linux_prstatus64_out (bfd *obfd,
+			   const struct elf_internal_linux_prstatus *from,
+			   void *to)
+{
+  struct elf_external_linux_prstatus64 *dest;
+
+  dest = (struct elf_external_linux_prstatus64 *) to;
+  bfd_put_32 (obfd, from->pr_info.si_signo, dest->pr_info + 0);
+  bfd_put_32 (obfd, from->pr_info.si_code, dest->pr_info + 4);
+  bfd_put_32 (obfd, from->pr_info.si_errno, dest->pr_info + 8);
+  bfd_put_16 (obfd, from->pr_cursig, dest->pr_cursig);
+  memset (dest->pad, 0, sizeof (dest->pad));
+  bfd_put_64 (obfd, from->pr_sigpend, dest->pr_sigpend);
+  bfd_put_64 (obfd, from->pr_sighold, dest->pr_sighold);
+  bfd_put_32 (obfd, from->pr_pid, dest->pr_pid);
+  bfd_put_32 (obfd, from->pr_ppid, dest->pr_ppid);
+  bfd_put_32 (obfd, from->pr_pgrp, dest->pr_pgrp);
+  bfd_put_32 (obfd, from->pr_sid, dest->pr_sid);
+  bfd_put_64 (obfd, from->pr_utime.tv_sec, dest->pr_utime + 0);
+  bfd_put_64 (obfd, from->pr_utime.tv_usec, dest->pr_utime + 8);
+  bfd_put_64 (obfd, from->pr_stime.tv_sec, dest->pr_stime + 0);
+  bfd_put_64 (obfd, from->pr_stime.tv_usec, dest->pr_stime + 8);
+  bfd_put_64 (obfd, from->pr_cutime.tv_sec, dest->pr_cutime + 0);
+  bfd_put_64 (obfd, from->pr_cutime.tv_usec, dest->pr_cutime + 8);
+  bfd_put_64 (obfd, from->pr_cstime.tv_sec, dest->pr_cstime + 0);
+  bfd_put_64 (obfd, from->pr_cstime.tv_usec, dest->pr_cstime + 8);
+  memcpy (dest->pr_fpvalid, from->pr_reg, from->pr_reg_size);
+  bfd_put_32 (obfd, from->pr_fpvalid, dest->pr_fpvalid + from->pr_reg_size);
+  memset (dest->pad2 + from->pr_reg_size, 0, sizeof (dest->pad2));
+}
+
 #endif
diff --git a/bfd/elf.c b/bfd/elf.c
index 74c2f2d..16d315d 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -9809,6 +9809,40 @@  elfcore_write_linux_prpsinfo64
 }
 
 char *
+elfcore_write_linux_prstatus32
+  (bfd *obfd,
+   char *buf,
+   int *bufsize,
+   const struct elf_internal_linux_prstatus *prstatus)
+{
+  size_t datasize = (prstatus->pr_reg_size
+		     + sizeof (struct elf_external_linux_prstatus32));
+  char data[1144];
+
+  BFD_ASSERT (sizeof (data) >= datasize);
+  swap_linux_prstatus32_out (obfd, prstatus, data);
+  return elfcore_write_note (obfd, buf, bufsize,
+			     "CORE", NT_PRSTATUS, data, datasize);
+}
+
+char *
+elfcore_write_linux_prstatus64
+  (bfd *obfd,
+   char *buf,
+   int *bufsize,
+   const struct elf_internal_linux_prstatus *prstatus)
+{
+  size_t datasize = (prstatus->pr_reg_size
+		     + sizeof (struct elf_external_linux_prstatus64));
+  char data[1144]; /* Size of ia64 prstatus.  */
+
+  BFD_ASSERT (sizeof (data) >= datasize);
+  swap_linux_prstatus64_out (obfd, prstatus, data);
+  return elfcore_write_note (obfd, buf, bufsize,
+			     "CORE", NT_PRSTATUS, data, datasize);
+}
+
+char *
 elfcore_write_prstatus (bfd *abfd,
 			char *buf,
 			int *bufsiz,