From: Roland McGrath Date: Thu, 23 Aug 2007 08:10:54 +0000 (+0000) Subject: readelf register printing sort order tweak X-Git-Tag: elfutils-0.130~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cb6d865011ad98a8ac2018f072f396a2268739ca;p=thirdparty%2Felfutils.git readelf register printing sort order tweak --- diff --git a/backends/ChangeLog b/backends/ChangeLog index 994aec07d..159e6dc17 100644 --- a/backends/ChangeLog +++ b/backends/ChangeLog @@ -1,3 +1,46 @@ +2007-08-23 Roland McGrath + + * x86_64_regs.c (x86_64_register_info): Put %rflags in "integer" set. + +2007-08-22 Roland McGrath + + * linux-core-note.c (prstatus_items): Add .group initializers. + (prpsinfo_items): Likewise. + * x86_64_corenote.c (PRSTATUS_REGSET_ITEMS): Likewise. + * i386_corenote.c (PRSTATUS_REGSET_ITEMS): Likewise. + * ppc_corenote.c (PRSTATUS_REGSET_ITEMS): Likewise. + +2007-08-20 Roland McGrath + + * ppc_symbol.c (ppc_check_special_symbol): For _GLOBAL_OFFSET_TABLE_ + when DT_PPC_GOT is not found, anywhere in the section is valid. + +2007-08-19 Roland McGrath + + * i386_auxv.c: New file. + * Makefile.am (i386_SRCS, x86_64_SRCS): Add it. + * ppc_auxv.c: New file. + * Makefile.am (ppc_SRCS, ppc64_SRCS): Add it. + * i386_init.c (i386_init): Initialize auxv_info hook. + * x86_64_init.c (x86_64_init): Likewise. + * ppc_init.c (ppc_init): Likewise. + * ppc64_init.c (ppc64_init): Likewise. + + * alpha_corenote.c: New file. + * Makefile.am (alpha_SRCS): Add it. + * alpha_init.c (alpha_init): Initialize core_note hook. + + * ppc_corenote.c: New file. + * ppc64_corenote.c: New file. + * Makefile.am (ppc_SRCS, ppc64_SRCS): Add them. + * ppc_init.c (ppc_init): Initialize core_note hook. + * ppc64_init.c (ppc64_init): Likewise. + + * linux-core-note.c: New file. + * Makefile.am (noinst_HEADERS): Add it. + * i386_corenote.c: Rewritten. + * x86_64_corenote.c: Likewise. + 2007-05-23 Roland McGrath * alpha_regs.c (alpha_register_info): fp -> s6 diff --git a/backends/Makefile.am b/backends/Makefile.am index f7e1525d8..84aa47852 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to create Makefile.in ## -## Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. +## Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Red Hat, Inc. ## This file is part of Red Hat elfutils. ## ## Red Hat elfutils is free software; you can redistribute it and/or modify @@ -70,7 +70,7 @@ libebl_%.map: Makefile i386_SRCS = i386_init.c i386_symbol.c i386_corenote.c \ - i386_retval.c i386_regs.c + i386_retval.c i386_regs.c i386_auxv.c libebl_i386_pic_a_SOURCES = $(i386_SRCS) am_libebl_i386_pic_a_OBJECTS = $(i386_SRCS:.c=.os) @@ -79,7 +79,7 @@ libebl_sh_pic_a_SOURCES = $(sh_SRCS) am_libebl_sh_pic_a_OBJECTS = $(sh_SRCS:.c=.os) x86_64_SRCS = x86_64_init.c x86_64_symbol.c x86_64_corenote.c \ - x86_64_retval.c x86_64_regs.c + x86_64_retval.c x86_64_regs.c i386_auxv.c libebl_x86_64_pic_a_SOURCES = $(x86_64_SRCS) am_libebl_x86_64_pic_a_OBJECTS = $(x86_64_SRCS:.c=.os) @@ -87,7 +87,8 @@ ia64_SRCS = ia64_init.c ia64_symbol.c ia64_regs.c ia64_retval.c libebl_ia64_pic_a_SOURCES = $(ia64_SRCS) am_libebl_ia64_pic_a_OBJECTS = $(ia64_SRCS:.c=.os) -alpha_SRCS = alpha_init.c alpha_symbol.c alpha_retval.c alpha_regs.c +alpha_SRCS = alpha_init.c alpha_symbol.c alpha_retval.c alpha_regs.c \ + alpha_corenote.c libebl_alpha_pic_a_SOURCES = $(alpha_SRCS) am_libebl_alpha_pic_a_OBJECTS = $(alpha_SRCS:.c=.os) @@ -99,11 +100,13 @@ sparc_SRCS = sparc_init.c sparc_symbol.c sparc_regs.c sparc_retval.c libebl_sparc_pic_a_SOURCES = $(sparc_SRCS) am_libebl_sparc_pic_a_OBJECTS = $(sparc_SRCS:.c=.os) -ppc_SRCS = ppc_init.c ppc_symbol.c ppc_retval.c ppc_regs.c +ppc_SRCS = ppc_init.c ppc_symbol.c ppc_retval.c ppc_regs.c \ + ppc_corenote.c ppc_auxv.c libebl_ppc_pic_a_SOURCES = $(ppc_SRCS) am_libebl_ppc_pic_a_OBJECTS = $(ppc_SRCS:.c=.os) -ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c ppc_regs.c +ppc64_SRCS = ppc64_init.c ppc64_symbol.c ppc64_retval.c \ + ppc64_corenote.c ppc_regs.c ppc_auxv.c libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS) am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os) @@ -134,7 +137,7 @@ uninstall: uninstall-am done rmdir --ignore-fail-on-non-empty $(DESTDIR)$(libdir)/$(LIBEBL_SUBDIR) -noinst_HEADERS = libebl_CPU.h common-reloc.c +noinst_HEADERS = libebl_CPU.h common-reloc.c linux-core-note.c EXTRA_DIST = $(foreach m,$(modules),$($(m)_SRCS)) $(modules:=_reloc.def) CLEANFILES = *.gcno *.gcda \ diff --git a/backends/alpha_corenote.c b/backends/alpha_corenote.c new file mode 100644 index 000000000..dcc62e9e7 --- /dev/null +++ b/backends/alpha_corenote.c @@ -0,0 +1,67 @@ +/* PowerPC specific core note handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils 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; version 2 of the License. + + Red Hat elfutils 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 Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#define BACKEND alpha_ +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { + { .offset = 0, .regno = 0, .count = 31, .bits = 64 }, /* r0-r30 */ + { .offset = 32 * 8, .regno = 64, .count = 1, .bits = 64 }, /* pc */ + { .offset = 33 * 8, .regno = 66, .count = 1, .bits = 64 }, /* unique */ + }; +#define PRSTATUS_REGS_SIZE (33 * 8) + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 32, .count = 32, .bits = 64 }, /* f0-f30, fpcr */ + }; +#define FPREGSET_SIZE (32 * 8) + +#define ULONG uint64_t +#define ALIGN_ULONG 8 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_LONG ELF_T_SXWORD +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#include "linux-core-note.c" diff --git a/backends/alpha_init.c b/backends/alpha_init.c index ba5ca12fc..794d412a8 100644 --- a/backends/alpha_init.c +++ b/backends/alpha_init.c @@ -54,8 +54,9 @@ alpha_init (elf, machine, eh, ehlen) HOOK (eh, dynamic_tag_check); HOOK (eh, reloc_simple_type); HOOK (eh, return_value_location); - HOOK (eh, register_info); HOOK (eh, machine_section_flag_check); + HOOK (eh, register_info); + HOOK (eh, core_note); eh->sysvhash_entrysize = sizeof (Elf64_Xword); return MODVERSION; diff --git a/backends/i386_auxv.c b/backends/i386_auxv.c new file mode 100644 index 000000000..5f7b15eff --- /dev/null +++ b/backends/i386_auxv.c @@ -0,0 +1,49 @@ +/* i386 specific auxv handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils 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; version 2 of the License. + + Red Hat elfutils 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 Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#define BACKEND i386_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "fpu\0" "vme\0" "de\0" "pse\0" "tsc\0" "msr\0" "pae\0" "mce\0" + "cx8\0" "apic\0" "10\0" "sep\0" "mtrr\0" "pge\0" "mca\0" "cmov\0" + "pat\0" "pse36\0" "pn\0" "clflush\0" "20\0" "dts\0" "acpi\0" "mmx\0" + "fxsr\0" "sse\0" "sse2\0" "ss\0" "ht\0" "tm\0" "ia64\0" "pbe\0" "\0"; + return 1; +} + +__typeof (i386_auxv_info) x86_64_auxv_info + __attribute__ ((alias ("i386_auxv_info"))); diff --git a/backends/i386_corenote.c b/backends/i386_corenote.c index c9d3e5fb2..cc72a45f6 100644 --- a/backends/i386_corenote.c +++ b/backends/i386_corenote.c @@ -1,7 +1,6 @@ /* i386 specific core note handling. - Copyright (C) 2002, 2005 Red Hat, Inc. + Copyright (C) 2007 Red Hat, Inc. This file is part of Red Hat elfutils. - Written by Ulrich Drepper , 2002. Red Hat elfutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -38,138 +37,68 @@ #include "libebl_CPU.h" -/* We cannot include since the definition would be for - the host platform and not always x86 as required here. */ -struct elf_prstatus +static const Ebl_Register_Location prstatus_regs[] = { - struct - { - int32_t si_signo; /* Signal number. */ - int32_t si_code; /* Extra code. */ - int32_t si_errno; /* Errno. */ - } pr_info; /* Info associated with signal. */ - int16_t pr_cursig; /* Current signal. */ - uint32_t pr_sigpend; /* Set of pending signals. */ - uint32_t pr_sighold; /* Set of held signals. */ - int32_t pr_pid; - int32_t pr_ppid; - int32_t pr_pgrp; - int32_t pr_sid; - struct i386_timeval - { - int32_t tv_sec; - int32_t tv_usec; - } pr_utime; /* User time. */ - struct i386_timeval pr_stime; /* System time. */ - struct i386_timeval pr_cutime; /* Cumulative user time. */ - struct i386_timeval pr_cstime; /* Cumulative system time. */ - uint32_t pr_reg[17]; /* GP registers. */ - int32_t pr_fpvalid; /* True if math copro being used. */ +#define GR(at, n, dwreg) \ + { .offset = at * 4, .regno = dwreg, .count = n, .bits = 32 } +#define SR(at, n, dwreg) \ + { .offset = at * 4, .regno = dwreg, .count = n, .bits = 16, .pad = 2 } + + GR (0, 1, 3), /* %ebx */ + GR (1, 2, 1), /* %ecx-%edx */ + GR (3, 2, 6), /* %esi-%edi */ + GR (5, 1, 5), /* %ebp */ + GR (6, 1, 0), /* %eax */ + SR (7, 1, 43), /* %ds */ + SR (8, 1, 40), /* %es */ + SR (9, 1, 44), /* %fs */ + SR (10, 1, 45), /* %gs */ + /* 11, 1, orig_eax */ + GR (12, 1, 8), /* %eip */ + SR (13, 1, 41), /* %cs */ + GR (14, 1, 9), /* eflags */ + GR (15, 1, 4), /* %esp */ + SR (16, 1, 42), /* %ss */ + +#undef GR +#undef SR }; - - -struct elf_prpsinfo +#define PRSTATUS_REGS_SIZE (17 * 4) + +#define ULONG uint32_t +#define PID_T int32_t +#define UID_T uint16_t +#define GID_T uint16_t +#define ALIGN_ULONG 4 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 2 +#define ALIGN_GID_T 2 +#define TYPE_ULONG ELF_T_WORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_HALF +#define TYPE_GID_T ELF_T_HALF + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "orig_eax", .type = ELF_T_SWORD, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + (4 * 11), \ + .group = "register" \ + } + +static const Ebl_Register_Location fpregset_regs[] = { - char pr_state; /* Numeric process state. */ - char pr_sname; /* Char for pr_state. */ - char pr_zomb; /* Zombie. */ - char pr_nice; /* Nice val. */ - uint32_t pr_flag; /* Flags. */ - uint16_t pr_uid; - uint16_t pr_gid; - int32_t pr_pid; - int32_t pr_ppid; - int32_t pr_pgrp; - int32_t pr_sid; - /* Lots missing */ - char pr_fname[16]; /* Filename of executable. */ - char pr_psargs[80]; /* Initial part of arg list. */ + { .offset = 0, .regno = 37, .count = 2, .bits = 32 }, /* fctrl-fstat */ + { .offset = 7 * 4, .regno = 11, .count = 8, .bits = 80 }, /* stN */ }; +#define FPREGSET_SIZE 108 +static const Ebl_Register_Location prxfpreg_regs[] = + { + { .offset = 0, .regno = 37, .count = 2, .bits = 16 }, /* fctrl-fstat */ + { .offset = 24, .regno = 39, .count = 1, .bits = 32 }, /* mxcsr */ + { .offset = 32, .regno = 11, .count = 8, .bits = 80, .pad = 6 }, /* stN */ + { .offset = 32 + 128, .regno = 21, .count = 8, .bits = 128 }, /* xmm */ + }; +#define PRXFPREG_SIZE 512 -bool -i386_core_note (name, type, descsz, desc) - const char *name __attribute__ ((unused)); - uint32_t type; - uint32_t descsz; - const char *desc; -{ - bool result = false; - - switch (type) - { - case NT_PRSTATUS: - if (descsz < sizeof (struct elf_prstatus)) - /* Not enough data. */ - break; - - struct elf_prstatus *stat = (struct elf_prstatus *) desc; - - printf (" SIGINFO: signo: %" PRId32 ", code = %" PRId32 - ", errno = %" PRId32 "\n" - " signal: %" PRId16 ", pending: %08" PRIx32 - ", holding: %8" PRIx32 "\n" - " pid: %" PRId32 ", ppid = %" PRId32 ", pgrp = %" PRId32 - ", sid = %" PRId32 "\n" - " utime: %6" PRId32 ".%06" PRId32 - "s, stime: %6" PRId32 ".%06" PRId32 "s\n" - " cutime: %6" PRId32 ".%06" PRId32 - "s, cstime: %6" PRId32 ".%06" PRId32 "s\n" - " eax: %08" PRIx32 " ebx: %08" PRIx32 " ecx: %08" PRIx32 - " edx: %08" PRIx32 "\n" - " esi: %08" PRIx32 " edi: %08" PRIx32 " ebp: %08" PRIx32 - " esp: %08" PRIx32 "\n" - " eip: %08" PRIx32 " eflags: %08" PRIx32 - " original eax: %08" PRIx32 "\n" - " cs: %04" PRIx32 " ds: %04" PRIx32 " es: %04" PRIx32 - " fs: %04" PRIx32 " gs: %04" PRIx32 " ss: %04" PRIx32 "\n\n", - stat->pr_info.si_signo, - stat->pr_info.si_code, - stat->pr_info.si_errno, - stat->pr_cursig, - stat->pr_sigpend, stat->pr_sighold, - stat->pr_pid, stat->pr_ppid, stat->pr_pgrp, stat->pr_sid, - stat->pr_utime.tv_sec, stat->pr_utime.tv_usec, - stat->pr_stime.tv_sec, stat->pr_stime.tv_usec, - stat->pr_cutime.tv_sec, stat->pr_cutime.tv_usec, - stat->pr_cstime.tv_sec, stat->pr_cstime.tv_usec, - stat->pr_reg[6], stat->pr_reg[0], stat->pr_reg[1], - stat->pr_reg[2], stat->pr_reg[3], stat->pr_reg[4], - stat->pr_reg[5], stat->pr_reg[15], stat->pr_reg[12], - stat->pr_reg[14], stat->pr_reg[11], stat->pr_reg[13] & 0xffff, - stat->pr_reg[7] & 0xffff, stat->pr_reg[8] & 0xffff, - stat->pr_reg[9] & 0xffff, stat->pr_reg[10] & 0xffff, - stat->pr_reg[16]); - - /* We handled this entry. */ - result = true; - break; - - case NT_PRPSINFO: - if (descsz < sizeof (struct elf_prpsinfo)) - /* Not enough data. */ - break; - - struct elf_prpsinfo *info = (struct elf_prpsinfo *) desc; - - printf (" state: %c (%hhd), zombie: %hhd, nice: %hhd\n" - " flags: %08" PRIx32 ", uid: %" PRId16 ", gid: %" PRId16"\n" - " pid: %" PRId32 ", ppid: %" PRId32 ", pgrp: %" PRId32 - ", sid: %" PRId32 "\n" - " fname: %.16s\n" - " args: %.80s\n\n", - info->pr_sname, info->pr_state, info->pr_zomb, info->pr_nice, - info->pr_flag, info->pr_uid, info->pr_gid, - info->pr_pid, info->pr_ppid, info->pr_pgrp, info->pr_sid, - info->pr_fname, info->pr_psargs); - - /* We handled this entry. */ - result = true; - break; - - default: - break; - } - - return result; -} +#include "linux-core-note.c" diff --git a/backends/i386_init.c b/backends/i386_init.c index 9f240075f..f25e1eb99 100644 --- a/backends/i386_init.c +++ b/backends/i386_init.c @@ -1,5 +1,5 @@ /* Initialization of i386 specific backend library. - Copyright (C) 2000, 2001, 2002, 2005, 2006 Red Hat, Inc. + Copyright (C) 2000, 2001, 2002, 2005, 2006, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2000. @@ -56,6 +56,7 @@ i386_init (elf, machine, eh, ehlen) HOOK (eh, debugscn_p); HOOK (eh, return_value_location); HOOK (eh, register_info); + HOOK (eh, auxv_info); return MODVERSION; } diff --git a/backends/linux-core-note.c b/backends/linux-core-note.c new file mode 100644 index 000000000..0913cc97b --- /dev/null +++ b/backends/linux-core-note.c @@ -0,0 +1,218 @@ +/* Common core note type descriptions for Linux. + Copyright (C) 2007 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils 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; version 2 of the License. + + Red Hat elfutils 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 Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +/* The including CPU_corenote.c file provides prstatus_regs and + defines macros ULONG, [PUG]ID_T, and ALIGN_*, TYPE_*. + + Here we describe the common layout used in . */ + +#define CHAR int8_t +#define ALIGN_CHAR 1 +#define TYPE_CHAR ELF_T_BYTE +#define SHORT uint16_t +#define ALIGN_SHORT 2 +#define TYPE_SHORT ELF_T_HALF +#define INT int32_t +#define ALIGN_INT 4 +#define TYPE_INT ELF_T_SWORD + +#define FIELD(type, name) type name __attribute__ ((aligned (ALIGN_##type))) + +struct EBLHOOK(siginfo) +{ + FIELD (INT, si_signo); + FIELD (INT, si_code); + FIELD (INT, si_errno); +}; + +struct EBLHOOK(timeval) +{ + FIELD (ULONG, tv_sec); + FIELD (ULONG, tv_usec); +}; + +struct EBLHOOK(prstatus) +{ + struct EBLHOOK(siginfo) pr_info; + FIELD (SHORT, pr_cursig); + FIELD (ULONG, pr_sigpend); + FIELD (ULONG, pr_sighold); + FIELD (PID_T, pr_pid); + FIELD (PID_T, pr_ppid); + FIELD (PID_T, pr_pgrp); + FIELD (PID_T, pr_sid); + struct EBLHOOK(timeval) pr_utime; + struct EBLHOOK(timeval) pr_stime; + struct EBLHOOK(timeval) pr_cutime; + struct EBLHOOK(timeval) pr_cstime; + FIELD (ULONG, pr_reg[PRSTATUS_REGS_SIZE / sizeof (ULONG)]); + FIELD (INT, pr_fpvalid); +}; + +#define FNAMESZ 16 +#define PRARGSZ 80 + +struct EBLHOOK(prpsinfo) +{ + FIELD (CHAR, pr_state); + FIELD (CHAR, pr_sname); + FIELD (CHAR, pr_zomb); + FIELD (CHAR, pr_nice); + FIELD (ULONG, pr_flag); + FIELD (UID_T, pr_uid); + FIELD (GID_T, pr_gid); + FIELD (PID_T, pr_pid); + FIELD (PID_T, pr_ppid); + FIELD (PID_T, pr_pgrp); + FIELD (PID_T, pr_sid); + FIELD (CHAR, pr_fname[FNAMESZ]); + FIELD (CHAR, pr_psargs[PRARGSZ]); +}; + +#undef FIELD + +#define FIELD(igroup, itype, item, fmt, ...) \ + { \ + .name = #item, \ + .group = #igroup, \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_##item), \ + .type = TYPE_##itype, \ + .format = fmt, \ + __VA_ARGS__ \ + } + +static const Ebl_Core_Item prstatus_items[] = + { + FIELD (signal, INT, info.si_signo, 'd'), + FIELD (signal, INT, info.si_code, 'd'), + FIELD (signal, INT, info.si_errno, 'd'), + FIELD (signal, SHORT, cursig, 'd'), + FIELD (signal, ULONG, sigpend, 'b'), + FIELD (signal, ULONG, sighold, 'b'), + FIELD (identity, PID_T, pid, 'd', .thread_identifier = true), + FIELD (identity, PID_T, ppid, 'd'), + FIELD (identity, PID_T, pgrp, 'd'), + FIELD (identity, PID_T, sid, 'd'), + FIELD (time, ULONG, utime, 'T', .count = 2), + FIELD (time, ULONG, stime, 'T', .count = 2), + FIELD (time, ULONG, cutime, 'T', .count = 2), + FIELD (time, ULONG, cstime, 'T', .count = 2), +#ifdef PRSTATUS_REGSET_ITEMS + PRSTATUS_REGSET_ITEMS, +#endif + FIELD (register, INT, fpvalid, 'd'), + }; + +#undef FIELD + +#define FIELD(igroup, itype, item, fmt, ...) \ + { \ + .name = #item, \ + .group = #igroup, \ + .offset = offsetof (struct EBLHOOK(prpsinfo), pr_##item), \ + .type = TYPE_##itype, \ + .format = fmt, \ + __VA_ARGS__ \ + } + +static const Ebl_Core_Item prpsinfo_items[] = + { + FIELD (state, CHAR, state, 'd'), + FIELD (state, CHAR, sname, 'c'), + FIELD (state, CHAR, zomb, 'd'), + FIELD (state, CHAR, nice, 'd'), + FIELD (state, ULONG, flag, 'x'), + FIELD (identity, UID_T, uid, 'd'), + FIELD (identity, GID_T, gid, 'd'), + FIELD (identity, PID_T, pid, 'd'), + FIELD (identity, PID_T, ppid, 'd'), + FIELD (identity, PID_T, pgrp, 'd'), + FIELD (identity, PID_T, sid, 'd'), + FIELD (command, CHAR, fname, 's', .count = FNAMESZ), + FIELD (command, CHAR, psargs, 's', .count = PRARGSZ), + }; + +#undef FIELD + +int +EBLHOOK(core_note) (n_type, descsz, + regs_offset, nregloc, reglocs, nitems, items) + GElf_Word n_type; + GElf_Word descsz; + GElf_Word *regs_offset; + size_t *nregloc; + const Ebl_Register_Location **reglocs; + size_t *nitems; + const Ebl_Core_Item **items; +{ + switch (n_type) + { + case NT_PRSTATUS: + if (descsz != sizeof (struct EBLHOOK(prstatus))) + return 0; + *regs_offset = offsetof (struct EBLHOOK(prstatus), pr_reg); + *nregloc = sizeof prstatus_regs / sizeof prstatus_regs[0]; + *reglocs = prstatus_regs; + *nitems = sizeof prstatus_items / sizeof prstatus_items[0]; + *items = prstatus_items; + return 1; + + case NT_PRPSINFO: + if (descsz != sizeof (struct EBLHOOK(prpsinfo))) + return 0; + *regs_offset = 0; + *nregloc = 0; + *reglocs = NULL; + *nitems = sizeof prpsinfo_items / sizeof prpsinfo_items[0]; + *items = prpsinfo_items; + return 1; + +#ifdef FPREGSET_SIZE + case NT_FPREGSET: + if (descsz != FPREGSET_SIZE) + return 0; + *regs_offset = 0; + *nregloc = sizeof fpregset_regs / sizeof fpregset_regs[0]; + *reglocs = fpregset_regs; + *nitems = 0; + *items = NULL; + return 1; +#endif + +#ifdef PRXFPREG_SIZE + case NT_PRXFPREG: + if (descsz != PRXFPREG_SIZE) + return 0; + *regs_offset = 0; + *nregloc = sizeof prxfpreg_regs / sizeof prxfpreg_regs[0]; + *reglocs = prxfpreg_regs; + *nitems = 0; + *items = NULL; + return 1; +#endif + } + + return 0; +} diff --git a/backends/ppc64_corenote.c b/backends/ppc64_corenote.c new file mode 100644 index 000000000..9d6a6a447 --- /dev/null +++ b/backends/ppc64_corenote.c @@ -0,0 +1,2 @@ +#define BITS 64 +#include "ppc_corenote.c" diff --git a/backends/ppc64_init.c b/backends/ppc64_init.c index 8cd75357d..02a592fd9 100644 --- a/backends/ppc64_init.c +++ b/backends/ppc64_init.c @@ -1,5 +1,5 @@ /* Initialization of PPC64 specific backend library. - Copyright (C) 2004, 2005, 2006 Red Hat, Inc. + Copyright (C) 2004, 2005, 2006, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2004. @@ -58,6 +58,8 @@ ppc64_init (elf, machine, eh, ehlen) HOOK (eh, bss_plt_p); HOOK (eh, return_value_location); HOOK (eh, register_info); + HOOK (eh, core_note); + HOOK (eh, auxv_info); return MODVERSION; } diff --git a/backends/ppc_auxv.c b/backends/ppc_auxv.c new file mode 100644 index 000000000..1c0a5cfcf --- /dev/null +++ b/backends/ppc_auxv.c @@ -0,0 +1,52 @@ +/* i386 specific auxv handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils 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; version 2 of the License. + + Red Hat elfutils 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 Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +int +EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format) +{ + if (a_type != AT_HWCAP) + return 0; + + *name = "HWCAP"; + *format = "b" + "ppcle\0" "truele\0" "3\0" "4\0" "5\0" "6\0" "7\0" "8\0" "9\0" + "power6x\0" "dfp\0" "pa6t\0" "arch_2_05\0" + "ic_snoop\0" "smt\0" "booke\0" "cellbe\0" + "power5+\0" "power5\0" "power4\0" "notb\0" + "efpdouble\0" "efpsingle\0" "spe\0" "ucache\0" + "4xxmac\0" "mmu\0" "fpu\0" "altivec\0" + "ppc601\0" "ppc64\0" "ppc32\0" "\0"; + return 1; +} + +__typeof (ppc_auxv_info) ppc64_auxv_info + __attribute__ ((alias ("ppc_auxv_info"))); diff --git a/backends/ppc_corenote.c b/backends/ppc_corenote.c new file mode 100644 index 000000000..e9ff124c1 --- /dev/null +++ b/backends/ppc_corenote.c @@ -0,0 +1,102 @@ +/* PowerPC specific core note handling. + Copyright (C) 2007 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils 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; version 2 of the License. + + Red Hat elfutils 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 Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifndef BITS +# define BITS 32 +# define BACKEND ppc_ +#else +# define BITS 64 +# define BACKEND ppc64_ +#endif +#include "libebl_CPU.h" + +static const Ebl_Register_Location prstatus_regs[] = + { +#define GR(at, n, dwreg) \ + { .offset = at * BITS/8, .regno = dwreg, .count = n, .bits = BITS } + + GR (0, 32, 0), /* r0-r31 */ + /* 32, 1, nip */ + GR (33, 1, 66), /* msr */ + /* 34, 1, orig_gpr3 */ + GR (35, 1, 109), /* ctr */ + GR (36, 1, 108), /* lr */ + GR (37, 1, 101), /* xer */ + GR (38, 1, 64), /* cr */ + GR (39, 1, 100), /* mq */ + /* 40, 1, trap */ + GR (41, 1, 119), /* dar */ + GR (42, 1, 118), /* dsisr */ + +#undef GR + }; +#define PRSTATUS_REGS_SIZE (BITS / 8 * 48) + +static const Ebl_Register_Location fpregset_regs[] = + { + { .offset = 0, .regno = 32, .count = 32, .bits = 64 }, /* f0-f31 */ + { .offset = 32 * 8 + 4, .regno = 65, .count = 1, .bits = 32 } /* fpscr */ + }; +#define FPREGSET_SIZE (33 * 8) + +#if BITS == 32 +# define ULONG uint32_t +# define ALIGN_ULONG 4 +# define TYPE_ULONG ELF_T_WORD +# define TYPE_LONG ELF_T_SWORD +#else +# define ULONG uint64_t +# define ALIGN_ULONG 8 +# define TYPE_ULONG ELF_T_XWORD +# define TYPE_LONG ELF_T_SXWORD +#endif +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_WORD +#define TYPE_GID_T ELF_T_WORD + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "orig_gpr3", .type = TYPE_LONG, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + (4 * 34), \ + .group = "register" \ + } + +#include "linux-core-note.c" diff --git a/backends/ppc_init.c b/backends/ppc_init.c index 1dfd5ec9b..7edc8fadd 100644 --- a/backends/ppc_init.c +++ b/backends/ppc_init.c @@ -1,5 +1,5 @@ /* Initialization of PPC specific backend library. - Copyright (C) 2004, 2005, 2006 Red Hat, Inc. + Copyright (C) 2004, 2005, 2006, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2004. @@ -57,6 +57,8 @@ ppc_init (elf, machine, eh, ehlen) HOOK (eh, bss_plt_p); HOOK (eh, return_value_location); HOOK (eh, register_info); + HOOK (eh, core_note); + HOOK (eh, auxv_info); return MODVERSION; } diff --git a/backends/ppc_symbol.c b/backends/ppc_symbol.c index 8a1950c01..9540a3e9c 100644 --- a/backends/ppc_symbol.c +++ b/backends/ppc_symbol.c @@ -1,5 +1,5 @@ /* PPC specific symbolic name handling. - Copyright (C) 2004, 2005 Red Hat, Inc. + Copyright (C) 2004, 2005, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2004. @@ -122,10 +122,13 @@ ppc_check_special_symbol (Elf *elf, GElf_Ehdr *ehdr, const GElf_Sym *sym, if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) { + /* In -msecure-plt mode, DT_PPC_GOT is present and must match. */ GElf_Addr gotaddr; if (find_dyn_got (elf, ehdr, &gotaddr)) return sym->st_value == gotaddr; - return sym->st_value == destshdr->sh_addr + 4; + + /* In -mbss-plt mode, any place in the section is valid. */ + return true; } const char *sname = elf_strptr (elf, ehdr->e_shstrndx, destshdr->sh_name); diff --git a/backends/x86_64_corenote.c b/backends/x86_64_corenote.c index 1a37c07b0..c2bc72e9c 100644 --- a/backends/x86_64_corenote.c +++ b/backends/x86_64_corenote.c @@ -1,7 +1,6 @@ /* x86-64 specific core note handling. - Copyright (C) 2005 Red Hat, Inc. + Copyright (C) 2005, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. - Written by Ulrich Drepper , 2005. Red Hat elfutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -38,147 +37,70 @@ #include "libebl_CPU.h" -/* We cannot include since the definition would be for - the host platform and not always x86-64 as required here. */ -struct elf_prstatus +static const Ebl_Register_Location prstatus_regs[] = { - struct - { - int32_t si_signo; /* Signal number. */ - int32_t si_code; /* Extra code. */ - int32_t si_errno; /* Errno. */ - } pr_info; /* Info associated with signal. */ - int16_t pr_cursig; /* Current signal. */ - uint64_t pr_sigpend; /* Set of pending signals. */ - uint64_t pr_sighold; /* Set of held signals. */ - int32_t pr_pid; - int32_t pr_ppid; - int32_t pr_pgrp; - int32_t pr_sid; - struct x86_64_timeval - { - int64_t tv_sec; - int32_t tv_usec; - } pr_utime; /* User time. */ - struct x86_64_timeval pr_stime; /* System time. */ - struct x86_64_timeval pr_cutime; /* Cumulative user time. */ - struct x86_64_timeval pr_cstime; /* Cumulative system time. */ - uint64_t pr_reg[27]; /* GP registers. */ - int32_t pr_fpvalid; /* True if math copro being used. */ +#define GR(at, n, dwreg) \ + { .offset = at * 8, .regno = dwreg, .count = n, .bits = 64 } +#define SR(at, n, dwreg) \ + { .offset = at * 8, .regno = dwreg, .count = n, .bits = 16, .pad = 6 } + + GR (0, 1, 15), /* %r15 */ + GR (1, 1, 14), /* %r14 */ + GR (2, 1, 13), /* %r13 */ + GR (3, 1, 12), /* %r12 */ + GR (4, 1, 6), /* %rbp */ + GR (5, 1, 3), /* %rbx */ + GR (6, 1, 11), /* %r11 */ + GR (7, 1, 10), /* %r10 */ + GR (8, 1, 9), /* %r9 */ + GR (9, 1, 8), /* %r8 */ + GR (10,1, 0), /* %rax */ + GR (11,1, 2), /* %rcx */ + GR (12,1, 1), /* %rdx */ + GR (13,2, 4), /* %rsi-%rdi */ + /* 15,1, orig_rax */ + GR (16,1, 16), /* %rip */ + SR (17,1, 51), /* %cs */ + GR (18,1, 49), /* %rFLAGS */ + GR (19,1, 7), /* %rsp */ + SR (20,1, 52), /* %ss */ + GR (21,2, 58), /* %fs.base-%gs.base */ + SR (23,1, 53), /* %ds */ + SR (24,1, 50), /* %es */ + SR (25,2, 54), /* %fs-%gs */ + +#undef GR +#undef SR }; - - -struct elf_prpsinfo +#define PRSTATUS_REGS_SIZE (27 * 8) + +#define ULONG uint64_t +#define PID_T int32_t +#define UID_T uint32_t +#define GID_T uint32_t +#define ALIGN_ULONG 8 +#define ALIGN_PID_T 4 +#define ALIGN_UID_T 4 +#define ALIGN_GID_T 4 +#define TYPE_ULONG ELF_T_XWORD +#define TYPE_PID_T ELF_T_SWORD +#define TYPE_UID_T ELF_T_SWORD +#define TYPE_GID_T ELF_T_SWORD + +#define PRSTATUS_REGSET_ITEMS \ + { \ + .name = "orig_rax", .type = ELF_T_SXWORD, .format = 'd', \ + .offset = offsetof (struct EBLHOOK(prstatus), pr_reg) + (8 * 15), \ + .group = "register" \ + } + +static const Ebl_Register_Location fpregset_regs[] = { - char pr_state; /* Numeric process state. */ - char pr_sname; /* Char for pr_state. */ - char pr_zomb; /* Zombie. */ - char pr_nice; /* Nice val. */ - uint64_t pr_flag; /* Flags. */ - uint32_t pr_uid; - uint32_t pr_gid; - int32_t pr_pid; - int32_t pr_ppid; - int32_t pr_pgrp; - int32_t pr_sid; - /* Lots missing */ - char pr_fname[16]; /* Filename of executable. */ - char pr_psargs[80]; /* Initial part of arg list. */ + { .offset = 0, .regno = 65, .count = 2, .bits = 16 }, /* fcw-fsw */ + { .offset = 24, .regno = 64, .count = 1, .bits = 32 }, /* mxcsr */ + { .offset = 32, .regno = 33, .count = 8, .bits = 80, .pad = 6 }, /* stN */ + { .offset = 32 + 128, .regno = 17, .count = 16, .bits = 128 }, /* xmm */ }; +#define FPREGSET_SIZE 512 - -bool -x86_64_core_note (name, type, descsz, desc) - const char *name __attribute__ ((unused)); - uint32_t type; - uint32_t descsz; - const char *desc; -{ - bool result = false; - - switch (type) - { - case NT_PRSTATUS: - if (descsz < sizeof (struct elf_prstatus)) - /* Not enough data. */ - break; - - struct elf_prstatus *stat = (struct elf_prstatus *) desc; - - printf (" SIGINFO: signo: %" PRId32 ", code = %" PRId32 - ", errno = %" PRId32 "\n" - " signal: %" PRId16 ", pending: %#08" PRIx64 ", holding: %#08" - PRIx64 "\n" - " pid: %" PRId32 ", ppid = %" PRId32 ", pgrp = %" PRId32 - ", sid = %" PRId32 "\n" - " utime: %6" PRId64 ".%06" PRId32 - "s, stime: %6" PRId64 ".%06" PRId32 "s\n" - " cutime: %6" PRId64 ".%06" PRId32 - "s, cstime: %6" PRId64 ".%06" PRId32 "s\n" - " rax: %016" PRIx64 " rbx: %016" PRIx64 "\n" - " rcx: %016" PRIx64 " rdx: %016" PRIx64 "\n" - " rsi: %016" PRIx64 " rdi: %016" PRIx64 "\n" - " rbp: %016" PRIx64 " rsp: %016" PRIx64 "\n" - " r8: %016" PRIx64 " r9: %016" PRIx64 "\n" - " r10: %016" PRIx64 " r11: %016" PRIx64 "\n" - " r12: %016" PRIx64 " r13: %016" PRIx64 "\n" - " r14: %016" PRIx64 " r15: %016" PRIx64 "\n" - " rip: %016" PRIx64 " eflags: %08" PRIx64 "\n" - " original rax: %016" PRIx64 "\n" - " cs: %04" PRIx64 " ds: %04" PRIx64 " es: %04" PRIx64 - " ss: %04" PRIx64 "\n" - " fs: %04" PRIx64 " fs_base: %016" PRIx64 - " gs: %04" PRIx64 " gs_base: %016" PRIx64 "\n\n", - stat->pr_info. si_signo, - stat->pr_info. si_code, - stat->pr_info. si_errno, - stat->pr_cursig, - stat->pr_sigpend, stat->pr_sighold, - stat->pr_pid, stat->pr_ppid, stat->pr_pgrp, stat->pr_sid, - stat->pr_utime.tv_sec, stat->pr_utime.tv_usec, - stat->pr_stime.tv_sec, stat->pr_stime.tv_usec, - stat->pr_cutime.tv_sec, stat->pr_cutime.tv_usec, - stat->pr_cstime.tv_sec, stat->pr_cstime.tv_usec, - stat->pr_reg[10], stat->pr_reg[5], stat->pr_reg[11], - stat->pr_reg[12], stat->pr_reg[13], stat->pr_reg[14], - stat->pr_reg[4], stat->pr_reg[10], stat->pr_reg[9], - stat->pr_reg[7], stat->pr_reg[6], stat->pr_reg[5], - stat->pr_reg[3], stat->pr_reg[2], stat->pr_reg[1], - stat->pr_reg[0], stat->pr_reg[16], stat->pr_reg[18], - stat->pr_reg[15], stat->pr_reg[17], stat->pr_reg[23], - stat->pr_reg[24], stat->pr_reg[20], - stat->pr_reg[25], stat->pr_reg[21], - stat->pr_reg[26], stat->pr_reg[22]); - - /* We handled this entry. */ - result = true; - break; - - case NT_PRPSINFO: - if (descsz < sizeof (struct elf_prpsinfo)) - /* Not enough data. */ - break; - - struct elf_prpsinfo *info = (struct elf_prpsinfo *) desc; - - printf (" state: %c (%hhd), zombie: %hhd, nice: %hhd\n" - " flags: %08" PRIx64 " uid: %" PRIu32 " gid: %" PRIu32 "\n" - " pid: %" PRId32 " ppid: %" PRId32 " pgrp: %" PRId32 - " sid: %" PRId32 "\n" - " fname: %.16s\n" - " args: %.80s\n\n", - info->pr_sname, info->pr_state, info->pr_zomb, info->pr_nice, - info->pr_flag, info->pr_uid, info->pr_gid, - info->pr_pid, info->pr_ppid, info->pr_pgrp, info->pr_sid, - info->pr_fname, info->pr_psargs); - - /* We handled this entry. */ - result = true; - break; - - default: - break; - } - - return result; -} +#include "linux-core-note.c" diff --git a/backends/x86_64_init.c b/backends/x86_64_init.c index 476f4ed27..b1764832e 100644 --- a/backends/x86_64_init.c +++ b/backends/x86_64_init.c @@ -1,5 +1,5 @@ /* Initialization of x86-64 specific backend library. - Copyright (C) 2002, 2005, 2006 Red Hat, Inc. + Copyright (C) 2002, 2005, 2006, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2002. @@ -35,8 +35,6 @@ /* This defines the common reloc hooks based on x86_64_reloc.def. */ #include "common-reloc.c" - - const char * x86_64_init (elf, machine, eh, ehlen) Elf *elf __attribute__ ((unused)); @@ -55,6 +53,7 @@ x86_64_init (elf, machine, eh, ehlen) HOOK (eh, core_note); HOOK (eh, return_value_location); HOOK (eh, register_info); + HOOK (eh, auxv_info); return MODVERSION; } diff --git a/backends/x86_64_regs.c b/backends/x86_64_regs.c index cfa405080..8eb0d33f5 100644 --- a/backends/x86_64_regs.c +++ b/backends/x86_64_regs.c @@ -156,6 +156,7 @@ x86_64_register_info (Ebl *ebl __attribute__ ((unused)), return stpcpy (&name[1], "s.base") + 1 - name; case 49: + *setname = "integer"; return stpcpy (name, "rflags") + 1 - name; case 62: return stpcpy (name, "tr") + 1 - name; diff --git a/libebl/ChangeLog b/libebl/ChangeLog index a48f8e333..c93e70474 100644 --- a/libebl/ChangeLog +++ b/libebl/ChangeLog @@ -1,3 +1,23 @@ +2007-08-22 Roland McGrath + + * libebl.h (Ebl_Core_Item): New member `group'. + +2007-08-19 Roland McGrath + + * ebl-hooks.h: Add new hook auxv_info. + * eblopenbackend.c (default_auxv_info): New function. + (fill_defaults): Initialize auxv_info hook. + * eblauxvinfo.c : New file. + * Makefile.am (gen_SOURCES): Add it. + * libebl.h: Declare ebl_auxv_info. + + * eblcorenote.c: Rewritten with new signature. + * Makefile.am (gen_SOURCES): Add it. + * libebl.h (Ebl_Register_Location, Ebl_Core_Item): New types. + (ebl_core_note_info): Completely revamp signature. + * ebl-hooks.h: Update decl. + * eblopenbackend.c (default_core_note): Update signature. + 2007-07-09 Roland McGrath * eblobjnotetypename.c (ebl_object_note_type_name): Handle diff --git a/libebl/Makefile.am b/libebl/Makefile.am index 741e5eee3..993800ca6 100644 --- a/libebl/Makefile.am +++ b/libebl/Makefile.am @@ -58,7 +58,7 @@ gen_SOURCES = eblopenbackend.c eblclosebackend.c eblstrtab.c \ eblelfclass.c eblelfdata.c eblelfmachine.c \ ebl_check_special_symbol.c eblbsspltp.c eblretval.c \ eblreginfo.c eblnonerelocp.c eblrelativerelocp.c \ - eblsysvhashentrysize.c + eblsysvhashentrysize.c eblauxvinfo.c libebl_a_SOURCES = $(gen_SOURCES) diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h index 5344df094..d466a1f3b 100644 --- a/libebl/ebl-hooks.h +++ b/libebl/ebl-hooks.h @@ -107,12 +107,17 @@ const char *EBLHOOK(core_note_type_name) (uint32_t, char *, size_t); /* Name of a note entry type for object files. */ const char *EBLHOOK(object_note_type_name) (uint32_t, char *, size_t); -/* Handle core note. */ -bool EBLHOOK(core_note) (const char *, uint32_t, uint32_t, const char *); +/* Describe core note format. */ +int EBLHOOK(core_note) (GElf_Word, GElf_Word, GElf_Word *, size_t *, + const Ebl_Register_Location **, + size_t *, const Ebl_Core_Item **); /* Handle object file note. */ bool EBLHOOK(object_note) (const char *, uint32_t, uint32_t, const char *); +/* Describe auxv element type. */ +int EBLHOOK(auxv_info) (GElf_Xword, const char **, const char **); + /* Check section name for being that of a debug informatino section. */ bool EBLHOOK(debugscn_p) (const char *); diff --git a/libebl/eblauxvinfo.c b/libebl/eblauxvinfo.c new file mode 100644 index 000000000..54583f9fb --- /dev/null +++ b/libebl/eblauxvinfo.c @@ -0,0 +1,121 @@ +/* Describe known auxv types. + Copyright (C) 2007 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils 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; version 2 of the License. + + Red Hat elfutils 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 Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define AUXV_TYPES \ + TYPE (NULL, "") \ + TYPE (IGNORE, "") \ + TYPE (EXECFD, "d") \ + TYPE (PHDR, "p") \ + TYPE (PHENT, "u") \ + TYPE (PHNUM, "u") \ + TYPE (PAGESZ, "u") \ + TYPE (BASE, "p") \ + TYPE (FLAGS, "x") \ + TYPE (ENTRY, "p") \ + TYPE (NOTELF, "") \ + TYPE (UID, "u") \ + TYPE (EUID, "u") \ + TYPE (GID, "u") \ + TYPE (EGID, "u") \ + TYPE (CLKTCK, "u") \ + TYPE (PLATFORM, "s") \ + TYPE (HWCAP, "x") \ + TYPE (FPUCW, "x") \ + TYPE (DCACHEBSIZE, "d") \ + TYPE (ICACHEBSIZE, "d") \ + TYPE (UCACHEBSIZE, "d") \ + TYPE (IGNOREPPC, "") \ + TYPE (SECURE, "u") \ + TYPE (SYSINFO, "p") \ + TYPE (SYSINFO_EHDR, "p") \ + TYPE (L1I_CACHESHAPE, "d") \ + TYPE (L1D_CACHESHAPE, "d") \ + TYPE (L2_CACHESHAPE, "d") \ + TYPE (L3_CACHESHAPE, "d") + +static const struct +{ + const char *name, *format; +} auxv_types[] = + { +#define TYPE(name, fmt) [AT_##name] = { #name, fmt }, + AUXV_TYPES +#undef TYPE + }; +#define nauxv_types (sizeof auxv_types / sizeof auxv_types[0]) + +int +ebl_auxv_info (ebl, a_type, name, format) + Ebl *ebl; + GElf_Xword a_type; + const char **name; + const char **format; +{ + int result = ebl->auxv_info (a_type, name, format); + if (result == 0 && a_type < nauxv_types) + { + /* The machine specific function did not know this type. */ + *name = auxv_types[a_type].name; + *format = auxv_types[a_type].format; + result = 1; + } + return result; +} diff --git a/libebl/eblcorenote.c b/libebl/eblcorenote.c index 9eb355f84..553d5ba93 100644 --- a/libebl/eblcorenote.c +++ b/libebl/eblcorenote.c @@ -1,7 +1,6 @@ -/* Print contents of core note. - Copyright (C) 2002, 2004, 2005, 2007 Red Hat, Inc. +/* Describe known core note formats. + Copyright (C) 2007 Red Hat, Inc. This file is part of Red Hat elfutils. - Written by Ulrich Drepper , 2002. Red Hat elfutils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -61,174 +60,48 @@ #include -void -ebl_core_note (ebl, name, type, descsz, desc) +int +ebl_core_note (ebl, n_type, descsz, + regs_offset, nregloc, reglocs, nitems, items) Ebl *ebl; - const char *name; - uint32_t type; - uint32_t descsz; - const char *desc; + GElf_Word n_type; + GElf_Word descsz; + GElf_Word *regs_offset; + size_t *nregloc; + const Ebl_Register_Location **reglocs; + size_t *nitems; + const Ebl_Core_Item **items; { - GElf_Ehdr ehdr_mem; - GElf_Ehdr *ehdr = gelf_getehdr (ebl->elf, &ehdr_mem); - assert (ehdr != NULL); - int class = ehdr->e_ident[EI_CLASS]; - int endian = ehdr->e_ident[EI_DATA]; - - if (! ebl->core_note (name, type, descsz, desc)) - /* The machine specific function did not know this type. */ - switch (type) - { - case NT_PLATFORM: - printf (gettext (" Platform: %.*s\n"), (int) descsz, desc); - break; - - case NT_AUXV: - ; - size_t elsize = (class == ELFCLASS32 - ? sizeof (Elf32_auxv_t) : sizeof (Elf64_auxv_t)); - - for (size_t cnt = 0; (cnt + 1) * elsize <= descsz; ++cnt) - { - uintmax_t atype; - uintmax_t val; - - if (class == ELFCLASS32) - { - Elf32_auxv_t *auxv = &((Elf32_auxv_t *) desc)[cnt]; - - if ((endian == ELFDATA2LSB && __BYTE_ORDER == __LITTLE_ENDIAN) - || (endian == ELFDATA2MSB && __BYTE_ORDER == __BIG_ENDIAN)) - { - atype = auxv->a_type; - val = auxv->a_un.a_val; - } - else - { - atype = bswap_32 (auxv->a_type); - val = bswap_32 (auxv->a_un.a_val); - } - } - else - { - Elf64_auxv_t *auxv = &((Elf64_auxv_t *) desc)[cnt]; - - if ((endian == ELFDATA2LSB && __BYTE_ORDER == __LITTLE_ENDIAN) - || (endian == ELFDATA2MSB && __BYTE_ORDER == __BIG_ENDIAN)) - { - atype = auxv->a_type; - val = auxv->a_un.a_val; - } - else - { - atype = bswap_64 (auxv->a_type); - val = bswap_64 (auxv->a_un.a_val); - } - } - - /* XXX Do we need the auxiliary vector info anywhere - else? If yes, move code into a separate function. */ - const char *at; - - switch (atype) + int result = ebl->core_note (n_type, descsz, regs_offset, nregloc, reglocs, + nitems, items); + if (result == 0) + { + /* The machine specific function did not know this type. */ + + *regs_offset = 0; + *nregloc = 0; + *reglocs = NULL; + switch (n_type) + { +#define ITEMS(type, table) \ + case type: \ + *items = table; \ + *nitems = sizeof table / sizeof table[0]; \ + result = 1; \ + break + + static const Ebl_Core_Item platform[] = + { { -#define NEW_AT(name) case AT_##name: at = #name; break - NEW_AT (NULL); - NEW_AT (IGNORE); - NEW_AT (EXECFD); - NEW_AT (PHDR); - NEW_AT (PHENT); - NEW_AT (PHNUM); - NEW_AT (PAGESZ); - NEW_AT (BASE); - NEW_AT (FLAGS); - NEW_AT (ENTRY); - NEW_AT (NOTELF); - NEW_AT (UID); - NEW_AT (EUID); - NEW_AT (GID); - NEW_AT (EGID); - NEW_AT (CLKTCK); - NEW_AT (PLATFORM); - NEW_AT (HWCAP); - NEW_AT (FPUCW); - NEW_AT (DCACHEBSIZE); - NEW_AT (ICACHEBSIZE); - NEW_AT (UCACHEBSIZE); - NEW_AT (IGNOREPPC); - NEW_AT (SECURE); - NEW_AT (SYSINFO); - NEW_AT (SYSINFO_EHDR); - NEW_AT (L1I_CACHESHAPE); - NEW_AT (L1D_CACHESHAPE); - NEW_AT (L2_CACHESHAPE); - NEW_AT (L3_CACHESHAPE); - - default:; - static char buf[30]; - sprintf (buf, "%ju (AT_?""?""?)", atype); - at = buf; - break; - } - - switch (atype) - { - /* Decimal. */ - case AT_EXECFD: - case AT_PHENT: - case AT_PHNUM: - case AT_PAGESZ: - case AT_UID: - case AT_EUID: - case AT_GID: - case AT_EGID: - case AT_CLKTCK: - case AT_FPUCW: - case AT_DCACHEBSIZE: - case AT_ICACHEBSIZE: - case AT_UCACHEBSIZE: - case AT_SECURE: - case AT_L1I_CACHESHAPE: - case AT_L1D_CACHESHAPE: - case AT_L2_CACHESHAPE: - case AT_L3_CACHESHAPE: - printf (" %s: %jd\n", at, val); - break; - - /* Normally zero. */ - case AT_NULL: - case AT_IGNORE: - case AT_IGNOREPPC: - case AT_NOTELF: - default: - if (val == 0) - { - printf (" %s\n", at); - break; - } - /* Fall through. */ - - /* Hex. */ - case AT_PHDR: - case AT_BASE: - case AT_FLAGS: /* XXX Print flags? */ - case AT_ENTRY: - case AT_PLATFORM: /* XXX Get string? */ - case AT_HWCAP: /* XXX Print flags? */ - case AT_SYSINFO: - case AT_SYSINFO_EHDR: - printf (" %s: %#jx\n", at, val); - break; + .name = "Platform", + .type = ELF_T_BYTE, .count = 0, .format = 's' } + }; + ITEMS (NT_PLATFORM, platform); - if (atype == AT_NULL) - /* Reached the end. */ - break; - } - break; +#undef ITEMS + } + } - default: - /* Unknown type. */ - break; - } + return result; } diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c index 5b1a7193a..63e64a10e 100644 --- a/libebl/eblopenbackend.c +++ b/libebl/eblopenbackend.c @@ -186,8 +186,12 @@ static const char *default_core_note_type_name (uint32_t, char *buf, size_t len); static const char *default_object_note_type_name (uint32_t, char *buf, size_t len); -static bool default_core_note (const char *name, uint32_t type, - uint32_t descsz, const char *desc); +static int default_core_note (GElf_Word n_type, GElf_Word descsz, + GElf_Word *regs_offset, size_t *nregloc, + const Ebl_Register_Location **reglocs, + size_t *nitems, const Ebl_Core_Item **); +static int default_auxv_info (GElf_Xword a_type, + const char **name, const char **format); static bool default_object_note (const char *name, uint32_t type, uint32_t descsz, const char *desc); static bool default_debugscn_p (const char *name); @@ -232,6 +236,7 @@ fill_defaults (Ebl *result) result->core_note_type_name = default_core_note_type_name; result->object_note_type_name = default_object_note_type_name; result->core_note = default_core_note; + result->auxv_info = default_auxv_info; result->object_note = default_object_note; result->debugscn_p = default_debugscn_p; result->copy_reloc_p = default_copy_reloc_p; @@ -567,6 +572,27 @@ default_core_note_type_name (uint32_t ignore __attribute__ ((unused)), return NULL; } +static int +default_auxv_info (GElf_Xword a_type __attribute__ ((unused)), + const char **name __attribute__ ((unused)), + const char **format __attribute__ ((unused))) +{ + return 0; +} + +static int +default_core_note (GElf_Word n_type __attribute__ ((unused)), + GElf_Word descsz __attribute__ ((unused)), + GElf_Word *ro __attribute__ ((unused)), + size_t *nregloc __attribute__ ((unused)), + const Ebl_Register_Location **reglocs + __attribute__ ((unused)), + size_t *nitems __attribute__ ((unused)), + const Ebl_Core_Item **items __attribute__ ((unused))) +{ + return 0; +} + static const char * default_object_note_type_name (uint32_t ignore __attribute__ ((unused)), char *buf __attribute__ ((unused)), @@ -575,15 +601,6 @@ default_object_note_type_name (uint32_t ignore __attribute__ ((unused)), return NULL; } -static bool -default_core_note (const char *name __attribute__ ((unused)), - uint32_t type __attribute__ ((unused)), - uint32_t descsz __attribute__ ((unused)), - const char *desc __attribute__ ((unused))) -{ - return NULL; -} - static bool default_object_note (const char *name __attribute__ ((unused)), uint32_t type __attribute__ ((unused)), diff --git a/libebl/libebl.h b/libebl/libebl.h index 1465fb1aa..7e29168d2 100644 --- a/libebl/libebl.h +++ b/libebl/libebl.h @@ -178,10 +178,6 @@ extern const char *ebl_core_note_type_name (Ebl *ebl, uint32_t type, char *buf, extern const char *ebl_object_note_type_name (Ebl *ebl, uint32_t type, char *buf, size_t len); -/* Print information about core note if available. */ -extern void ebl_core_note (Ebl *ebl, const char *name, uint32_t type, - uint32_t descsz, const char *desc); - /* Print information about object note if available. */ extern void ebl_object_note (Ebl *ebl, const char *name, uint32_t type, uint32_t descsz, const char *desc); @@ -306,6 +302,43 @@ extern void ebl_gstrtabfinalize (struct Ebl_GStrtab *st, Elf_Data *data); /* Get offset in wide char string table for string associated with SE. */ extern size_t ebl_gstrtaboffset (struct Ebl_GStrent *se); + +/* Register map info. */ +typedef struct +{ + Dwarf_Half offset; /* Byte offset in register data block. */ + Dwarf_Half regno; /* DWARF register number. */ + uint8_t bits; /* Bits of data for one register. */ + uint8_t pad; /* Bytes of padding after register's data. */ + Dwarf_Half count; /* Consecutive register numbers here. */ +} Ebl_Register_Location; + +/* Non-register data items in core notes. */ +typedef struct +{ + const char *name; /* Printable identifier. */ + const char *group; /* Identifier for category of related items. */ + Dwarf_Half offset; /* Byte offset in note data. */ + Dwarf_Half count; + Elf_Type type; + char format; + bool thread_identifier; +} Ebl_Core_Item; + +/* Describe the format of a core file note with type field matching N_TYPE + and descriptor size matching DESCSZ. */ +extern int ebl_core_note (Ebl *ebl, GElf_Word n_type, GElf_Word descsz, + GElf_Word *regs_offset, size_t *nregloc, + const Ebl_Register_Location **reglocs, + size_t *nitems, const Ebl_Core_Item **items) + __nonnull_attribute__ (1, 4, 5, 6, 7, 8); + +/* Describe the auxv type number. */ +extern int ebl_auxv_info (Ebl *ebl, GElf_Xword a_type, + const char **name, const char **format) + __nonnull_attribute__ (1, 3, 4); + + #ifdef __cplusplus } #endif diff --git a/libelf/ChangeLog b/libelf/ChangeLog index a26728cdf..4962c30aa 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,19 @@ +2007-08-19 Roland McGrath + + * gelf_update_auxv.c: New file. + * gelf_getauxv.c: New file. + * Makefile.am (libelf_a_SOURCES): Add them. + * gelf.h: Declare gelf_getauxv, gelf_update_auxv. + * libelf.map (ELFUTILS_1.3): New set, inherits fom ELFUTILS_1.2. + Export gelf_getauxv, gelf_update_auxv. + + * libelf.h (Elf_Type): Add ELF_T_AUXV. + * abstract.h: Add auxv_t entries. + * exttypes.h: Likewise. + * gelf_xlate.h: Likewise. + * gelf_xlate.c (__elf_xfctstom): Add ELF_T_AUXV entries. + * gelf_fsize.c (__libelf_type_sizes): Likewise. + 2007-08-12 Roland McGrath * elf32_updatefile.c (compare_sections): Sort secondarily on sh_size, diff --git a/libelf/Makefile.am b/libelf/Makefile.am index b93f49c63..3e8322e94 100644 --- a/libelf/Makefile.am +++ b/libelf/Makefile.am @@ -83,6 +83,7 @@ libelf_a_SOURCES = elf_version.c elf_hash.c elf_error.c elf_fill.c \ gelf_getdyn.c gelf_update_dyn.c \ gelf_getmove.c gelf_update_move.c \ gelf_getsyminfo.c gelf_update_syminfo.c \ + gelf_getauxv.c gelf_update_auxv.c \ gelf_xlatetof.c gelf_xlatetom.c \ nlist.c \ gelf_getsymshndx.c gelf_update_symshndx.c \ diff --git a/libelf/abstract.h b/libelf/abstract.h index 3c6250d04..e359f96b7 100644 --- a/libelf/abstract.h +++ b/libelf/abstract.h @@ -1,5 +1,5 @@ /* Abstract description of component ELF types. - Copyright (C) 1998, 1999, 2000, 2002, 2004 Red Hat, Inc. + Copyright (C) 1998, 1999, 2000, 2002, 2004, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 1998. @@ -314,3 +314,20 @@ END (Bits, Ext##Lib) Lib (32, Ext) #define Lib64(Ext) \ Lib (64, Ext) + +#define auxv_t32(Ext) \ +START (32, auxv_t, Ext##auxv_t) \ + TYPE_NAME (ElfW2(32, Ext##Word), a_type) \ + TYPE_EXTRA (union {) \ + TYPE_EXTRA (ElfW2(32, Ext##Word) a_val;) \ + TYPE_XLATE (Elf32_cvt_Addr1 (&tdest->a_un.a_val, &tsrc->a_un.a_val);) \ + TYPE_EXTRA (} a_un;) \ +END (32, Ext##auxv_t) +#define auxv_t64(Ext) \ +START (64, auxv_t, Ext##auxv_t) \ + TYPE_NAME (ElfW2(64, Ext##Xword), a_type) \ + TYPE_EXTRA (union {) \ + TYPE_EXTRA (ElfW2(64, Ext##Xword) a_val;) \ + TYPE_XLATE (Elf64_cvt_Addr1 (&tdest->a_un.a_val, &tsrc->a_un.a_val);) \ + TYPE_EXTRA (} a_un;) \ +END (64, Ext##auxv_t) diff --git a/libelf/exttypes.h b/libelf/exttypes.h index 1dff8ce36..3bb90c3ad 100644 --- a/libelf/exttypes.h +++ b/libelf/exttypes.h @@ -1,5 +1,5 @@ /* External ELF types. - Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Copyright (C) 1998, 1999, 2000, 2002, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. Contributed by Ulrich Drepper , 1998. @@ -94,6 +94,7 @@ Verneed32 (Ext_); Vernaux32 (Ext_); Syminfo32 (Ext_); Move32 (Ext_); +auxv_t32 (Ext_); Ehdr64 (Ext_); Phdr64 (Ext_); @@ -109,6 +110,7 @@ Verneed64 (Ext_); Vernaux64 (Ext_); Syminfo64 (Ext_); Move64 (Ext_); +auxv_t64 (Ext_); #undef START #undef END diff --git a/libelf/gelf.h b/libelf/gelf.h index 2ef256ccb..b985c1c0c 100644 --- a/libelf/gelf.h +++ b/libelf/gelf.h @@ -1,5 +1,5 @@ /* This file defines generic ELF types, structures, and macros. - Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -327,6 +327,14 @@ extern int gelf_update_verdaux (Elf_Data *__data, int __offset, GElf_Verdaux *__src); +/* Get auxv entry at the given index. */ +extern GElf_auxv_t *gelf_getauxv (Elf_Data *__data, int __ndx, + GElf_auxv_t *__dst); + +/* Update auxv entry at the given index. */ +extern int gelf_update_auxv (Elf_Data *__data, int __ndx, GElf_auxv_t *__src); + + /* Retrieve uninterpreted chunk of the file contents. */ extern char *gelf_rawchunk (Elf *__elf, GElf_Off __offset, GElf_Word __size); diff --git a/libelf/gelf_fsize.c b/libelf/gelf_fsize.c index a8c368c38..98197e0f3 100644 --- a/libelf/gelf_fsize.c +++ b/libelf/gelf_fsize.c @@ -1,5 +1,5 @@ /* Return the size of an object file type. - Copyright (C) 1998, 1999, 2000, 2002 Red Hat, Inc. + Copyright (C) 1998, 1999, 2000, 2002, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 1998. @@ -86,7 +86,8 @@ const size_t __libelf_type_sizes[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] = [ELF_T_VNAUX] = sizeof (ElfW2(LIBELFBITS, Ext_Vernaux)), \ [ELF_T_NHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Nhdr)), \ [ELF_T_SYMINFO] = sizeof (ElfW2(LIBELFBITS, Ext_Syminfo)), \ - [ELF_T_MOVE] = sizeof (ElfW2(LIBELFBITS, Ext_Move)) + [ELF_T_MOVE] = sizeof (ElfW2(LIBELFBITS, Ext_Move)), \ + [ELF_T_AUXV] = sizeof (ElfW2(LIBELFBITS, Ext_auxv_t)) TYPE_SIZES (32) }, [ELFCLASS64 - 1] = { diff --git a/libelf/gelf_getauxv.c b/libelf/gelf_getauxv.c new file mode 100644 index 000000000..036bdccf7 --- /dev/null +++ b/libelf/gelf_getauxv.c @@ -0,0 +1,130 @@ +/* Get information from auxiliary vector at the given index. + Copyright (C) 2007 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils 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; version 2 of the License. + + Red Hat elfutils 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 Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libelfP.h" + + +GElf_auxv_t * +gelf_getauxv (data, ndx, dst) + Elf_Data *data; + int ndx; + GElf_auxv_t *dst; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + GElf_auxv_t *result = NULL; + Elf *elf; + + if (data_scn == NULL) + return NULL; + + if (unlikely (data_scn->d.d_type != ELF_T_AUXV)) + { + __libelf_seterrno (ELF_E_INVALID_HANDLE); + return NULL; + } + + elf = data_scn->s->elf; + + rwlock_rdlock (elf->lock); + + /* This is the one place where we have to take advantage of the fact + that an `Elf_Data' pointer is also a pointer to `Elf_Data_Scn'. + The interface is broken so that it requires this hack. */ + if (elf->class == ELFCLASS32) + { + Elf32_auxv_t *src; + + /* Here it gets a bit more complicated. The format of the vector + entries has to be converted. The user better have provided a + buffer where we can store the information. While copying the data + we convert the format. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_auxv_t) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + src = &((Elf32_auxv_t *) data_scn->d.d_buf)[ndx]; + + /* This might look like a simple copy operation but it's + not. There are zero- and sign-extensions going on. */ + dst->a_type = src->a_type; + dst->a_un.a_val = src->a_un.a_val; + } + else + { + /* If this is a 64 bit object it's easy. */ + assert (sizeof (GElf_auxv_t) == sizeof (Elf64_auxv_t)); + + /* The data is already in the correct form. Just make sure the + index is OK. */ + if (unlikely ((ndx + 1) * sizeof (GElf_auxv_t) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + *dst = ((GElf_auxv_t *) data_scn->d.d_buf)[ndx]; + } + + result = dst; + + out: + rwlock_unlock (elf->lock); + + return result; +} diff --git a/libelf/gelf_update_auxv.c b/libelf/gelf_update_auxv.c new file mode 100644 index 000000000..b294ead7f --- /dev/null +++ b/libelf/gelf_update_auxv.c @@ -0,0 +1,135 @@ +/* Update information in dynamic table at the given index. + Copyright (C) 2007 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils 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; version 2 of the License. + + Red Hat elfutils 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 Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include + +#include "libelfP.h" + + +int +gelf_update_auxv (data, ndx, src) + Elf_Data *data; + int ndx; + GElf_auxv_t *src; +{ + Elf_Data_Scn *data_scn = (Elf_Data_Scn *) data; + Elf_Scn *scn; + int result = 0; + + if (data == NULL) + return 0; + + if (unlikely (ndx < 0)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + return 0; + } + + if (unlikely (data_scn->d.d_type != ELF_T_AUXV)) + { + /* The type of the data better should match. */ + __libelf_seterrno (ELF_E_DATA_MISMATCH); + return 0; + } + + scn = data_scn->s; + rwlock_wrlock (scn->elf->lock); + + if (scn->elf->class == ELFCLASS32) + { + Elf32_auxv_t *auxv; + + /* There is the possibility that the values in the input are + too large. */ + if (unlikely (src->a_type > 0xffffffffll) + || unlikely (src->a_un.a_val > 0xffffffffull)) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + goto out; + } + + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf32_auxv_t) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + auxv = &((Elf32_auxv_t *) data_scn->d.d_buf)[ndx]; + + auxv->a_type = src->a_type; + auxv->a_un.a_val = src->a_un.a_val; + } + else + { + /* Check whether we have to resize the data buffer. */ + if (unlikely ((ndx + 1) * sizeof (Elf64_auxv_t) > data_scn->d.d_size)) + { + __libelf_seterrno (ELF_E_INVALID_INDEX); + goto out; + } + + ((Elf64_auxv_t *) data_scn->d.d_buf)[ndx] = *src; + } + + result = 1; + + /* Mark the section as modified. */ + scn->flags |= ELF_F_DIRTY; + + out: + rwlock_unlock (scn->elf->lock); + + return result; +} diff --git a/libelf/gelf_xlate.c b/libelf/gelf_xlate.c index f1bbdf3a7..080474fdc 100644 --- a/libelf/gelf_xlate.c +++ b/libelf/gelf_xlate.c @@ -1,5 +1,5 @@ /* Transformation functions for ELF data types. - Copyright (C) 1998, 1999, 2000, 2002, 2004, 2005, 2006 Red Hat, Inc. + Copyright (C) 1998,1999,2000,2002,2004,2005,2006,2007 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 1998. @@ -216,7 +216,8 @@ const xfct_t __elf_xfctstom[EV_NUM - 1][EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] [ELF_T_NHDR] = ElfW2(Bits, cvt_Nhdr), \ [ELF_T_SYMINFO] = ElfW2(Bits, cvt_Syminfo), \ [ELF_T_MOVE] = ElfW2(Bits, cvt_Move), \ - [ELF_T_LIB] = ElfW2(Bits, cvt_Lib) + [ELF_T_LIB] = ElfW2(Bits, cvt_Lib), \ + [ELF_T_AUXV] = ElfW2(Bits, cvt_auxv_t) define_xfcts (32), [ELF_T_GNUHASH] = Elf32_cvt_Word }, diff --git a/libelf/gelf_xlate.h b/libelf/gelf_xlate.h index eec47ee68..e7659f12a 100644 --- a/libelf/gelf_xlate.h +++ b/libelf/gelf_xlate.h @@ -1,5 +1,5 @@ /* Helper file for type conversion function generation. - Copyright (C) 1998, 1999, 2000, 2002, 2004 Red Hat, Inc. + Copyright (C) 1998, 1999, 2000, 2002, 2004, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. Contributed by Ulrich Drepper , 1998. @@ -70,6 +70,7 @@ TYPE (Dyn, LIBELFBITS) TYPE (Syminfo, LIBELFBITS) TYPE (Move, LIBELFBITS) TYPE (Lib, LIBELFBITS) +TYPE (auxv_t, LIBELFBITS) /* Prepare for the next round. */ diff --git a/libelf/libelf.h b/libelf/libelf.h index 2f58e4c4e..a5d744cf3 100644 --- a/libelf/libelf.h +++ b/libelf/libelf.h @@ -1,5 +1,5 @@ /* Interface for libelf. - Copyright (C) 1998, 1999, 2000, 2002, 2004, 2005, 2006 Red Hat, Inc. + Copyright (C) 1998, 1999, 2000, 2002, 2004, 2005, 2006, 2007 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -83,6 +83,7 @@ typedef enum ELF_T_MOVE, /* Elf32_Move, Elf64_Move, ... */ ELF_T_LIB, /* Elf32_Lib, Elf64_Lib, ... */ ELF_T_GNUHASH, /* GNU-style hash section. */ + ELF_T_AUXV, /* Elf32_auxv_t, Elf64_auxv_t, ... */ /* Keep this the last entry. */ ELF_T_NUM } Elf_Type; diff --git a/libelf/libelf.map b/libelf/libelf.map index 9549c3176..bc597c6fe 100644 --- a/libelf/libelf.map +++ b/libelf/libelf.map @@ -117,3 +117,9 @@ ELFUTILS_1.2 { global: elf_gnu_hash; } ELFUTILS_1.1.1; + +ELFUTILS_1.3 { + global: + gelf_getauxv; + gelf_update_auxv; +}; diff --git a/src/ChangeLog b/src/ChangeLog index 77c983810..2c51f472b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,49 @@ +2007-08-23 Roland McGrath + + * readelf.c (printf_with_wrap): Function removed. + (REGISTER_WRAP_COLUMN): New macro. + (handle_core_register): Use print_core_item instead. + (struct register_info): New type. + (compare_registers, compare_register_sets): New functions. + (register_bitpos, compare_sets_by_info): New functions. + (handle_core_registers): Use those to segregate and sort registers + for display. + + * readelf.c (ITEM_WRAP_COLUMN): New macro. + (print_core_item): New function. + (handle_core_item): Use it instead of printf_with_wrap. + (compare_core_items, compare_core_item_groups): New functions. + (handle_core_items): Use them. Sort by group and force line breaks + between groups. + + * readelf.c (handle_core_registers, handle_core_items): New functions, + broken out of ... + (handle_core_note): ... here. Call them. + +2007-08-22 Roland McGrath + + * unstrip.c (new_shstrtab): New function, broken out of ... + (copy_elided_sections): ... here. + +2007-08-20 Roland McGrath + + Avoid local function trampolines in nm binary. + * nm.c (sort_by_address): Move to a static function instead of local + inside show_symbols. + (sort_by_name_strtab): New static variable. + (sort_by_name): Use it. Move to a static function instead of local + inside show_symbols. + (show_symbols): Set sort_by_name_strtab. + +2007-08-19 Roland McGrath + + * readelf.c (handle_auxv_note): New function. + (handle_notes): Call it. + + * readelf.c (printf_with_wrap, convert): New functions. + (handle_core_item, (handle_core_register): New functions. + (handle_notes): Call those with details from ebl_core_note. + 2007-08-12 Roland McGrath * elflint.c (check_note): Accept type 0 with name "Linux". diff --git a/src/nm.c b/src/nm.c index d79b00582..48f08aca8 100644 --- a/src/nm.c +++ b/src/nm.c @@ -938,34 +938,39 @@ show_symbols_posix (Elf *elf, GElf_Word strndx, const char *prefix, /* Maximum size of memory we allocate on the stack. */ #define MAX_STACK_ALLOC 65536 -static void -show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, - GElf_Shdr *shdr, const char *prefix, const char *fname, - const char *fullname) +static int +sort_by_address (const void *p1, const void *p2) { - int sort_by_name (const void *p1, const void *p2) - { - GElf_SymX *s1 = (GElf_SymX *) p1; - GElf_SymX *s2 = (GElf_SymX *) p2; - int result; + GElf_SymX *s1 = (GElf_SymX *) p1; + GElf_SymX *s2 = (GElf_SymX *) p2; - result = strcmp (elf_strptr (ebl->elf, shdr->sh_link, s1->sym.st_name), - elf_strptr (ebl->elf, shdr->sh_link, s2->sym.st_name)); + int result = (s1->sym.st_value < s2->sym.st_value + ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1)); - return reverse_sort ? -result : result; - } + return reverse_sort ? -result : result; +} - int sort_by_address (const void *p1, const void *p2) - { - GElf_SymX *s1 = (GElf_SymX *) p1; - GElf_SymX *s2 = (GElf_SymX *) p2; +static Elf_Data *sort_by_name_strtab; + +static int +sort_by_name (const void *p1, const void *p2) +{ + GElf_SymX *s1 = (GElf_SymX *) p1; + GElf_SymX *s2 = (GElf_SymX *) p2; - int result = (s1->sym.st_value < s2->sym.st_value - ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1)); + const char *n1 = sort_by_name_strtab->d_buf + s1->sym.st_name; + const char *n2 = sort_by_name_strtab->d_buf + s2->sym.st_name; - return reverse_sort ? -result : result; - } + int result = strcmp (n1, n2); + + return reverse_sort ? -result : result; +} +static void +show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, + GElf_Shdr *shdr, const char *prefix, const char *fname, + const char *fullname) +{ /* Get the section header string table index. */ size_t shstrndx; if (elf_getshstrndx (ebl->elf, &shstrndx) < 0) @@ -1142,7 +1147,11 @@ show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, /* Sort the entries according to the users wishes. */ if (sort == sort_name) - qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name); + { + sort_by_name_strtab = elf_getdata (elf_getscn (ebl->elf, shdr->sh_link), + NULL); + qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name); + } else if (sort == sort_numeric) qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_address); diff --git a/src/readelf.c b/src/readelf.c index e8b0bb4a7..747309597 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -4949,6 +4950,621 @@ print_debug (Ebl *ebl, GElf_Ehdr *ehdr) } +#define ITEM_INDENT 4 +#define ITEM_WRAP_COLUMN 150 +#define REGISTER_WRAP_COLUMN 75 + +/* Print "NAME: FORMAT", wrapping when FORMAT_MAX chars of FORMAT would + make the line exceed ITEM_WRAP_COLUMN. Unpadded numbers look better + for the core items. But we do not want the line breaks to depend on + the particular values. */ +static unsigned int +__attribute__ ((format (printf, 7, 8))) +print_core_item (unsigned int colno, char sep, unsigned int wrap, + size_t name_width, const char *name, + size_t format_max, const char *format, ...) +{ + size_t len = strlen (name); + if (name_width < len) + name_width = len; + + size_t n = name_width + sizeof ": " - 1 + format_max; + + if (colno == 0) + { + printf ("%*s", ITEM_INDENT, ""); + colno = ITEM_INDENT + n; + } + else if (colno + 2 + n < wrap) + { + printf ("%c ", sep); + colno += 2 + n; + } + else + { + printf ("\n%*s", ITEM_INDENT, ""); + colno = ITEM_INDENT + n; + } + + printf ("%s: %*s", name, (int) (name_width - len), ""); + + va_list ap; + va_start (ap, format); + vprintf (format, ap); + va_end (ap); + + return colno; +} + +static const void * +convert (Elf *core, Elf_Type type, uint_fast16_t count, + void *value, const void *data) +{ + Elf_Data valuedata = + { + .d_type = type, + .d_buf = value, + .d_size = gelf_fsize (core, type, count, EV_CURRENT), + .d_version = EV_CURRENT, + }; + Elf_Data indata = + { + .d_type = type, + .d_buf = (void *) data, + .d_size = valuedata.d_size, + .d_version = EV_CURRENT, + }; + + Elf_Data *d = (gelf_getclass (core) == ELFCLASS32 + ? elf32_xlatetom : elf64_xlatetom) + (&valuedata, &indata, elf_getident (core, NULL)[EI_DATA]); + if (d == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot convert core note data: %s"), elf_errmsg (-1)); + + return data + indata.d_size; +} + +typedef uint8_t GElf_Byte; + +static unsigned int +handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc, + unsigned int colno) +{ + uint_fast16_t count = item->count ?: 1; + +#define TYPES \ + DO_TYPE (BYTE, Byte, "0x%.2" PRIx8, "%" PRId8, 4); \ + DO_TYPE (HALF, Half, "0x%.4" PRIx16, "%" PRId16, 6); \ + DO_TYPE (WORD, Word, "0x%.8" PRIx32, "%" PRId32, 11); \ + DO_TYPE (SWORD, Sword, "%" PRId32, "%" PRId32, 11); \ + DO_TYPE (XWORD, Xword, "0x%.16" PRIx64, "%" PRId64, 20); \ + DO_TYPE (SXWORD, Sxword, "%" PRId64, "%" PRId64, 20) + +#define DO_TYPE(NAME, Name, hex, dec, max) GElf_##Name Name[count] + union { TYPES; } value; +#undef DO_TYPE + + desc = convert (core, item->type, count, &value, desc + item->offset); + + switch (item->format) + { + case 'd': + assert (count == 1); + switch (item->type) + { +#define DO_TYPE(NAME, Name, hex, dec, max) \ + case ELF_T_##NAME: \ + colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, \ + 0, item->name, max, dec, value.Name[0]); \ + break + TYPES; +#undef DO_TYPE + default: + abort (); + } + break; + + case 'x': + assert (count == 1); + switch (item->type) + { +#define DO_TYPE(NAME, Name, hex, dec, max) \ + case ELF_T_##NAME: \ + colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, \ + 0, item->name, max, hex, value.Name[0]); \ + break + TYPES; +#undef DO_TYPE + default: + abort (); + } + break; + + case 'b': + assert (count == 1); + Dwarf_Word bits = 0; + Dwarf_Word bit = 0; + switch (item->type) + { +#define DO_TYPE(NAME, Name, hex, dec, max) \ + case ELF_T_##NAME: \ + bits = value.Name[0]; \ + bit = (Dwarf_Word) 1 << ((sizeof value.Name[0] * 8) - 1); \ + break + TYPES; +#undef DO_TYPE + default: + abort (); + } + char printed[sizeof (Dwarf_Word) * 8 + 1]; + int i = 0; + while (bit != 0) + { + printed[i++] = (bits & bit) ? '1' : '0'; + bit >>= 1; + } + colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name, + sizeof printed - 1, "%.*s", i, printed); + break; + + case 'T': + assert (count == 2); + Dwarf_Word sec; + Dwarf_Word usec; + size_t maxfmt = 7; + switch (item->type) + { +#define DO_TYPE(NAME, Name, hex, dec, max) \ + case ELF_T_##NAME: \ + sec = value.Name[0]; \ + usec = value.Name[1]; \ + maxfmt += max; \ + break + TYPES; +#undef DO_TYPE + default: + abort (); + } + colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name, + maxfmt, "%" PRIu64 ".%.6" PRIu64, sec, usec); + break; + + case 'c': + assert (count == 1); + colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name, + 1, "%c", value.Byte[0]); + break; + + case 's': + colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name, + count, "%.*s", (int) count, value.Byte); + break; + + default: + error (0, 0, "XXX not handling format '%c' for %s", + item->format, item->name); + break; + } + +#undef TYPES + + return colno; +} + + +/* Sort items by group, and by layout offset within each group. */ +static int +compare_core_items (const void *a, const void *b) +{ + const Ebl_Core_Item *const *p1 = a; + const Ebl_Core_Item *const *p2 = b; + const Ebl_Core_Item *item1 = *p1; + const Ebl_Core_Item *item2 = *p2; + + return ((item1->group == item2->group ? 0 + : strcmp (item1->group, item2->group)) + ?: (int) item1->offset - (int) item2->offset); +} + +/* Sort item groups by layout offset of the first item in the group. */ +static int +compare_core_item_groups (const void *a, const void *b) +{ + const Ebl_Core_Item *const *const *p1 = a; + const Ebl_Core_Item *const *const *p2 = b; + const Ebl_Core_Item *const *group1 = *p1; + const Ebl_Core_Item *const *group2 = *p2; + const Ebl_Core_Item *item1 = *group1; + const Ebl_Core_Item *item2 = *group2; + + return (int) item1->offset - (int) item2->offset; +} + +static unsigned int +handle_core_items (Elf *core, const void *desc, + const Ebl_Core_Item *items, size_t nitems) +{ + if (nitems == 0) + return 0; + + /* Sort to collect the groups together. */ + const Ebl_Core_Item *sorted_items[nitems]; + for (size_t i = 0; i < nitems; ++i) + sorted_items[i] = &items[i]; + qsort (sorted_items, nitems, sizeof sorted_items[0], &compare_core_items); + + /* Collect the unique groups and sort them. */ + const Ebl_Core_Item **groups[nitems]; + groups[0] = &sorted_items[0]; + size_t ngroups = 1; + for (size_t i = 1; i < nitems; ++i) + if (sorted_items[i]->group != sorted_items[i - 1]->group + && strcmp (sorted_items[i]->group, sorted_items[i - 1]->group)) + groups[ngroups++] = &sorted_items[i]; + qsort (groups, ngroups, sizeof groups[0], &compare_core_item_groups); + + /* Write out all the groups. */ + unsigned int colno = 0; + for (size_t i = 0; i < ngroups; ++i) + { + for (const Ebl_Core_Item **item = groups[i]; + (item < &sorted_items[nitems] + && ((*item)->group == groups[i][0]->group + || !strcmp ((*item)->group, groups[i][0]->group))); + ++item) + colno = handle_core_item (core, *item, desc, colno); + + /* Force a line break at the end of the group. */ + colno = ITEM_WRAP_COLUMN; + } + + return colno; +} + +static unsigned int +handle_bit_registers (const Ebl_Register_Location *regloc, const void *desc, + unsigned int colno) +{ + desc += regloc->offset; + + abort (); /* XXX */ + return colno; +} + + +static unsigned int +handle_core_register (Ebl *ebl, Elf *core, int maxregname, + const Ebl_Register_Location *regloc, const void *desc, + unsigned int colno) +{ + if (regloc->bits % 8 != 0) + return handle_bit_registers (regloc, desc, colno); + + desc += regloc->offset; + + for (int reg = regloc->regno; reg < regloc->regno + regloc->count; ++reg) + { + const char *pfx; + const char *set; + char name[16]; + int bits; + int type; + ssize_t n = ebl_register_info (ebl, reg, name, sizeof name, + &pfx, &set, &bits, &type); + if (n <= 0) + error (EXIT_FAILURE, 0, + gettext ("unable to handle register number %d"), + regloc->regno); + +#define TYPES \ + BITS (8, BYTE, "%4" PRId8, "0x%.2" PRIx8, 4); \ + BITS (16, HALF, "%6" PRId16, "0x%.4" PRIx16, 6); \ + BITS (32, WORD, "%11" PRId32, " 0x%.8" PRIx32, 11); \ + BITS (64, XWORD, "%20" PRId64, " 0x%.16" PRIx64, 20) + +#define BITS(bits, xtype, sfmt, ufmt, max) \ + uint##bits##_t b##bits; int##bits##_t b##bits##s + union { TYPES; uint64_t b128[2]; } value; +#undef BITS + + switch (type) + { + case DW_ATE_unsigned: + case DW_ATE_signed: + case DW_ATE_address: + switch (bits) + { +#define BITS(bits, xtype, sfmt, ufmt, max) \ + case bits: \ + desc = convert (core, ELF_T_##xtype, 1, &value, desc); \ + if (type == DW_ATE_signed) \ + colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, \ + maxregname, name, \ + max, sfmt, value.b##bits##s); \ + else \ + colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, \ + maxregname, name, \ + max, ufmt, value.b##bits); \ + break + + TYPES; + + case 128: + assert (type == DW_ATE_unsigned); + desc = convert (core, ELF_T_XWORD, 2, &value, desc); + int be = elf_getident (core, NULL)[EI_DATA] == ELFDATA2MSB; + colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, + maxregname, name, + 34, "0x%.16" PRIx64 "%.16" PRIx64, + value.b128[!be], value.b128[be]); + break; + + default: + abort (); +#undef BITS + } + break; + + default: + /* Print each byte in hex, the whole thing in native byte order. */ + assert (bits % 8 == 0); + const uint8_t *bytes = desc; + desc += bits / 8; + char hex[bits / 4 + 1]; + hex[bits / 4] = '\0'; + int incr = 1; + if (elf_getident (core, NULL)[EI_DATA] == ELFDATA2LSB) + { + bytes += bits / 8 - 1; + incr = -1; + } + size_t idx = 0; + for (char *h = hex; bits > 0; bits -= 8, idx += incr) + { + *h++ = "0123456789abcdef"[bytes[idx] >> 4]; + *h++ = "0123456789abcdef"[bytes[idx] & 0xf]; + } + colno = print_core_item (colno, ' ', REGISTER_WRAP_COLUMN, + maxregname, name, + 2 + sizeof hex - 1, "0x%s", hex); + break; + } + desc += regloc->pad; + +#undef TYPES + } + + return colno; +} + + +struct register_info +{ + const Ebl_Register_Location *regloc; + const char *set; + char name[16]; + Dwarf_Half regno; + uint8_t bits; + uint8_t type; +}; + +static int +register_bitpos (const struct register_info *r) +{ + return (r->regloc->offset * 8 + + ((r->regno - r->regloc->regno) + * (r->regloc->bits + r->regloc->pad * 8))); +} + +static int +compare_sets_by_info (const struct register_info *r1, + const struct register_info *r2) +{ + return ((int) r2->bits - (int) r1->bits + ?: register_bitpos (r1) - register_bitpos (r2)); +} + +/* Sort registers by set, and by size and layout offset within each set. */ +static int +compare_registers (const void *a, const void *b) +{ + const struct register_info *r1 = a; + const struct register_info *r2 = b; + + /* Unused elements sort last. */ + if (r1->regloc == NULL) + return r2->regloc == NULL ? 0 : 1; + if (r2->regloc == NULL) + return -1; + + return ((r1->set == r2->set ? 0 : strcmp (r1->set, r2->set)) + ?: compare_sets_by_info (r1, r2)); +} + +/* Sort register sets by layout offset of the first register in the set. */ +static int +compare_register_sets (const void *a, const void *b) +{ + const struct register_info *const *p1 = a; + const struct register_info *const *p2 = b; + return compare_sets_by_info (*p1, *p2); +} + +static unsigned int +handle_core_registers (Ebl *ebl, Elf *core, const void *desc, + const Ebl_Register_Location *reglocs, size_t nregloc) +{ + if (nregloc == 0) + return 0; + + ssize_t maxnreg = ebl_register_info (ebl, 0, NULL, 0, NULL, NULL, NULL, NULL); + if (maxnreg <= 0) + error (EXIT_FAILURE, 0, + gettext ("cannot register info: %s"), elf_errmsg (-1)); + + struct register_info regs[maxnreg]; + memset (regs, 0, sizeof regs); + + /* Sort to collect the sets together. */ + int maxreg = 0; + for (size_t i = 0; i < nregloc; ++i) + for (int reg = reglocs[i].regno; + reg < reglocs[i].regno + reglocs[i].count; + ++reg) + { + assert (reg < maxnreg); + if (reg > maxreg) + maxreg = reg; + struct register_info *info = ®s[reg]; + + const char *pfx; + int bits; + int type; + ssize_t n = ebl_register_info (ebl, reg, info->name, sizeof info->name, + &pfx, &info->set, &bits, &type); + if (n <= 0) + error (EXIT_FAILURE, 0, + gettext ("cannot register info: %s"), elf_errmsg (-1)); + + info->regloc = ®locs[i]; + info->regno = reg; + info->bits = bits; + info->type = type; + } + qsort (regs, maxreg + 1, sizeof regs[0], &compare_registers); + + /* Collect the unique sets and sort them. */ + inline bool same_set (const struct register_info *a, + const struct register_info *b) + { + return (a < ®s[maxnreg] && a->regloc != NULL + && b < ®s[maxnreg] && b->regloc != NULL + && a->bits == b->bits + && (a->set == b->set || !strcmp (a->set, b->set))); + } + struct register_info *sets[maxreg + 1]; + sets[0] = ®s[0]; + size_t nsets = 1; + for (int i = 1; i <= maxreg; ++i) + if (regs[i].regloc != NULL && !same_set (®s[i], ®s[i - 1])) + sets[nsets++] = ®s[i]; + qsort (sets, nsets, sizeof sets[0], &compare_register_sets); + + /* Write out all the sets. */ + unsigned int colno = 0; + for (size_t i = 0; i < nsets; ++i) + { + /* Find the longest name of a register in this set. */ + size_t maxname = 0; + const struct register_info *end; + for (end = sets[i]; same_set (sets[i], end); ++end) + { + size_t len = strlen (end->name); + if (len > maxname) + maxname = len; + } + + for (const struct register_info *reg = sets[i]; + reg < end; + reg += reg->regloc->count ?: 1) + colno = handle_core_register (ebl, core, maxname, + reg->regloc, desc, colno); + + /* Force a line break at the end of the group. */ + colno = REGISTER_WRAP_COLUMN; + } + + return colno; +} + +static void +handle_auxv_note (Ebl *ebl, Elf *core, GElf_Word descsz, const void *desc) +{ + const size_t nauxv = descsz / gelf_fsize (core, ELF_T_AUXV, 1, EV_CURRENT); + for (size_t i = 0; i < nauxv; ++i) + { + const GElf_auxv_t *av = (const GElf_auxv_t *) desc + i; + + const char *name; + const char *fmt; + if (ebl_auxv_info (ebl, av->a_type, &name, &fmt) == 0) + { + /* Unknown type. */ + if (av->a_un.a_val == 0) + printf (" %" PRIu64 "\n", av->a_type); + else + printf (" %" PRIu64 ": %#" PRIx64 "\n", + av->a_type, av->a_un.a_val); + } + else + switch (fmt[0]) + { + case '\0': /* Normally zero. */ + if (av->a_un.a_val == 0) + { + printf (" %s\n", name); + break; + } + /* Fall through */ + case 'x': /* hex */ + case 'p': /* address */ + case 's': /* address of string */ + printf (" %s: %#" PRIx64 "\n", name, av->a_un.a_val); + break; + case 'u': + printf (" %s: %" PRIu64 "\n", name, av->a_un.a_val); + break; + case 'd': + printf (" %s: %" PRId64 "\n", name, av->a_un.a_val); + break; + + case 'b': + printf (" %s: %#" PRIx64 " ", name, av->a_un.a_val); + GElf_Xword bit = 1; + const char *pfx = "<"; + for (const char *p = fmt + 1; *p != 0; p = strchr (p, '\0') + 1) + { + if (av->a_un.a_val & bit) + { + printf ("%s%s", pfx, p); + pfx = " "; + } + bit <<= 1; + } + printf (">\n"); + break; + + default: + abort (); + } + } +} + +static void +handle_core_note (Ebl *ebl, const GElf_Nhdr *nhdr, const void *desc) +{ + GElf_Word regs_offset; + size_t nregloc; + const Ebl_Register_Location *reglocs; + size_t nitems; + const Ebl_Core_Item *items; + + if (! ebl_core_note (ebl, nhdr->n_type, nhdr->n_descsz, + ®s_offset, &nregloc, ®locs, &nitems, &items)) + return; + + unsigned int colno = handle_core_items (ebl->elf, desc, items, nitems); + if (colno != 0) + putchar_unlocked ('\n'); + + colno = handle_core_registers (ebl, ebl->elf, desc + regs_offset, + reglocs, nregloc); + if (colno != 0) + putchar_unlocked ('\n'); +} + + static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr) { @@ -4998,18 +5614,13 @@ handle_notes (Ebl *ebl, GElf_Ehdr *ehdr) size_t idx = 0; while (idx < phdr->p_filesz) { - /* XXX Handle 64-bit note section entries correctly. */ - struct - { - uint32_t namesz; - uint32_t descsz; - uint32_t type; - char name[0]; - } *noteentry = (__typeof (noteentry)) (notemem + idx); + const GElf_Nhdr *nhdr = (const GElf_Nhdr *) (notemem + idx); + const char *name = (const char *) (nhdr + 1); + const void *desc = &name[ALIGNED_LEN (nhdr->n_namesz)]; if (idx + 12 > phdr->p_filesz - || (idx + 12 + ALIGNED_LEN (noteentry->namesz) - + ALIGNED_LEN (noteentry->descsz) > phdr->p_filesz)) + || (idx + 12 + ALIGNED_LEN (nhdr->n_namesz) + + ALIGNED_LEN (nhdr->n_descsz) > phdr->p_filesz)) /* This entry isn't completely contained in the note section. Ignore it. */ break; @@ -5017,32 +5628,34 @@ handle_notes (Ebl *ebl, GElf_Ehdr *ehdr) char buf[100]; char buf2[100]; printf (gettext (" %-13.*s %9" PRId32 " %s\n"), - (int) noteentry->namesz, noteentry->name, - noteentry->descsz, + (int) nhdr->n_namesz, name, + nhdr->n_descsz, ehdr->e_type == ET_CORE - ? ebl_core_note_type_name (ebl, noteentry->type, + ? ebl_core_note_type_name (ebl, nhdr->n_type, buf, sizeof (buf)) - : ebl_object_note_type_name (ebl, noteentry->type, + : ebl_object_note_type_name (ebl, nhdr->n_type, buf2, sizeof (buf2))); /* Filter out invalid entries. */ - if (memchr (noteentry->name, '\0', noteentry->namesz) != NULL + if (memchr (name, '\0', nhdr->n_namesz) != NULL /* XXX For now help broken Linux kernels. */ || 1) { if (ehdr->e_type == ET_CORE) - ebl_core_note (ebl, noteentry->name, noteentry->type, - noteentry->descsz, - ¬eentry->name[ALIGNED_LEN (noteentry->namesz)]); + { + if (nhdr->n_type == NT_AUXV) + handle_auxv_note (ebl, ebl->elf, nhdr->n_descsz, desc); + else + handle_core_note (ebl, nhdr, desc); + } else - ebl_object_note (ebl, noteentry->name, noteentry->type, - noteentry->descsz, - ¬eentry->name[ALIGNED_LEN (noteentry->namesz)]); + ebl_object_note (ebl, name, nhdr->n_type, + nhdr->n_descsz, desc); } /* Move to the next entry. */ - idx += (12 + ALIGNED_LEN (noteentry->namesz) - + ALIGNED_LEN (noteentry->descsz)); + idx += (12 + ALIGNED_LEN (nhdr->n_namesz) + + ALIGNED_LEN (nhdr->n_descsz)); } gelf_freechunk (ebl->elf, notemem); diff --git a/src/unstrip.c b/src/unstrip.c index c1d40f1ca..a8c30022f 100644 --- a/src/unstrip.c +++ b/src/unstrip.c @@ -1094,6 +1094,73 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab, return split_bss; } +/* Create new .shstrtab contents, subroutine of copy_elided_sections. + This can't be open coded there and still use variable-length auto arrays, + since the end of our block would free other VLAs too. */ +static Elf_Data * +new_shstrtab (Elf *unstripped, size_t unstripped_shnum, + Elf_Data *shstrtab, size_t unstripped_shstrndx, + struct section *sections, size_t stripped_shnum, + struct Ebl_Strtab *strtab) +{ + if (strtab == NULL) + return NULL; + + struct Ebl_Strent *unstripped_strent[unstripped_shnum - 1]; + memset (unstripped_strent, 0, sizeof unstripped_strent); + for (struct section *sec = sections; + sec < §ions[stripped_shnum - 1]; + ++sec) + if (sec->outscn != NULL) + { + if (sec->strent == NULL) + { + sec->strent = ebl_strtabadd (strtab, sec->name, 0); + ELF_CHECK (sec->strent != NULL, + _("cannot add section name to string table: %s")); + } + unstripped_strent[elf_ndxscn (sec->outscn) - 1] = sec->strent; + } + + /* Add names of sections we aren't touching. */ + for (size_t i = 0; i < unstripped_shnum - 1; ++i) + if (unstripped_strent[i] == NULL) + { + Elf_Scn *scn = elf_getscn (unstripped, i + 1); + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + const char *name = get_section_name (i + 1, shdr, shstrtab); + unstripped_strent[i] = ebl_strtabadd (strtab, name, 0); + ELF_CHECK (unstripped_strent[i] != NULL, + _("cannot add section name to string table: %s")); + } + else + unstripped_strent[i] = NULL; + + /* Now finalize the string table so we can get offsets. */ + Elf_Data *strtab_data = elf_getdata (elf_getscn (unstripped, + unstripped_shstrndx), NULL); + ELF_CHECK (elf_flagdata (strtab_data, ELF_C_SET, ELF_F_DIRTY), + _("cannot update section header string table data: %s")); + ebl_strtabfinalize (strtab, strtab_data); + + /* Update the sh_name fields of sections we aren't modifying later. */ + for (size_t i = 0; i < unstripped_shnum - 1; ++i) + if (unstripped_strent[i] != NULL) + { + Elf_Scn *scn = elf_getscn (unstripped, i + 1); + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + shdr->sh_name = ebl_strtaboffset (unstripped_strent[i]); + if (i + 1 == unstripped_shstrndx) + shdr->sh_size = strtab_data->d_size; + ELF_CHECK (gelf_update_shdr (scn, shdr), + _("cannot update section header: %s")); + } + + return strtab_data; +} + /* Fill in any SHT_NOBITS sections in UNSTRIPPED by copying their contents and sh_type from STRIPPED. */ static void @@ -1310,63 +1377,11 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, ndx_section[secndx - 1] = elf_ndxscn (sec->outscn); } - Elf_Data *strtab_data = NULL; - if (strtab != NULL) - { - /* We added some sections, so we need a new shstrtab. */ - - struct Ebl_Strent *unstripped_strent[unstripped_shnum - 1]; - memset (unstripped_strent, 0, sizeof unstripped_strent); - for (struct section *sec = sections; - sec < §ions[stripped_shnum - 1]; - ++sec) - if (sec->outscn != NULL) - { - if (sec->strent == NULL) - { - sec->strent = ebl_strtabadd (strtab, sec->name, 0); - ELF_CHECK (sec->strent != NULL, - _("cannot add section name to string table: %s")); - } - unstripped_strent[elf_ndxscn (sec->outscn) - 1] = sec->strent; - } - - /* Add names of sections we aren't touching. */ - for (size_t i = 0; i < unstripped_shnum - 1; ++i) - if (unstripped_strent[i] == NULL) - { - scn = elf_getscn (unstripped, i + 1); - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - const char *name = get_section_name (i + 1, shdr, shstrtab); - unstripped_strent[i] = ebl_strtabadd (strtab, name, 0); - ELF_CHECK (unstripped_strent[i] != NULL, - _("cannot add section name to string table: %s")); - } - else - unstripped_strent[i] = NULL; - - /* Now finalize the string table so we can get offsets. */ - strtab_data = elf_getdata (elf_getscn (unstripped, unstripped_shstrndx), - NULL); - ELF_CHECK (elf_flagdata (strtab_data, ELF_C_SET, ELF_F_DIRTY), - _("cannot update section header string table data: %s")); - ebl_strtabfinalize (strtab, strtab_data); - - /* Update the sh_name fields of sections we aren't modifying later. */ - for (size_t i = 0; i < unstripped_shnum - 1; ++i) - if (unstripped_strent[i] != NULL) - { - scn = elf_getscn (unstripped, i + 1); - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - shdr->sh_name = ebl_strtaboffset (unstripped_strent[i]); - if (i + 1 == unstripped_shstrndx) - shdr->sh_size = strtab_data->d_size; - ELF_CHECK (gelf_update_shdr (scn, shdr), - _("cannot update section header: %s")); - } - } + /* We added some sections, so we need a new shstrtab. */ + Elf_Data *strtab_data = new_shstrtab (unstripped, unstripped_shnum, + shstrtab, unstripped_shstrndx, + sections, stripped_shnum, + strtab); /* Get the updated section count. */ ELF_CHECK (elf_getshnum (unstripped, &unstripped_shnum) == 0, diff --git a/tests/ChangeLog b/tests/ChangeLog index cc7e07279..adfcb2c75 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2007-08-23 Roland McGrath + + * run-allregs.sh: Update expected x86-64 output for %rflags. + 2007-08-12 Roland McGrath * run-strip-test7.sh: New file. diff --git a/tests/run-allregs.sh b/tests/run-allregs.sh index 74f973800..c7f46b0b9 100755 --- a/tests/run-allregs.sh +++ b/tests/run-allregs.sh @@ -106,6 +106,7 @@ integer registers: 14: %r14 (r14), signed 64 bits 15: %r15 (r15), signed 64 bits 16: %rip (rip), address 64 bits + 49: %rflags (rflags), unsigned 64 bits MMX registers: 41: %mm0 (mm0), unsigned 64 bits 42: %mm1 (mm1), unsigned 64 bits @@ -133,7 +134,6 @@ SSE registers: 31: %xmm14 (xmm14), unsigned 128 bits 32: %xmm15 (xmm15), unsigned 128 bits control registers: - 49: %rflags (rflags), unsigned 64 bits 62: %tr (tr), unsigned 64 bits 63: %ldtr (ldtr), unsigned 64 bits 64: %mxcsr (mxcsr), unsigned 64 bits