From 059c83e5db89955913a39fe6705acca571c32c3f Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 21 Feb 2008 06:19:39 +0000 Subject: [PATCH] Finish elflint .gnu.attributes checking --- backends/ChangeLog | 23 +++++ backends/Makefile.am | 6 +- backends/alpha_auxv.c | 46 +++++++++ backends/alpha_init.c | 3 +- backends/i386_corenote.c | 32 +++++- backends/ppc_attrs.c | 76 ++++++++++++++ backends/ppc_corenote.c | 15 ++- backends/ppc_init.c | 3 +- libdwfl/ChangeLog | 16 +++ libdwfl/dwfl_build_id_find_elf.c | 5 +- libdwfl/dwfl_module_getdwarf.c | 9 +- libdwfl/relocate.c | 28 ++++-- libebl/ChangeLog | 22 ++++ libebl/Makefile.am | 4 +- libebl/ebl-hooks.h | 6 +- libebl/eblcheckobjattr.c | 81 +++++++++++++++ libebl/eblcorenotetypename.c | 4 +- libebl/eblopenbackend.c | 19 +++- libebl/eblsectiontypename.c | 51 ++++++---- libebl/libebl.h | 11 +- libelf/ChangeLog | 17 ++++ libelf/elf.h | 7 +- libelf/elf_begin.c | 133 ++++++------------------ src/ChangeLog | 24 +++++ src/elfcmp.c | 6 +- src/elflint.c | 201 ++++++++++++++++++++++++++++++++++++- src/readelf.c | 211 ++++++++++++++++++++++++++++++++++++--- tests/ChangeLog | 6 ++ tests/Makefile.am | 3 +- tests/run-elflint-test.sh | 5 +- tests/testfile46.bz2 | Bin 0 -> 322 bytes 31 files changed, 908 insertions(+), 165 deletions(-) create mode 100644 backends/alpha_auxv.c create mode 100644 backends/ppc_attrs.c create mode 100644 libebl/eblcheckobjattr.c create mode 100644 tests/testfile46.bz2 diff --git a/backends/ChangeLog b/backends/ChangeLog index 25155db..681ba94 100644 --- a/backends/ChangeLog +++ b/backends/ChangeLog @@ -1,3 +1,26 @@ +2008-02-20 Roland McGrath + + * ppc_attrs.c: New file. + * Makefile.am (ppc_SRCS, ppc64_SRCS): Add it. + * ppc_init.c (ppc_init): Initialize check_object_attribute hook. + +2008-02-14 Roland McGrath + + * alpha_auxv.c: New file. + * Makefile.am (alpha_SRCS): Add it. + * alpha_init.c (alpha_init): Initialize auxv_info hook. + +2008-02-08 Roland McGrath + + * ppc_corenote.c (spe_regs): New const variable. + (EXTRA_NOTES): Use it for NT_PPC_SPE. + +2008-01-02 Roland McGrath + + * i386_corenote.c (tls_items): New const table. + (tls_info): New function, uses it. + (EXTRA_NOTES): Use it to handle NT_386_TLS. + 2008-01-08 Ulrich Drepper * Makefile.am: Add x86-64 disassembler. diff --git a/backends/Makefile.am b/backends/Makefile.am index 79fccfd..75eacde 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -81,7 +81,7 @@ 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_corenote.c + alpha_corenote.c alpha_auxv.c libebl_alpha_pic_a_SOURCES = $(alpha_SRCS) am_libebl_alpha_pic_a_OBJECTS = $(alpha_SRCS:.c=.os) @@ -95,12 +95,12 @@ 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_corenote.c ppc_auxv.c + ppc_corenote.c ppc_auxv.c ppc_attrs.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 \ - ppc64_corenote.c ppc_regs.c ppc_auxv.c + ppc64_corenote.c ppc_regs.c ppc_auxv.c ppc_attrs.c libebl_ppc64_pic_a_SOURCES = $(ppc64_SRCS) am_libebl_ppc64_pic_a_OBJECTS = $(ppc64_SRCS:.c=.os) diff --git a/backends/alpha_auxv.c b/backends/alpha_auxv.c new file mode 100644 index 0000000..38a8bcd --- /dev/null +++ b/backends/alpha_auxv.c @@ -0,0 +1,46 @@ +/* Alpha-specific auxv handling. + Copyright (C) 2008 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 alpha_ +#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" + "bwx\0" "fix\0" "cix\0" "0x08\0" + "0x10\0" "0x20\0" "0x40\0" "0x80\0" + "max\0" "precise_trap\0" + "\0"; + return 1; +} diff --git a/backends/alpha_init.c b/backends/alpha_init.c index 794d412..3c9e29d 100644 --- a/backends/alpha_init.c +++ b/backends/alpha_init.c @@ -1,5 +1,5 @@ /* Initialization of Alpha specific backend library. - Copyright (C) 2002, 2005, 2006, 2007 Red Hat, Inc. + Copyright (C) 2002, 2005, 2006, 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2002. @@ -57,6 +57,7 @@ alpha_init (elf, machine, eh, ehlen) HOOK (eh, machine_section_flag_check); HOOK (eh, register_info); HOOK (eh, core_note); + HOOK (eh, auxv_info); eh->sysvhash_entrysize = sizeof (Elf64_Xword); return MODVERSION; diff --git a/backends/i386_corenote.c b/backends/i386_corenote.c index f6c4c1d..02d8ec3 100644 --- a/backends/i386_corenote.c +++ b/backends/i386_corenote.c @@ -1,5 +1,5 @@ /* i386 specific core note handling. - Copyright (C) 2007 Red Hat, Inc. + Copyright (C) 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -101,6 +101,34 @@ static const Ebl_Register_Location prxfpreg_regs[] = }; #define EXTRA_NOTES \ - EXTRA_REGSET (NT_PRFPXREG, 512, prxfpreg_regs) + EXTRA_REGSET (NT_PRFPXREG, 512, prxfpreg_regs) \ + case NT_386_TLS: \ + return tls_info (descsz, regs_offset, nregloc, reglocs, nitems, items); + +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ + +static const Ebl_Core_Item tls_items[] = + { + { .type = ELF_T_WORD, .offset = 0x0, .format = 'd', .name = "index" }, + { .type = ELF_T_WORD, .offset = 0x4, .format = 'x', .name = "base" }, + { .type = ELF_T_WORD, .offset = 0x8, .format = 'x', .name = "limit" }, + { .type = ELF_T_WORD, .offset = 0xc, .format = 'x', .name = "flags" }, + }; + +static int +tls_info (GElf_Word descsz, GElf_Word *regs_offset, + size_t *nregloc, const Ebl_Register_Location **reglocs, + size_t *nitems, const Ebl_Core_Item **items) +{ + if (descsz % 16 != 0) + return 0; + + *regs_offset = 0; + *nregloc = 0; + *reglocs = NULL; + *nitems = sizeof tls_items / sizeof tls_items[0]; + *items = tls_items; + return 1; +} #include "linux-core-note.c" diff --git a/backends/ppc_attrs.c b/backends/ppc_attrs.c new file mode 100644 index 0000000..733b874 --- /dev/null +++ b/backends/ppc_attrs.c @@ -0,0 +1,76 @@ +/* Object attribute tags for PowerPC. + Copyright (C) 2008 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 + +#define BACKEND ppc_ +#include "libebl_CPU.h" + +bool +ppc_check_object_attribute (ebl, vendor, tag, value, tag_name, value_name) + Ebl *ebl __attribute__ ((unused)); + const char *vendor; + int tag; + uint64_t value; + const char **tag_name; + const char **value_name; +{ + if (!strcmp (vendor, "gnu")) + switch (tag) + { + case 4: + *tag_name = "GNU_Power_ABI_FP"; + static const char *fp_kinds[] = + { + "Hard or soft float", + "Hard float", + "Soft float", + }; + if (value < sizeof fp_kinds / sizeof fp_kinds[0]) + *value_name = fp_kinds[value]; + return true; + + case 8: + *tag_name = "GNU_Power_ABI_Vector"; + static const char *vector_kinds[] = + { + "Any", "Generic", "AltiVec", "SPE" + }; + if (value < sizeof vector_kinds / sizeof vector_kinds[0]) + *value_name = vector_kinds[value]; + return true; + } + + return false; +} + +__typeof (ppc_check_object_attribute) + ppc64_check_object_attribute + __attribute__ ((alias ("ppc_check_object_attribute"))); diff --git a/backends/ppc_corenote.c b/backends/ppc_corenote.c index daadbb4..59e619e 100644 --- a/backends/ppc_corenote.c +++ b/backends/ppc_corenote.c @@ -1,5 +1,5 @@ /* PowerPC specific core note handling. - Copyright (C) 2007 Red Hat, Inc. + Copyright (C) 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -81,8 +81,19 @@ static const Ebl_Register_Location altivec_regs[] = { .offset = 33 * 16, .regno = 356, .count = 1, .bits = 32, .pad = 12 } }; +static const Ebl_Register_Location spe_regs[] = + { + /* evr0-evr31 + { .offset = 0, .regno = ???, .count = 32, .bits = 32 }, + * acc * + { .offset = 32 * 4, .regno = ???, .count = 1, .bits = 64 }, */ + /* spefscr */ + { .offset = 34 * 4, .regno = 612, .count = 1, .bits = 32 } + }; + #define EXTRA_NOTES \ - EXTRA_REGSET (NT_PPC_VMX, 34 * 16, altivec_regs) + EXTRA_REGSET (NT_PPC_VMX, 34 * 16, altivec_regs) \ + EXTRA_REGSET (NT_PPC_SPE, 35 * 4, spe_regs) #if BITS == 32 # define ULONG uint32_t diff --git a/backends/ppc_init.c b/backends/ppc_init.c index 7edc8fa..2e58716 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, 2007 Red Hat, Inc. + Copyright (C) 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2004. @@ -59,6 +59,7 @@ ppc_init (elf, machine, eh, ehlen) HOOK (eh, register_info); HOOK (eh, core_note); HOOK (eh, auxv_info); + HOOK (eh, check_object_attribute); return MODVERSION; } diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index f878c0d..01a2537 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,19 @@ +2008-02-19 Roland McGrath + + * relocate.c (relocate_section): Check for an unhandled relocation + type before resolving a reloc's symbol. Lift DWFL_E_BADRELTYPE -> + DWFL_E_UNKNOWN_MACHINE check out of loops. + + * dwfl_module_getdwarf.c (load_dw): Skip relocation if + DEBUGFILE->relocated is already set. + +2008-01-26 Roland McGrath + + * dwfl_module_getdwarf.c (open_elf): Open FILE->name if it's non-null. + + * dwfl_build_id_find_elf.c (__libdwfl_open_by_build_id): Don't clear + incoming *FILE_NAME at the start. + 2008-01-08 Roland McGrath * Makefile.am (euinclude): Variable removed. diff --git a/libdwfl/dwfl_build_id_find_elf.c b/libdwfl/dwfl_build_id_find_elf.c index c621501..a6e38ce 100644 --- a/libdwfl/dwfl_build_id_find_elf.c +++ b/libdwfl/dwfl_build_id_find_elf.c @@ -1,5 +1,5 @@ /* Find an ELF file for a module from its build ID. - Copyright (C) 2007 Red Hat, Inc. + Copyright (C) 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -57,7 +57,8 @@ int internal_function __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name) { - *file_name = NULL; + /* If *FILE_NAME was primed into the module, leave it there + as the fallback when we have nothing to offer. */ errno = 0; if (mod->build_id_len <= 0) return -1; diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index 775df73..7dd9b53 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -1,5 +1,5 @@ /* Find debugging and symbol information for a module in libdwfl. - Copyright (C) 2005, 2006, 2007 Red Hat, Inc. + Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -61,6 +61,11 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file) { if (file->elf == NULL) { + /* If there was a pre-primed file name left that the callback left + behind, try to open that file name. */ + if (file->fd < 0 && file->name != NULL) + file->fd = TEMP_FAILURE_RETRY (open64 (file->name, O_RDONLY)); + if (file->fd < 0) return CBFAIL; @@ -585,7 +590,7 @@ __libdwfl_module_getebl (Dwfl_Module *mod) static Dwfl_Error load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile) { - if (mod->e_type == ET_REL) + if (mod->e_type == ET_REL && !debugfile->relocated) { const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c index 6265f1b..abacc04 100644 --- a/libdwfl/relocate.c +++ b/libdwfl/relocate.c @@ -1,5 +1,5 @@ /* Relocate debug information. - Copyright (C) 2005, 2006, 2007 Red Hat, Inc. + Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -306,6 +306,12 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend, int rtype, int symndx) { + /* First see if this is a reloc we can handle. + If we are skipping it, don't bother resolving the symbol. */ + Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype); + if (unlikely (type == ELF_T_NUM)) + return DWFL_E_BADRELTYPE; + /* First, resolve the symbol to an absolute value. */ GElf_Addr value; @@ -342,7 +348,6 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \ DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword) size_t size; - Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype); switch (type) { #define DO_TYPE(NAME, Name) \ @@ -352,10 +357,6 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, TYPES; #undef DO_TYPE default: - /* This might be because ebl_openbackend failed to find - any libebl_CPU.so library. Diagnose that clearly. */ - if (ebl_get_elfmachine (mod->ebl) == EM_NONE) - return DWFL_E_UNKNOWN_MACHINE; return DWFL_E_BADRELTYPE; } @@ -437,6 +438,19 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, return DWFL_E_LIBELF; Dwfl_Error result = DWFL_E_NOERROR; + bool first_badreltype = true; + inline void check_badreltype (void) + { + if (first_badreltype) + { + first_badreltype = false; + if (ebl_get_elfmachine (mod->ebl) == EM_NONE) + /* This might be because ebl_openbackend failed to find + any libebl_CPU.so library. Diagnose that clearly. */ + result = DWFL_E_UNKNOWN_MACHINE; + } + } + size_t nrels = shdr->sh_size / shdr->sh_entsize; size_t complete = 0; if (shdr->sh_type == SHT_REL) @@ -448,6 +462,7 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, result = relocate (r->r_offset, NULL, GELF_R_TYPE (r->r_info), GELF_R_SYM (r->r_info)); + check_badreltype (); if (partial) switch (result) { @@ -476,6 +491,7 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, result = relocate (r->r_offset, &r->r_addend, GELF_R_TYPE (r->r_info), GELF_R_SYM (r->r_info)); + check_badreltype (); if (partial) switch (result) { diff --git a/libebl/ChangeLog b/libebl/ChangeLog index 86c9178..8ebc6c1 100644 --- a/libebl/ChangeLog +++ b/libebl/ChangeLog @@ -1,3 +1,25 @@ +2008-02-20 Roland McGrath + + * libebl.h: Declare ebl_check_object_attribute. + * eblcheckobjattr.c: New file. + * Makefile.am (gen_SOURCES): Add it. + * ebl-hooks.h: Add check_object_attribute hook. + * eblopenbackend.c (default_check_object_attribute): New function. + (fill_defaults): Initialize pointer to it. + +2008-02-19 Roland McGrath + + * eblsectiontypename.c (ebl_section_type_name): + Handle SHT_GNU_ATTRIBUTES. + +2008-02-08 Roland McGrath + + * eblcorenotetypename.c (ebl_core_note_type_name): Handle NT_PPC_SPE. + +2008-01-30 Roland McGrath + + * eblcorenotetypename.c (ebl_core_note_type_name): Handle NT_386_TLS. + 2007-10-18 Roland McGrath * eblcorenotetypename.c (ebl_core_note_type_name): Handle NT_PPC_VMX. diff --git a/libebl/Makefile.am b/libebl/Makefile.am index 2cf570e..1e36b33 100644 --- a/libebl/Makefile.am +++ b/libebl/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,2008 Red Hat, Inc. ## This file is part of Red Hat elfutils. ## ## Red Hat elfutils is free software; you can redistribute it and/or modify @@ -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 eblauxvinfo.c + eblsysvhashentrysize.c eblauxvinfo.c eblcheckobjattr.c libebl_a_SOURCES = $(gen_SOURCES) diff --git a/libebl/ebl-hooks.h b/libebl/ebl-hooks.h index c0c929b..c236b35 100644 --- a/libebl/ebl-hooks.h +++ b/libebl/ebl-hooks.h @@ -115,6 +115,10 @@ int EBLHOOK(core_note) (GElf_Word, GElf_Word, GElf_Word *, size_t *, /* Handle object file note. */ bool EBLHOOK(object_note) (const char *, uint32_t, uint32_t, const char *); +/* Check object attribute. */ +bool EBLHOOK(check_object_attribute) (Ebl *, const char *, int, uint64_t, + const char **, const char **); + /* Describe auxv element type. */ int EBLHOOK(auxv_info) (GElf_Xword, const char **, const char **); @@ -148,7 +152,7 @@ ssize_t EBLHOOK(register_info) (Ebl *ebl, const char **prefix, const char **setname, int *bits, int *type); - /* Disassembler function. */ +/* Disassembler function. */ int EBLHOOK(disasm) (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, const char *fmt, DisasmOutputCB_t outcb, DisasmGetSymCB_t symcb, void *outcbarg, void *symcbarg); diff --git a/libebl/eblcheckobjattr.c b/libebl/eblcheckobjattr.c new file mode 100644 index 0000000..fe75de7 --- /dev/null +++ b/libebl/eblcheckobjattr.c @@ -0,0 +1,81 @@ +/* Check object attributes. + Copyright (C) 2008 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 + + +bool +ebl_check_object_attribute (ebl, vendor, tag, value, tag_name, value_name) + Ebl *ebl; + const char *vendor; + int tag; + uint64_t value; + const char **tag_name; + const char **value_name; +{ + if (ebl->check_object_attribute (ebl, vendor, tag, value, + tag_name, value_name)) + return true; + + if (strcmp (vendor, "gnu")) + return false; + + if (tag == 32) + { + *tag_name = "compatibility"; + return true; + } + + return false; +} diff --git a/libebl/eblcorenotetypename.c b/libebl/eblcorenotetypename.c index 44b0237..d01932f 100644 --- a/libebl/eblcorenotetypename.c +++ b/libebl/eblcorenotetypename.c @@ -1,5 +1,5 @@ /* Return note type name. - Copyright (C) 2002, 2007 Red Hat, Inc. + Copyright (C) 2002, 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2002. @@ -99,6 +99,8 @@ ebl_core_note_type_name (ebl, type, buf, len) #define KNOWNSTYPE(name) case NT_##name: res = #name; break KNOWNSTYPE (PRXFPREG); KNOWNSTYPE (PPC_VMX); + KNOWNSTYPE (PPC_SPE); + KNOWNSTYPE (386_TLS); #undef KNOWNSTYPE default: diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c index 8a44f90..08817f6 100644 --- a/libebl/eblopenbackend.c +++ b/libebl/eblopenbackend.c @@ -1,5 +1,5 @@ /* Generate ELF backend handle. - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. + Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007,2008 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -210,6 +210,10 @@ static ssize_t default_register_info (Ebl *ebl, const char **prefix, const char **setname, int *bits, int *type); +static bool default_check_object_attribute (Ebl *ebl, const char *vendor, + int tag, uint64_t value, + const char **tag_name, + const char **value_name); static void @@ -246,6 +250,7 @@ fill_defaults (Ebl *result) result->bss_plt_p = default_bss_plt_p; result->return_value_location = default_return_value_location; result->register_info = default_register_info; + result->check_object_attribute = default_check_object_attribute; result->disasm = NULL; result->destr = default_destr; result->sysvhash_entrysize = sizeof (Elf32_Word); @@ -700,3 +705,15 @@ default_register_info (Ebl *ebl __attribute__ ((unused)), *type = DW_ATE_void; return snprintf (name, namelen, "reg%d", regno); } + +static bool +default_check_object_attribute (Ebl *ebl __attribute__ ((unused)), + const char *vendor __attribute__ ((unused)), + int tag __attribute__ ((unused)), + uint64_t value __attribute__ ((unused)), + const char **tag_name, const char **value_name) +{ + *tag_name = NULL; + *value_name = NULL; + return false; +} diff --git a/libebl/eblsectiontypename.c b/libebl/eblsectiontypename.c index b62c37b..a37e5f6 100644 --- a/libebl/eblsectiontypename.c +++ b/libebl/eblsectiontypename.c @@ -1,5 +1,5 @@ /* Return section type name. - Copyright (C) 2001, 2002, 2006 Red Hat, Inc. + Copyright (C) 2001, 2002, 2006, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2001. @@ -110,31 +110,38 @@ ebl_section_type_name (ebl, section, buf, len) res = sunwtypes[section - SHT_LOSUNW]; } else - { - /* A few GNU additions. */ - if (section == SHT_CHECKSUM) + /* A few GNU additions. */ + switch (section) + { + case SHT_CHECKSUM: res = "CHECKSUM"; - else if (section == SHT_GNU_LIBLIST) + break; + case SHT_GNU_LIBLIST: res = "GNU_LIBLIST"; - else if (section == SHT_GNU_HASH) + break; + case SHT_GNU_HASH: res = "GNU_HASH"; - /* Handle OS-specific section names. */ - else - { - if (section >= SHT_LOOS && section <= SHT_HIOS) - snprintf (buf, len, "SHT_LOOS+%x", section - SHT_LOOS); - /* Handle processor-specific section names. */ - else if (section >= SHT_LOPROC && section <= SHT_HIPROC) - snprintf (buf, len, "SHT_LOPROC+%x", section - SHT_LOPROC); - else if ((unsigned int) section >= SHT_LOUSER - && (unsigned int) section <= SHT_HIUSER) - snprintf (buf, len, "SHT_LOUSER+%x", section - SHT_LOUSER); - else - snprintf (buf, len, "%s: %d", gettext (""), section); + break; + case SHT_GNU_ATTRIBUTES: + res = "GNU_ATTRIBUTES"; + break; - res = buf; - } - } + default: + /* Handle OS-specific section names. */ + if (section >= SHT_LOOS && section <= SHT_HIOS) + snprintf (buf, len, "SHT_LOOS+%x", section - SHT_LOOS); + /* Handle processor-specific section names. */ + else if (section >= SHT_LOPROC && section <= SHT_HIPROC) + snprintf (buf, len, "SHT_LOPROC+%x", section - SHT_LOPROC); + else if ((unsigned int) section >= SHT_LOUSER + && (unsigned int) section <= SHT_HIUSER) + snprintf (buf, len, "SHT_LOUSER+%x", section - SHT_LOUSER); + else + snprintf (buf, len, "%s: %d", gettext (""), section); + + res = buf; + break; + } } return res; diff --git a/libebl/libebl.h b/libebl/libebl.h index 7e29168..083de03 100644 --- a/libebl/libebl.h +++ b/libebl/libebl.h @@ -1,5 +1,5 @@ /* Interface for libebl. - Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007 Red Hat, Inc. + Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -182,6 +182,15 @@ extern const char *ebl_object_note_type_name (Ebl *ebl, uint32_t type, extern void ebl_object_note (Ebl *ebl, const char *name, uint32_t type, uint32_t descsz, const char *desc); +/* Check whether an attribute in a .gnu_attributes section is recognized. + Fills in *TAG_NAME with the name for this tag. + If VALUE is a known value for that tag, also fills in *VALUE_NAME. */ +extern bool ebl_check_object_attribute (Ebl *ebl, const char *vendor, + int tag, uint64_t value, + const char **tag_name, + const char **value_name); + + /* Check section name for being that of a debug informatino section. */ extern bool ebl_debugscn_p (Ebl *ebl, const char *name); diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 17633ba..ef7b37a 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,8 +1,25 @@ +2008-02-19 Roland McGrath + + * elf.h: Update from glibc. + +2008-02-08 Roland McGrath + + * elf.h: Update from glibc. + 2008-01-31 Ulrich Drepper * elf_strptr.c (elf_strptr): Don't fail if the ELF file is currently under construction and no raw data can be read from disk. +2008-01-30 Roland McGrath + + * elf.h: Update from glibc. + +2008-01-26 Roland McGrath + + * elf_begin.c (__libelf_next_arhdr): Rewrite conversions using a macro. + Fixes various pastos in wrong type in sizeof, wrong string parsed. + 2008-01-20 Roland McGrath * elf_getaroff.c: Calculate from start_offset, instead of using diff --git a/libelf/elf.h b/libelf/elf.h index acd3d3e..928e9ec 100644 --- a/libelf/elf.h +++ b/libelf/elf.h @@ -1,5 +1,6 @@ /* This file defines standard ELF types, structures, and macros. - Copyright (C) 1995-2003,2004,2005,2006,2007 Free Software Foundation, Inc. + Copyright (C) 1995-2003,2004,2005,2006,2007,2008 + Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -330,6 +331,7 @@ typedef struct #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ #define SHT_NUM 19 /* Number of defined types. */ #define SHT_LOOS 0x60000000 /* Start OS-specific. */ +#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ #define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ #define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ #define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ @@ -605,6 +607,8 @@ typedef struct #define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ #define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ #define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ +#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ +#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ /* Legal values for the note segment descriptor types for object files. */ @@ -1278,6 +1282,7 @@ typedef struct #define HWCAP_SPARC_V9 16 /* The CPU is v9, so v8plus is ok. */ #define HWCAP_SPARC_ULTRA3 32 #define HWCAP_SPARC_BLKINIT 64 /* Sun4v with block-init/load-twin. */ +#define HWCAP_SPARC_N2 128 /* MIPS R3000 specific definitions. */ diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c index d84f904..b95b06b 100644 --- a/libelf/elf_begin.c +++ b/libelf/elf_begin.c @@ -1,5 +1,5 @@ /* Create descriptor for processing file. - Copyright (C) 1998-2005, 2006, 2007 Red Hat, Inc. + Copyright (C) 1998-2005, 2006, 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 1998. @@ -850,112 +850,45 @@ __libelf_next_arhdr (elf) elf_ar_hdr->ar_name = elf->state.ar.ar_name; } + if (unlikely (ar_hdr->ar_size[0] == ' ')) + /* Something is really wrong. We cannot live without a size for + the member since it will not be possible to find the next + archive member. */ + { + __libelf_seterrno (ELF_E_INVALID_ARCHIVE); + return -1; + } + /* Since there are no specialized functions to convert ASCII to time_t, uid_t, gid_t, mode_t, and off_t we use either atol or atoll depending on the size of the types. We are also prepared for the case where the whole field in the `struct ar_hdr' is filled in which case we cannot simply use atol/l but instead have to create a temporary copy. */ - if (ar_hdr->ar_date[sizeof (ar_hdr->ar_date) - 1] == ' ') - { - if (ar_hdr->ar_date[0] == ' ') - elf_ar_hdr->ar_date = 0; - else - elf_ar_hdr->ar_date = (sizeof (time_t) <= sizeof (long int) - ? (time_t) atol (ar_hdr->ar_date) - : (time_t) atoll (ar_hdr->ar_date)); - } - else - { - char buf[sizeof (ar_hdr->ar_date) + 1]; - *((char *) __mempcpy (buf, ar_hdr->ar_date, sizeof (ar_hdr->ar_date))) - = '\0'; - elf_ar_hdr->ar_date = (sizeof (time_t) <= sizeof (long int) - ? (time_t) atol (ar_hdr->ar_date) - : (time_t) atoll (ar_hdr->ar_date)); - } - if (ar_hdr->ar_uid[sizeof (ar_hdr->ar_uid) - 1] == ' ') - { - if (ar_hdr->ar_uid[0] == ' ') - elf_ar_hdr->ar_uid = 0; - else - elf_ar_hdr->ar_uid = (sizeof (uid_t) <= sizeof (long int) - ? (uid_t) atol (ar_hdr->ar_uid) - : (uid_t) atoll (ar_hdr->ar_uid)); - } - else - { - char buf[sizeof (ar_hdr->ar_uid) + 1]; - *((char *) __mempcpy (buf, ar_hdr->ar_uid, sizeof (ar_hdr->ar_uid))) - = '\0'; - elf_ar_hdr->ar_uid = (sizeof (uid_t) <= sizeof (long int) - ? (uid_t) atol (ar_hdr->ar_uid) - : (uid_t) atoll (ar_hdr->ar_uid)); - } - - if (ar_hdr->ar_gid[sizeof (ar_hdr->ar_gid) - 1] == ' ') - { - if (ar_hdr->ar_gid[0] == ' ') - elf_ar_hdr->ar_gid = 0; - else - elf_ar_hdr->ar_gid = (sizeof (gid_t) <= sizeof (long int) - ? (gid_t) atol (ar_hdr->ar_gid) - : (gid_t) atoll (ar_hdr->ar_gid)); - } - else - { - char buf[sizeof (ar_hdr->ar_gid) + 1]; - *((char *) __mempcpy (buf, ar_hdr->ar_gid, sizeof (ar_hdr->ar_gid))) - = '\0'; - elf_ar_hdr->ar_gid = (sizeof (gid_t) <= sizeof (long int) - ? (gid_t) atol (ar_hdr->ar_gid) - : (gid_t) atoll (ar_hdr->ar_gid)); - } - - if (ar_hdr->ar_mode[sizeof (ar_hdr->ar_mode) - 1] == ' ') - { - if (ar_hdr->ar_mode[0] == ' ') - elf_ar_hdr->ar_mode = 0; - else - elf_ar_hdr->ar_mode = (sizeof (mode_t) <= sizeof (long int) - ? (mode_t) strtol (ar_hdr->ar_mode, NULL, 8) - : (mode_t) strtoll (ar_hdr->ar_mode, NULL, 8)); - } - else - { - char buf[sizeof (ar_hdr->ar_mode) + 1]; - *((char *) __mempcpy (buf, ar_hdr->ar_mode, sizeof (ar_hdr->ar_mode))) - = '\0'; - elf_ar_hdr->ar_mode = (sizeof (mode_t) <= sizeof (long int) - ? (mode_t) strtol (ar_hdr->ar_mode, NULL, 8) - : (mode_t) strtoll (ar_hdr->ar_mode, NULL, 8)); - } - - if (ar_hdr->ar_size[sizeof (ar_hdr->ar_size) - 1] == ' ') - { - if (unlikely (ar_hdr->ar_size[0] == ' ')) - /* Something is really wrong. We cannot live without a size for - the member since it will not be possible to find the next - archive member. */ - { - __libelf_seterrno (ELF_E_INVALID_ARCHIVE); - return -1; - } - else - elf_ar_hdr->ar_size = (sizeof (time_t) == sizeof (long int) - ? (off_t) atol (ar_hdr->ar_size) - : (off_t) atoll (ar_hdr->ar_size)); - } - else - { - char buf[sizeof (ar_hdr->ar_size) + 1]; - *((char *) __mempcpy (buf, ar_hdr->ar_size, sizeof (ar_hdr->ar_size))) - = '\0'; - elf_ar_hdr->ar_size = (sizeof (time_t) == sizeof (long int) - ? (off_t) atol (ar_hdr->ar_size) - : (off_t) atoll (ar_hdr->ar_size)); - } +#define INT_FIELD(FIELD) \ + do \ + { \ + char buf[sizeof (ar_hdr->FIELD) + 1]; \ + const char *string = ar_hdr->FIELD; \ + if (ar_hdr->FIELD[sizeof (ar_hdr->FIELD) - 1] != ' ') \ + { \ + *((char *) __mempcpy (buf, ar_hdr->FIELD, sizeof (ar_hdr->FIELD))) \ + = '\0'; \ + string = buf; \ + } \ + if (sizeof (elf_ar_hdr->FIELD) <= sizeof (long int)) \ + elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atol (string); \ + else \ + elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atoll (string); \ + } \ + while (0) + + INT_FIELD (ar_date); + INT_FIELD (ar_uid); + INT_FIELD (ar_gid); + INT_FIELD (ar_mode); + INT_FIELD (ar_size); return 0; } diff --git a/src/ChangeLog b/src/ChangeLog index d3e49e4..f28c700 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,21 @@ +2008-02-20 Roland McGrath + + * readelf.c (print_attributes): New function. + (process_elf_file): Call it under -A. + + * elflint.c (check_attributes): Implement it for real. + +2008-02-19 Roland McGrath + + * elflint.c (special_sections): Handle .gnu.attributes section. + (check_sections): Likewise. + (check_attributes): New function. + +2008-02-10 Roland McGrath + + * elfcmp.c (main): Ignore sh_offset differences in non-SHF_ALLOC + sections and ET_REL files. + 2008-02-02 Ulrich Drepper * elf32-i386.script: Add .eh_frame_hdr, .tdata, and .tbss sections. @@ -110,6 +128,12 @@ 2008-01-04 Roland McGrath + * readelf.c (handle_core_items): Take new arg DESCSZ; if nonzero, + a size greater than the items cover means multiple sets of items. + (handle_core_note): Update caller. + +2008-01-04 Roland McGrath + * strip.c (handle_elf): Move SHDRIDX defn to silence gcc warning. 2008-01-03 Roland McGrath diff --git a/src/elfcmp.c b/src/elfcmp.c index be9aacc..0e134df 100644 --- a/src/elfcmp.c +++ b/src/elfcmp.c @@ -1,5 +1,5 @@ /* Compare relevant content of two ELF files. - Copyright (C) 2005, 2006, 2007 Red Hat, Inc. + Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 2005. @@ -259,7 +259,9 @@ main (int argc, char *argv[]) // XXX Any flags which should be ignored? || shdr1->sh_flags != shdr2->sh_flags || shdr1->sh_addr != shdr2->sh_addr - || shdr1->sh_offset != shdr2->sh_offset + || (shdr1->sh_offset != shdr2->sh_offset + && (shdr1->sh_flags & SHF_ALLOC) + && ehdr1->e_type != ET_REL) || shdr1->sh_size != shdr2->sh_size || shdr1->sh_link != shdr2->sh_link || shdr1->sh_info != shdr2->sh_info diff --git a/src/elflint.c b/src/elflint.c index b65170c..9a1a717 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -46,7 +46,12 @@ #include #include +#include "../libelf/libelfP.h" +#include "../libelf/common.h" #include "../libebl/libeblP.h" +#include "../libdw/libdwP.h" +#include "../libdwfl/libdwflP.h" +#include "../libdw/memory-access.h" /* Name and version of program. */ @@ -3099,6 +3104,194 @@ section [%2d] '%s': unknown parent version '%s'\n"), } } +static void +check_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx) +{ + if (shdr->sh_size == 0) + { + ERROR (gettext ("section [%2d] '%s': empty object attributes section\n"), + idx, section_name (ebl, idx)); + return; + } + + Elf_Data *data = elf_rawdata (elf_getscn (ebl->elf, idx), NULL); + if (data == NULL || data->d_size == 0) + { + ERROR (gettext ("section [%2d] '%s': cannot get section data\n"), + idx, section_name (ebl, idx)); + return; + } + + inline size_t pos (const unsigned char *p) + { + return p - (const unsigned char *) data->d_buf; + } + + const unsigned char *p = data->d_buf; + if (*p++ != 'A') + { + ERROR (gettext ("section [%2d] '%s': unrecognized attribute format\n"), + idx, section_name (ebl, idx)); + return; + } + + inline size_t left (void) + { + return (const unsigned char *) data->d_buf + data->d_size - p; + } + + while (left () >= 4) + { + uint32_t len; + memcpy (&len, p, sizeof len); + + if (len == 0) + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: zero length field in attribute section\n"), + idx, section_name (ebl, idx), pos (p)); + + if (MY_ELFDATA != ehdr->e_ident[EI_DATA]) + CONVERT (len); + + if (len > left ()) + { + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: invalid length in attribute section\n"), + idx, section_name (ebl, idx), pos (p)); + break; + } + + const unsigned char *name = p + sizeof len; + p += len; + + unsigned const char *q = memchr (name, '\0', len); + if (q == NULL) + { + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: unterminated vendor name string\n"), + idx, section_name (ebl, idx), pos (p)); + continue; + } + ++q; + + if (q - name == sizeof "gnu" && !memcmp (name, "gnu", sizeof "gnu")) + while (q < p) + { + unsigned const char *chunk = q; + + unsigned int subsection_tag; + get_uleb128 (subsection_tag, q); + + if (q >= p) + { + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: endless ULEB128 in attribute subsection tag\n"), + idx, section_name (ebl, idx), pos (chunk)); + break; + } + + uint32_t subsection_len; + if (p - q < (ptrdiff_t) sizeof subsection_len) + { + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: truncated attribute section\n"), + idx, section_name (ebl, idx), pos (q)); + break; + } + + memcpy (&subsection_len, q, sizeof subsection_len); + if (subsection_len == 0) + { + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: zero length field in attribute subsection\n"), + idx, section_name (ebl, idx), pos (q)); + + q += sizeof subsection_len; + continue; + } + + if (MY_ELFDATA != ehdr->e_ident[EI_DATA]) + CONVERT (subsection_len); + + if (p - chunk < subsection_len) + { + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: invalid length in attribute subsection\n"), + idx, section_name (ebl, idx), pos (q)); + break; + } + + const unsigned char *subsection_end = chunk + subsection_len; + chunk = q; + q = subsection_end; + + if (subsection_tag != 1) /* Tag_File */ + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: attribute subsection has unexpected tag %u\n"), + idx, section_name (ebl, idx), pos (chunk), subsection_tag); + else + { + chunk += sizeof subsection_len; + while (chunk < q) + { + unsigned int tag; + get_uleb128 (tag, chunk); + + uint64_t value = 0; + const unsigned char *r = chunk; + if (tag == 32 || (tag & 1) == 0) + { + get_uleb128 (value, r); + if (r > q) + { + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: endless ULEB128 in attribute tag\n"), + idx, section_name (ebl, idx), pos (chunk)); + break; + } + } + if (tag == 32 || (tag & 1) != 0) + { + r = memchr (r, '\0', q - r); + if (r == NULL) + { + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: unterminated string in attribute\n"), + idx, section_name (ebl, idx), pos (chunk)); + break; + } + ++r; + } + + const char *tag_name = NULL; + const char *value_name = NULL; + if (!ebl_check_object_attribute (ebl, (const char *) name, + tag, value, + &tag_name, &value_name)) + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: unrecognized attribute tag %u\n"), + idx, section_name (ebl, idx), pos (chunk), tag); + else if ((tag & 1) == 0 && value_name == NULL) + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: unrecognized %s attribute value %" PRIu64 "\n"), + idx, section_name (ebl, idx), pos (chunk), + tag_name, value); + + chunk = r; + } + } + } + else + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: vendor '%s' unknown\n"), + idx, section_name (ebl, idx), pos (p), name); + } + + if (left () != 0) + ERROR (gettext ("\ +section [%2d] '%s': offset %zu: extra bytes after last attribute section\n"), + idx, section_name (ebl, idx), pos (p)); +} static bool has_loadable_segment; static bool has_interp_segment; @@ -3150,7 +3343,8 @@ static const struct /* The following are GNU extensions. */ { ".gnu.version", 13, SHT_GNU_versym, exact, SHF_ALLOC, 0 }, { ".gnu.version_d", 15, SHT_GNU_verdef, exact, SHF_ALLOC, 0 }, - { ".gnu.version_r", 15, SHT_GNU_verneed, exact, SHF_ALLOC, 0 } + { ".gnu.version_r", 15, SHT_GNU_verneed, exact, SHF_ALLOC, 0 }, + { ".gnu.attributes", 16, SHT_GNU_ATTRIBUTES, exact, 0, 0 }, }; #define nspecial_sections \ (sizeof (special_sections) / sizeof (special_sections[0])) @@ -3365,6 +3559,7 @@ section [%2zu] '%s': size not multiple of entry size\n"), ERROR (gettext ("cannot get section header\n")); if (shdr->sh_type >= SHT_NUM + && shdr->sh_type != SHT_GNU_ATTRIBUTES && shdr->sh_type != SHT_GNU_LIBLIST && shdr->sh_type != SHT_CHECKSUM && shdr->sh_type != SHT_GNU_verdef @@ -3557,6 +3752,10 @@ section [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"), check_verdef (ebl, shdr, cnt); break; + case SHT_GNU_ATTRIBUTES: + check_attributes (ebl, ehdr, shdr, cnt); + break; + default: /* Nothing. */ break; diff --git a/src/readelf.c b/src/readelf.c index 90c460f..0f0773c 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -1,5 +1,5 @@ /* Print information from ELF file in human-readable form. - Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007 Red Hat, Inc. + Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper , 1999. @@ -52,6 +52,7 @@ #include #include "../libelf/libelfP.h" +#include "../libelf/common.h" #include "../libebl/libeblP.h" #include "../libdw/libdwP.h" #include "../libdwfl/libdwflP.h" @@ -221,6 +222,7 @@ static void print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr); static void handle_hash (Ebl *ebl); static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr); static void print_liblist (Ebl *ebl); +static void print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr); static void dump_data (Ebl *ebl); static void dump_strings (Ebl *ebl); static void print_strings (Ebl *ebl); @@ -640,6 +642,8 @@ process_elf_file (Dwfl_Module *dwflmod, int fd) print_symtab (ebl, SHT_SYMTAB); if (print_arch) print_liblist (ebl); + if (print_arch) + print_attributes (ebl, ehdr); if (dump_data_sections != NULL) dump_data (pure_ebl); if (string_sections != NULL) @@ -2777,6 +2781,166 @@ print_liblist (Ebl *ebl) } } +static void +print_attributes (Ebl *ebl, const GElf_Ehdr *ehdr) +{ + /* Find the object attributes sections. For this we have to search + through the section table. */ + Elf_Scn *scn = NULL; + + /* Get the section header string table index. */ + size_t shstrndx; + if (unlikely (elf_getshstrndx (ebl->elf, &shstrndx) < 0)) + error (EXIT_FAILURE, 0, + gettext ("cannot get section header string table index")); + + while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + + if (shdr == NULL || shdr->sh_type != SHT_GNU_ATTRIBUTES) + continue; + + printf (gettext ("\ +\nObject attributes section [%2zu] '%s' of %" PRIu64 + " bytes at offset %#0" PRIx64 ":\n"), + elf_ndxscn (scn), + elf_strptr (ebl->elf, shstrndx, shdr->sh_name), + shdr->sh_size, shdr->sh_offset); + + Elf_Data *data = elf_rawdata (scn, NULL); + if (data == NULL) + return; + + const unsigned char *p = data->d_buf; + + if (unlikely (*p++ != 'A')) + return; + + fputs_unlocked (gettext (" Owner Size\n"), stdout); + + inline size_t left (void) + { + return (const unsigned char *) data->d_buf + data->d_size - p; + } + + while (left () >= 4) + { + uint32_t len; + memcpy (&len, p, sizeof len); + + if (MY_ELFDATA != ehdr->e_ident[EI_DATA]) + CONVERT (len); + + if (unlikely (len > left ())) + break; + + const unsigned char *name = p + sizeof len; + p += len; + + unsigned const char *q = memchr (name, '\0', len); + if (unlikely (q == NULL)) + continue; + ++q; + + printf (gettext (" %-13s %4" PRIu32 "\n"), name, len); + + if (q - name == sizeof "gnu" + && !memcmp (name, "gnu", sizeof "gnu")) + while (q < p) + { + const unsigned char *const sub = q; + + unsigned int subsection_tag; + get_uleb128 (subsection_tag, q); + if (unlikely (q >= p)) + break; + + uint32_t subsection_len; + if (unlikely (p - sub < (ptrdiff_t) sizeof subsection_len)) + break; + + memcpy (&subsection_len, q, sizeof subsection_len); + + if (MY_ELFDATA != ehdr->e_ident[EI_DATA]) + CONVERT (subsection_len); + + if (unlikely (p - sub < subsection_len)) + break; + + const unsigned char *r = q + sizeof subsection_len; + q = sub + subsection_len; + + switch (subsection_tag) + { + default: + printf (gettext (" %-4u %12" PRIu32 "\n"), + subsection_tag, subsection_len); + break; + + case 1: /* Tag_File */ + printf (gettext (" File: %11" PRIu32 "\n"), + subsection_len); + + while (r < q) + { + unsigned int tag; + get_uleb128 (tag, r); + if (unlikely (r >= q)) + break; + + uint64_t value = 0; + const char *string = NULL; + if (tag == 32 || (tag & 1) == 0) + { + get_uleb128 (value, r); + if (r > q) + break; + } + if (tag == 32 || (tag & 1) != 0) + { + r = memchr (r, '\0', q - r); + if (r == NULL) + break; + ++r; + } + + const char *tag_name = NULL; + const char *value_name = NULL; + ebl_check_object_attribute (ebl, (const char *) name, + tag, value, + &tag_name, &value_name); + + if (tag_name != NULL) + { + if (tag == 32) + printf (gettext (" %s: %" PRId64 ", %s\n"), + tag_name, value, string); + else if (string == NULL && value_name == NULL) + printf (gettext (" %s: %" PRId64 "\n"), + tag_name, value); + else + printf (gettext (" %s: %s\n"), + tag_name, string ?: value_name); + } + else + { + assert (tag != 32); + if (string == NULL) + printf (gettext (" %u: %" PRId64 "\n"), + tag, value); + else + printf (gettext (" %u: %s\n"), + tag, string); + } + } + } + } + } + } +} + static char * format_dwarf_addr (Dwfl_Module *dwflmod, @@ -5426,7 +5590,7 @@ compare_core_item_groups (const void *a, const void *b) } static unsigned int -handle_core_items (Elf *core, const void *desc, +handle_core_items (Elf *core, const void *desc, size_t descsz, const Ebl_Core_Item *items, size_t nitems) { if (nitems == 0) @@ -5450,18 +5614,35 @@ handle_core_items (Elf *core, const void *desc, /* Write out all the groups. */ unsigned int colno = 0; - for (size_t i = 0; i < ngroups; ++i) + + do { - 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); + 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; + } - /* Force a line break at the end of the group. */ - colno = ITEM_WRAP_COLUMN; + if (descsz == 0) + break; + + /* This set of items consumed a certain amount of the note's data. + If there is more data there, we have another unit of the same size. + Loop to print that out too. */ + const Ebl_Core_Item *item = &items[nitems - 1]; + size_t eltsz = item->offset + gelf_fsize (core, item->type, + item->count ?: 1, EV_CURRENT); + descsz -= eltsz; + desc += eltsz; } + while (descsz > 0); return colno; } @@ -5807,7 +5988,13 @@ handle_core_note (Ebl *ebl, const GElf_Nhdr *nhdr, const void *desc) ®s_offset, &nregloc, ®locs, &nitems, &items)) return; - unsigned int colno = handle_core_items (ebl->elf, desc, items, nitems); + /* Pass 0 for DESCSZ when there are registers in the note, + so that the ITEMS array does not describe the whole thing. + For non-register notes, the actual descsz might be a multiple + of the unit size, not just exactly the unit size. */ + unsigned int colno = handle_core_items (ebl->elf, desc, + nregloc == 0 ? nhdr->n_descsz : 0, + items, nitems); if (colno != 0) putchar_unlocked ('\n'); diff --git a/tests/ChangeLog b/tests/ChangeLog index 97865b5..f4bedcb 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,9 @@ +2008-02-20 Roland McGrath + + * testfile46.bz2: New data file. + * Makefile.am (EXTRA_DIST): Add it. + * run-elflint-test.sh: Test on it. + 2008-02-01 Ulrich Drepper * Makefile.am: Hook up sha1-tst.c. diff --git a/tests/Makefile.am b/tests/Makefile.am index 5d5c918..a058e58 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -136,7 +136,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ testfile38.bz2 testfile39.bz2 testfile40.bz2 testfile40.debug.bz2 \ testfile41.bz2 testfile42.bz2 testfile43.bz2 \ testfile44.S.bz2 testfile44.expect.bz2 run-disasm-x86.sh \ - testfile45.S.bz2 testfile45.expect.bz2 run-disasm-x86-64.sh + testfile45.S.bz2 testfile45.expect.bz2 run-disasm-x86-64.sh \ + testfile46.bz2 installed_TESTS_ENVIRONMENT = libdir=$(DESTDIR)$(libdir) \ bindir=$(DESTDIR)$(bindir) \ diff --git a/tests/run-elflint-test.sh b/tests/run-elflint-test.sh index a0b93a2..9f45d51 100755 --- a/tests/run-elflint-test.sh +++ b/tests/run-elflint-test.sh @@ -1,5 +1,5 @@ #! /bin/sh -# Copyright (C) 2005, 2007 Red Hat, Inc. +# Copyright (C) 2005, 2007, 2008 Red Hat, Inc. # This file is part of Red Hat elfutils. # Written by Ulrich Drepper , 2005. # @@ -41,4 +41,7 @@ testrun ../src/elflint -q testfile33 testfiles testfile42 testrun ../src/elflint -q --gnu-ld testfile42 +testfiles testfile47 +testrun ../src/elflint -q testfile47 + exit 0 diff --git a/tests/testfile46.bz2 b/tests/testfile46.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..db83b278c5a86808592b6d55293c12fad9031cdc GIT binary patch literal 322 zcmV-I0lof0T4*^jL0KkKSpx9!^8f(&f5!j#d*f7>L!?mr4qHVa==I0ob%7 literal 0 HcmV?d00001 -- 2.7.4