diff options
| author | Roland McGrath <[email protected]> | 2008-02-21 06:19:39 +0000 |
|---|---|---|
| committer | Roland McGrath <[email protected]> | 2008-02-21 06:19:39 +0000 |
| commit | 059c83e5db89955913a39fe6705acca571c32c3f (patch) | |
| tree | 9eaf08fd255365d45be91bb3bf288194ffa423e5 /src | |
| parent | 712d78eced9020ccfa1c27d32c2929cf16398293 (diff) | |
Finish elflint .gnu.attributes checking
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 24 | ||||
| -rw-r--r-- | src/elfcmp.c | 6 | ||||
| -rw-r--r-- | src/elflint.c | 201 | ||||
| -rw-r--r-- | src/readelf.c | 211 |
4 files changed, 427 insertions, 15 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index d3e49e41..f28c7006 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,21 @@ +2008-02-20 Roland McGrath <[email protected]> + + * 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 <[email protected]> + + * elflint.c (special_sections): Handle .gnu.attributes section. + (check_sections): Likewise. + (check_attributes): New function. + +2008-02-10 Roland McGrath <[email protected]> + + * elfcmp.c (main): Ignore sh_offset differences in non-SHF_ALLOC + sections and ET_REL files. + 2008-02-02 Ulrich Drepper <[email protected]> * elf32-i386.script: Add .eh_frame_hdr, .tdata, and .tbss sections. @@ -110,6 +128,12 @@ 2008-01-04 Roland McGrath <[email protected]> + * 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 <[email protected]> + * strip.c (handle_elf): Move SHDRIDX defn to silence gcc warning. 2008-01-03 Roland McGrath <[email protected]> diff --git a/src/elfcmp.c b/src/elfcmp.c index be9aaccd..0e134df8 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 <[email protected]>, 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 b65170ce..9a1a7179 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -46,7 +46,12 @@ #include <elf-knowledge.h> #include <system.h> +#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 90c460f9..0f0773c8 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 <[email protected]>, 1999. @@ -52,6 +52,7 @@ #include <system.h> #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'); |
