[PATCH 1/2] New entry points for writing Linux NT_PRPSINFO notes.

Pedro Alves
2013-01-31T23:04:59Z

GDB wants to be able to write more complete NT_PRPSINFO Linux notes in
core files. Currently only a few fields are filled in -- fname,
psargs. The current interface, elfcore_write_note is va_args based.
This gets ugly and hard to manage when you expand from those 2 args to
many more. Another point we'd like to address is that core generation
should be host independent, and not depend on the default configured
target. IOW, with GDB on host X, connected to a GDBserver running on
host Y, we want the gcore command to generate correct cores for Y, not
X. This should be true even if neither X nor Y are the default target
for that bfd/GDB build (e.g., a --target=Z --enable-targets=all
build).

One complication is that different kernels/core ABIs have different
prpsinfo_t (and prstatus_t, etc.) structures. Since almost duplicate
bfd target vectors for an arch is not desirable (say, one bare metal,
one Solaris, one GNU/Linux, all for the same arch), one solution would
be to make each write_core_note hooks themselves know for which OS
they are generating the core for. To know which OS it is, I could
picture things like looking at elf_elfheader (abfd)->e_ident[EI_OSABI]
and other possible identifying bits in the bfd. I think that'd get
ugly fast, introduces core generation ordering issues, and, well, GDB
already has the necessary info handy (for core reading, GDB does look
at EI_OSABI and other identifying bits in its osabi "sniff"ing
machinery, but also queries the running target, and other non-bfd
bits).

Since GDB has the needed info already, I believe the simplest solution
to all this, is the one below.

Add a new "struct elf_internal_linux_prpsinfo" structure that is the
internal representation of Linux prpsinfo. The Linux-speficic (but
host-independent) bits of GDB that drive bfd into generating core
notes will instanciate an object of this type, fill it in, and then
call a bfd function (separate from the bfd vector) that swaps the
object to the proper external representation appropriate for the Linux
arch the core is being generated for, and then writes the note.

Most Linux ports have the same prpsinfo_t type (layed out in memory as
per their ABIs, naturally). Be default, for Linux, GDB will call
these two new functions:

/* Linux/most 32-bit archs. */
extern char *elfcore_write_linux_prpsinfo32
(bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *);

/* Linux/most 64-bit archs. */
extern char *elfcore_write_linux_prpsinfo64
(bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *);

GDB will select which depending on the target's pointer width.

PowerPC 32-bit however has a slightly different structure, so it gets
its own entry point:

/* Linux/PPC32 uses different layout compared to most archs. */
extern char *elfcore_write_ppc_linux_prpsinfo32
(bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *);

Tested on x86_64 Fedora 17 by building GDB with --enable-targets=all,
in both 64-bit, and -m32 modes, and by running GDBs testsuite with
each build. No regressions.

I haven't audited all Linux ports to see if like PPC their prpsinfo_t
types are not like the others'.

bfd/
2013-01-31 Sergio Durigan Junior <sergiodj@redhat.com>
Pedro Alves <palves@redhat.com>

* Makefile.in (SOURCE_HFILES): Add `elf-linux-psinfo.h'.
* elf-bfd.h (elf_internal_linux_prpsinfo): New structure
declaration.
(elfcore_write_linux_prpsinfo32, elfcore_write_linux_prpsinfo64)
(elfcore_write_ppc32_linux_prpsinfo32): New declarations.
* elf-linux-psinfo.h: New file.
* elf.c: Include elf-linux-psinfo.h.
(elfcore_write_linux_prpsinfo32, elfcore_write_linux_prpsinfo64):
New functions.
* elf32-ppc.c: Include `elf-linux-psinfo.h'.
(elf_external_ppc_linux_prpsinfo32): New structure declaration.
(PPC_LINUX_PRPSINFO32_SWAP_FIELDS): New macro.
(elfcore_write_ppc_linux_prpsinfo32): New function.
---
0 files changed

diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index af4e5ed..a92debf 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -1072,7 +1072,7 @@ BUILD_CFILES = \
CFILES = $(SOURCE_CFILES) $(BUILD_CFILES)
SOURCE_HFILES = \
aout-target.h aoutf1.h aoutx.h coffcode.h coffswap.h ecoffswap.h \
- elf-bfd.h elf-hppa.h elf32-hppa.h \
+ elf-bfd.h elf-linux-psinfo.h elf-hppa.h elf32-hppa.h \
elf64-hppa.h elfcode.h elfcore.h \
freebsd.h genlink.h go32stub.h \
libaout.h libbfd.h libcoff.h libecoff.h libhppa.h libieee.h \
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index faaf632..1fd73cf 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -2285,6 +2285,42 @@ extern char *elfcore_write_lwpstatus
extern char *elfcore_write_register_note
(bfd *, char *, int *, const char *, const void *, int);

+/* Internal structure which holds information to be included in the
+ PRPSINFO section of Linux core files.
+
+ This is an "internal" structure in the sense that it should be used
+ to pass information to BFD (via the `elfcore_write_linux_prpsinfo'
+ function), so things like endianess shouldn't be an issue. This
+ structure will eventually be converted in one of the
+ `elf_external_linux_*' structures and written out to an output bfd
+ by one of the functions declared below. */
+
+struct elf_internal_linux_prpsinfo
+ {
+ char pr_state; /* Numeric process state. */
+ char pr_sname; /* Char for pr_state. */
+ char pr_zomb; /* Zombie. */
+ char pr_nice; /* Nice val. */
+ unsigned long pr_flag; /* Flags. */
+ unsigned int pr_uid;
+ unsigned int pr_gid;
+ int pr_pid, pr_ppid, pr_pgrp, pr_sid;
+ char pr_fname[16 + 1]; /* Filename of executable. */
+ char pr_psargs[80 + 1]; /* Initial part of arg list. */
+ };
+
+/* Linux/most 32-bit archs. */
+extern char *elfcore_write_linux_prpsinfo32
+ (bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *);
+
+/* Linux/most 64-bit archs. */
+extern char *elfcore_write_linux_prpsinfo64
+ (bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *);
+
+/* Linux/PPC32 uses different layout compared to most archs. */
+extern char *elfcore_write_ppc_linux_prpsinfo32
+ (bfd *, char *, int *, const struct elf_internal_linux_prpsinfo *);
+
extern bfd *_bfd_elf32_bfd_from_remote_memory
(bfd *templ, bfd_vma ehdr_vma, bfd_vma *loadbasep,
int (*target_read_memory) (bfd_vma, bfd_byte *, bfd_size_type));
diff --git a/bfd/elf-linux-psinfo.h b/bfd/elf-linux-psinfo.h
new file mode 100644
index 0000000..c965284
--- /dev/null
+++ b/bfd/elf-linux-psinfo.h
@@ -0,0 +1,127 @@
+/* Definitions for PRPSINFO structures under ELF on GNU/Linux.
+ Copyright 2013 Free Software Foundation, Inc.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef ELF_LINUX_PSINFO_H
+#define ELF_LINUX_PSINFO_H
+
+/* The PRPSINFO structures defined below are used by most
+ architectures, although some of them define their own versions
+ (like e.g., PPC). */
+
+/* External 32-bit structure for PRPSINFO. This structure is
+ ABI-defined, thus we choose to use char arrays here in order to
+ avoid dealing with different types in different architectures.
+
+ This structure will ultimately be written in the corefile's note
+ section, as the PRPSINFO. */
+
+struct elf_external_linux_prpsinfo32
+ {
+ char pr_state; /* Numeric process state. */
+ char pr_sname; /* Char for pr_state. */
+ char pr_zomb; /* Zombie. */
+ char pr_nice; /* Nice val. */
+ char pr_flag[4]; /* Flags. */
+ char pr_uid[2];
+ char pr_gid[2];
+ char pr_pid[4];
+ char pr_ppid[4];
+ char pr_pgrp[4];
+ char pr_sid[4];
+ char pr_fname[16]; /* Filename of executable. */
+ char pr_psargs[80]; /* Initial part of arg list. */
+ };
+
+/* Helper macro to swap (properly handling endianess) things from the
+ `elf_internal_linux_prpsinfo' structure to the
+ `elf_external_linux_prpsinfo32' structure.
+
+ Note that FROM should be a pointer, and TO should be the explicit
+ type. */
+
+#define LINUX_PRPSINFO32_SWAP_FIELDS(abfd, from, to) \
+ do \
+ { \
+ H_PUT_8 (abfd, from->pr_state, &to.pr_state); \
+ H_PUT_8 (abfd, from->pr_sname, &to.pr_sname); \
+ H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb); \
+ H_PUT_8 (abfd, from->pr_nice, &to.pr_nice); \
+ H_PUT_32 (abfd, from->pr_flag, to.pr_flag); \
+ H_PUT_16 (abfd, from->pr_uid, to.pr_uid); \
+ H_PUT_16 (abfd, from->pr_gid, to.pr_gid); \
+ H_PUT_32 (abfd, from->pr_pid, to.pr_pid); \
+ H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid); \
+ H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp); \
+ H_PUT_32 (abfd, from->pr_sid, to.pr_sid); \
+ strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname)); \
+ strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \
+ } while (0)
+
+/* External 64-bit structure for PRPSINFO. This structure is
+ ABI-defined, thus we choose to use char arrays here in order to
+ avoid dealing with different types in different architectures.
+
+ This structure will ultimately be written in the corefile's note
+ section, as the PRPSINFO. */
+
+struct elf_external_linux_prpsinfo64
+ {
+ char pr_state; /* Numeric process state. */
+ char pr_sname; /* Char for pr_state. */
+ char pr_zomb; /* Zombie. */
+ char pr_nice; /* Nice val. */
+ char pr_flag[8]; /* Flags. */
+ char gap[4];
+ char pr_uid[4];
+ char pr_gid[4];
+ char pr_pid[4];
+ char pr_ppid[4];
+ char pr_pgrp[4];
+ char pr_sid[4];
+ char pr_fname[16]; /* Filename of executable. */
+ char pr_psargs[80]; /* Initial part of arg list. */
+ };
+
+/* Helper macro to swap (properly handling endianess) things from the
+ `elf_internal_linux_prpsinfo' structure to the
+ `elf_external_linux_prpsinfo64' structure.
+
+ Note that FROM should be a pointer, and TO should be the explicit
+ type. */
+
+#define LINUX_PRPSINFO64_SWAP_FIELDS(abfd, from, to) \
+ do \
+ { \
+ H_PUT_8 (abfd, from->pr_state, &to.pr_state); \
+ H_PUT_8 (abfd, from->pr_sname, &to.pr_sname); \
+ H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb); \
+ H_PUT_8 (abfd, from->pr_nice, &to.pr_nice); \
+ H_PUT_64 (abfd, from->pr_flag, to.pr_flag); \
+ H_PUT_32 (abfd, from->pr_uid, to.pr_uid); \
+ H_PUT_32 (abfd, from->pr_gid, to.pr_gid); \
+ H_PUT_32 (abfd, from->pr_pid, to.pr_pid); \
+ H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid); \
+ H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp); \
+ H_PUT_32 (abfd, from->pr_sid, to.pr_sid); \
+ strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname)); \
+ strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \
+ } while (0)
+
+#endif
diff --git a/bfd/elf.c b/bfd/elf.c
index 9cd3542..7ab3683 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -45,6 +45,7 @@ SECTION
#include "elf-bfd.h"
#include "libiberty.h"
#include "safe-ctype.h"
+#include "elf-linux-psinfo.h"

