summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRoland McGrath <[email protected]>2008-02-21 06:19:39 +0000
committerRoland McGrath <[email protected]>2008-02-21 06:19:39 +0000
commit059c83e5db89955913a39fe6705acca571c32c3f (patch)
tree9eaf08fd255365d45be91bb3bf288194ffa423e5 /src
parent712d78eced9020ccfa1c27d32c2929cf16398293 (diff)
Finish elflint .gnu.attributes checking
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog24
-rw-r--r--src/elfcmp.c6
-rw-r--r--src/elflint.c201
-rw-r--r--src/readelf.c211
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)
&regs_offset, &nregloc, &reglocs, &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');