From 3ccd529460bbb5369d025a341e074b0697e261a5 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 21 Jan 2016 19:54:32 +1030 Subject: [PATCH] Linux core prstatus support 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. --- bfd/elf-bfd.h | 29 +++++++++++ bfd/elf-linux-core.h | 114 ++++++++++++++++++++++++++++++++++++++++++- bfd/elf.c | 34 +++++++++++++ 3 files changed, 176 insertions(+), 1 deletion(-) diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 6a04f044e78..b0f5026a5f3 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 48fd5aeb559..3838ad16d70 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 74c2f2d33a4..16d315df2ca 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -9808,6 +9808,40 @@ elfcore_write_linux_prpsinfo64 "CORE", NT_PRPSINFO, &data, sizeof (data)); } +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, -- 2.47.2