#ifdef CORE_HEADER
#include CORE_HEADER
@@ -9159,6 +9160,34 @@ elfcore_write_prpsinfo (bfd *abfd,
}

char *
+elfcore_write_linux_prpsinfo32
+ (bfd *abfd, char *buf, int *bufsiz,
+ const struct elf_internal_linux_prpsinfo *prpsinfo)
+{
+ struct elf_external_linux_prpsinfo32 data;
+
+ memset (&data, 0, sizeof (data));
+ LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data);
+
+ return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO,
+ &data, sizeof (data));
+}
+
+char *
+elfcore_write_linux_prpsinfo64
+ (bfd *abfd, char *buf, int *bufsiz,
+ const struct elf_internal_linux_prpsinfo *prpsinfo)
+{
+ struct elf_external_linux_prpsinfo64 data;
+
+ memset (&data, 0, sizeof (data));
+ LINUX_PRPSINFO64_SWAP_FIELDS (abfd, prpsinfo, data);
+
+ return elfcore_write_note (abfd, buf, bufsiz,
+ "CORE", NT_PRPSINFO, &data, sizeof (data));
+}
+
+char *
elfcore_write_prstatus (bfd *abfd,
char *buf,
int *bufsiz,
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c
index 3f4e4bf..bf14206 100644
--- a/bfd/elf32-ppc.c
+++ b/bfd/elf32-ppc.c
@@ -37,6 +37,7 @@
#include "elf32-ppc.h"
#include "elf-vxworks.h"
#include "dwarf2.h"
+#include "elf-linux-psinfo.h"

typedef enum split16_format_type
{
@@ -1777,6 +1778,58 @@ static reloc_howto_type ppc_elf_howto_raw[] = {
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
};
+
+/* External 32-bit PPC structure for PRPSINFO. This structure is
+ ABI-defined, thus we choose to use char arrays here in order to
+ avoid dealing with different types in different architectures.
+
+ The PPC 32-bit structure uses int for `pr_uid' and `pr_gid' while
+ most non-PPC architectures use `short int'.
+
+ This structure will ultimately be written in the corefile's note
+ section, as the PRPSINFO. */
+
+struct elf_external_ppc_linux_prpsinfo32
+ {
+ char pr_state; /* Numeric process state. */
+ char pr_sname; /* Char for pr_state. */
+ char pr_zomb; /* Zombie. */
+ char pr_nice; /* Nice val. */
+ char pr_flag[4]; /* Flags. */
+ char pr_uid[4];
+ char pr_gid[4];
+ char pr_pid[4];
+ char pr_ppid[4];
+ char pr_pgrp[4];
+ char pr_sid[4];
+ char pr_fname[16]; /* Filename of executable. */
+ char pr_psargs[80]; /* Initial part of arg list. */
+ };
+
+/* Helper macro to swap (properly handling endianess) things from the
+ `elf_internal_prpsinfo' structure to the `elf_external_ppc_prpsinfo32'
+ structure.
+
+ Note that FROM should be a pointer, and TO should be the explicit type. */
+
+#define PPC_LINUX_PRPSINFO32_SWAP_FIELDS(abfd, from, to) \
+ do \
+ { \
+ H_PUT_8 (abfd, from->pr_state, &to.pr_state); \
+ H_PUT_8 (abfd, from->pr_sname, &to.pr_sname); \
+ H_PUT_8 (abfd, from->pr_zomb, &to.pr_zomb); \
+ H_PUT_8 (abfd, from->pr_nice, &to.pr_nice); \
+ H_PUT_32 (abfd, from->pr_flag, to.pr_flag); \
+ H_PUT_32 (abfd, from->pr_uid, to.pr_uid); \
+ H_PUT_32 (abfd, from->pr_gid, to.pr_gid); \
+ H_PUT_32 (abfd, from->pr_pid, to.pr_pid); \
+ H_PUT_32 (abfd, from->pr_ppid, to.pr_ppid); \
+ H_PUT_32 (abfd, from->pr_pgrp, to.pr_pgrp); \
+ H_PUT_32 (abfd, from->pr_sid, to.pr_sid); \
+ strncpy (to.pr_fname, from->pr_fname, sizeof (to.pr_fname)); \
+ strncpy (to.pr_psargs, from->pr_psargs, sizeof (to.pr_psargs)); \
+ } while (0)
+
\f
/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */

@@ -2212,6 +2265,19 @@ ppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
return TRUE;
}

+char *
+elfcore_write_ppc_linux_prpsinfo32 (bfd *abfd, char *buf, int *bufsiz,
+ const struct elf_internal_linux_prpsinfo *prpsinfo)
+{
+ struct elf_external_ppc_linux_prpsinfo32 data;
+
+ memset (&data, 0, sizeof (data));
+ PPC_LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data);
+
+ return elfcore_write_note (abfd, buf, bufsiz,
+ "CORE", NT_PRPSINFO, &data, sizeof (data));
+}
+
static char *
ppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...)
{