diff options
-rw-r--r-- | libebl/ChangeLog | 8 | ||||
-rw-r--r-- | libebl/eblobjnote.c | 151 | ||||
-rw-r--r-- | libebl/eblobjnotetypename.c | 25 | ||||
-rw-r--r-- | libebl/libebl.h | 4 | ||||
-rw-r--r-- | libelf/ChangeLog | 9 | ||||
-rw-r--r-- | libelf/elf-knowledge.h | 21 | ||||
-rw-r--r-- | src/ChangeLog | 8 | ||||
-rw-r--r-- | src/elflint.c | 13 | ||||
-rw-r--r-- | src/readelf.c | 16 | ||||
-rw-r--r-- | tests/ChangeLog | 4 | ||||
-rwxr-xr-x | tests/run-readelf-n.sh | 55 |
11 files changed, 308 insertions, 6 deletions
diff --git a/libebl/ChangeLog b/libebl/ChangeLog index 076596f0..79a2ff4c 100644 --- a/libebl/ChangeLog +++ b/libebl/ChangeLog @@ -1,3 +1,11 @@ +2018-11-12 Mark Wielaard <mark@klomp.org> + + * libebl.h (ebl_object_note): Add new argument namesz. + * eblobjnote.c (ebl_object_note): Likewise and handle GNU Build + Attribute notes. + * eblobjnotetypename.c (ebl_object_note_type_name): Handle GNU + Build Attribute notes. + 2018-11-11 Mark Wielaard <mark@klomp.org> * eblobjnote.c (ebl_object_note): Recognize NT_VERSION with zero diff --git a/libebl/eblobjnote.c b/libebl/eblobjnote.c index 8fda7d99..58ac86d7 100644 --- a/libebl/eblobjnote.c +++ b/libebl/eblobjnote.c @@ -37,11 +37,14 @@ #include <string.h> #include <libeblP.h> +#include "common.h" #include "libelfP.h" +#include "libdwP.h" +#include "memory-access.h" void -ebl_object_note (Ebl *ebl, const char *name, uint32_t type, +ebl_object_note (Ebl *ebl, uint32_t namesz, const char *name, uint32_t type, uint32_t descsz, const char *desc) { if (! ebl->object_note (name, type, descsz, desc)) @@ -135,6 +138,152 @@ ebl_object_note (Ebl *ebl, const char *name, uint32_t type, return; } + if (strncmp (name, ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX, + strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)) == 0 + && (type == NT_GNU_BUILD_ATTRIBUTE_OPEN + || type == NT_GNU_BUILD_ATTRIBUTE_FUNC)) + { + /* There might or might not be a pair of addresses in the desc. */ + if (descsz > 0) + { + printf (" Address Range: "); + + union + { + Elf64_Addr a64[2]; + Elf32_Addr a32[2]; + } addrs; + + size_t addr_size = gelf_fsize (ebl->elf, ELF_T_ADDR, + 2, EV_CURRENT); + if (descsz != addr_size) + printf ("<unknown data>\n"); + else + { + Elf_Data src = + { + .d_type = ELF_T_ADDR, .d_version = EV_CURRENT, + .d_buf = (void *) desc, .d_size = descsz + }; + + Elf_Data dst = + { + .d_type = ELF_T_ADDR, .d_version = EV_CURRENT, + .d_buf = &addrs, .d_size = descsz + }; + + if (gelf_xlatetom (ebl->elf, &dst, &src, + elf_getident (ebl->elf, + NULL)[EI_DATA]) == NULL) + printf ("%s\n", elf_errmsg (-1)); + else + { + if (addr_size == 4) + printf ("%#" PRIx32 " - %#" PRIx32 "\n", + addrs.a32[0], addrs.a32[1]); + else + printf ("%#" PRIx64 " - %#" PRIx64 "\n", + addrs.a64[0], addrs.a64[1]); + } + } + } + + /* Most data actually is inside the name. + https://fedoraproject.org/wiki/Toolchain/Watermark */ + + /* We need at least 2 chars of data to describe the + attribute and value encodings. */ + const char *data = (name + + strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)); + if (namesz < 2) + { + printf ("<insufficient data>\n"); + return; + } + + printf (" "); + + /* In most cases the value comes right after the encoding bytes. */ + const char *value = &data[2]; + switch (data[1]) + { + case GNU_BUILD_ATTRIBUTE_VERSION: + printf ("VERSION: "); + break; + case GNU_BUILD_ATTRIBUTE_STACK_PROT: + printf ("STACK_PROT: "); + break; + case GNU_BUILD_ATTRIBUTE_RELRO: + printf ("RELRO: "); + break; + case GNU_BUILD_ATTRIBUTE_STACK_SIZE: + printf ("STACK_SIZE: "); + break; + case GNU_BUILD_ATTRIBUTE_TOOL: + printf ("TOOL: "); + break; + case GNU_BUILD_ATTRIBUTE_ABI: + printf ("ABI: "); + break; + case GNU_BUILD_ATTRIBUTE_PIC: + printf ("PIC: "); + break; + case GNU_BUILD_ATTRIBUTE_SHORT_ENUM: + printf ("SHORT_ENUM: "); + break; + case 32 ... 126: + printf ("\"%s\": ", &data[1]); + value += strlen (&data[1]) + 1; + break; + default: + printf ("<unknown>: "); + break; + } + + switch (data[0]) + { + case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC: + { + /* Any numbers are always in (unsigned) little endian. */ + static const Dwarf dbg + = { .other_byte_order = MY_ELFDATA != ELFDATA2LSB }; + size_t bytes = namesz - (value - name); + uint64_t val; + if (bytes == 1) + val = *(unsigned char *) value; + else if (bytes == 2) + val = read_2ubyte_unaligned (&dbg, value); + else if (bytes == 4) + val = read_4ubyte_unaligned (&dbg, value); + else if (bytes == 8) + val = read_8ubyte_unaligned (&dbg, value); + else + goto unknown; + printf ("%" PRIx64, val); + } + break; + case GNU_BUILD_ATTRIBUTE_TYPE_STRING: + printf ("\"%s\"", value); + break; + case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE: + printf ("TRUE"); + break; + case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE: + printf ("FALSE"); + break; + default: + { + unknown: + printf ("<unknown>"); + } + break; + } + + printf ("\n"); + + return; + } + /* NT_VERSION doesn't have any info. All data is in the name. */ if (descsz == 0 && type == NT_VERSION) return; diff --git a/libebl/eblobjnotetypename.c b/libebl/eblobjnotetypename.c index 8cdd7819..29a5391c 100644 --- a/libebl/eblobjnotetypename.c +++ b/libebl/eblobjnotetypename.c @@ -1,5 +1,5 @@ /* Return note type name. - Copyright (C) 2002, 2007, 2009, 2011, 2016 Red Hat, Inc. + Copyright (C) 2002, 2007, 2009, 2011, 2016, 2018 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2002. @@ -79,6 +79,29 @@ ebl_object_note_type_name (Ebl *ebl, const char *name, uint32_t type, } } + if (strncmp (name, ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX, + strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)) == 0) + { + /* GNU Build Attribute notes (ab)use the owner name to store + most of their data. Don't decode everything here. Just + the type.*/ + char *t = buf; + const char *gba = "GNU Build Attribute"; + int w = snprintf (t, len, "%s ", gba); + t += w; + len -= w; + if (type == NT_GNU_BUILD_ATTRIBUTE_OPEN) + w = snprintf (t, len, "OPEN"); + else if (type == NT_GNU_BUILD_ATTRIBUTE_FUNC) + w = snprintf (t, len, "FUNC"); + else + w = snprintf (t, len, "%x", type); + t += w; + len -= w; + + return buf; + } + if (strcmp (name, "GNU") != 0) { /* NT_VERSION is special, all data is in the name. */ diff --git a/libebl/libebl.h b/libebl/libebl.h index 58306547..ca9b9fec 100644 --- a/libebl/libebl.h +++ b/libebl/libebl.h @@ -179,8 +179,8 @@ extern const char *ebl_object_note_type_name (Ebl *ebl, const char *name, char *buf, size_t len); /* 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); +extern void ebl_object_note (Ebl *ebl, uint32_t namesz, 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. diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 53da9a65..2675ba55 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,12 @@ +2018-11-12 Mark Wielaard <mark@klomp.org> + + * elf-knowledge.c (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX): New define. + (NT_GNU_BUILD_ATTRIBUTE_{OPEN,FUNC}): Likewise. + (GNU_BUILD_ATTRIBUTE_TYPE_{NUMERIC,STRING,BOOL_TRUE,BOOL_FALSE}): + Likewise. + (GNU_BUILD_ATTRIBUTE_{VERSION,STACK_PROT,RELRO,STACK_SIZE,TOOL,ABI, + PIC,SHORT_ENUM}): Likewise. + 2018-11-09 Mark Wielaard <mark@klomp.org> * elf_compress.c (__libelf_reset_rawdata): Make rawdata change diff --git a/libelf/elf-knowledge.h b/libelf/elf-knowledge.h index 64f58878..9d3be0ff 100644 --- a/libelf/elf-knowledge.h +++ b/libelf/elf-knowledge.h @@ -77,4 +77,25 @@ || ((Ehdr)->e_machine == EM_S390 \ && (Ehdr)->e_ident[EI_CLASS] == ELFCLASS64) ? 8 : 4) +/* GNU Annobin notes are not fully standardized and abuses the owner name. */ + +#define ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX "GA" + +#define NT_GNU_BUILD_ATTRIBUTE_OPEN 0x100 +#define NT_GNU_BUILD_ATTRIBUTE_FUNC 0x101 + +#define GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC '*' +#define GNU_BUILD_ATTRIBUTE_TYPE_STRING '$' +#define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE '+' +#define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE '!' + +#define GNU_BUILD_ATTRIBUTE_VERSION 1 +#define GNU_BUILD_ATTRIBUTE_STACK_PROT 2 +#define GNU_BUILD_ATTRIBUTE_RELRO 3 +#define GNU_BUILD_ATTRIBUTE_STACK_SIZE 4 +#define GNU_BUILD_ATTRIBUTE_TOOL 5 +#define GNU_BUILD_ATTRIBUTE_ABI 6 +#define GNU_BUILD_ATTRIBUTE_PIC 7 +#define GNU_BUILD_ATTRIBUTE_SHORT_ENUM 8 + #endif /* elf-knowledge.h */ diff --git a/src/ChangeLog b/src/ChangeLog index 0ed86bbf..f014de8f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2018-11-12 Mark Wielaard <mark@klomp.org> + + * elflint.c (check_note_data): Recognize NT_GNU_BUILD_ATTRIBUTE_OPEN + and NT_GNU_BUILD_ATTRIBUTE_OPEN. + * readelf.c (handle_notes_data): Handle + ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX. Pass nhdr.n_namesz to + ebl_object_note. + 2018-11-11 Mark Wielaard <mark@klomp.org> * readelf.c (handle_notes_data): Pass n_descsz to diff --git a/src/elflint.c b/src/elflint.c index dff74eee..184ca125 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -4344,6 +4344,19 @@ section [%2d] '%s': unknown core file note type %" PRIu32 } goto unknown_note; + case NT_GNU_BUILD_ATTRIBUTE_OPEN: + case NT_GNU_BUILD_ATTRIBUTE_FUNC: + /* GNU Build Attributes store most data in the owner + name, which must start with the + ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX "GA". */ + if (nhdr.n_namesz >= sizeof ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX + && strncmp (data->d_buf + name_offset, + ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX, + strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)) == 0) + break; + else + goto unknown_note; + case 0: /* Linux vDSOs use a type 0 note for the kernel version word. */ if (nhdr.n_namesz == sizeof "Linux" diff --git a/src/readelf.c b/src/readelf.c index 659e34fb..3a73710f 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -12193,10 +12193,21 @@ handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr, const char *name = nhdr.n_namesz == 0 ? "" : data->d_buf + name_offset; const char *desc = data->d_buf + desc_offset; + /* GNU Build Attributes are weird, they store most of their data + into the owner name field. Extract just the owner name + prefix here, then use the rest later as data. */ + bool is_gnu_build_attr + = strncmp (name, ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX, + strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)) == 0; + const char *print_name = (is_gnu_build_attr + ? ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX : name); + size_t print_namesz = (is_gnu_build_attr + ? strlen (print_name) : nhdr.n_namesz); + char buf[100]; char buf2[100]; printf (gettext (" %-13.*s %9" PRId32 " %s\n"), - (int) nhdr.n_namesz, name, nhdr.n_descsz, + (int) print_namesz, print_name, nhdr.n_descsz, ehdr->e_type == ET_CORE ? ebl_core_note_type_name (ebl, nhdr.n_type, buf, sizeof (buf)) @@ -12237,7 +12248,8 @@ handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr, handle_core_note (ebl, &nhdr, name, desc); } else - ebl_object_note (ebl, name, nhdr.n_type, nhdr.n_descsz, desc); + ebl_object_note (ebl, nhdr.n_namesz, name, nhdr.n_type, + nhdr.n_descsz, desc); } } diff --git a/tests/ChangeLog b/tests/ChangeLog index d92b8e3a..e6a9bde4 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2018-11-12 Mark Wielaard <mark@klomp.org> + + * run-readelf-n.sh: Add testfile-annobingroup.o test. + 2018-11-11 Mark Wielaard <mark@klomp.org> * run-readelf-n.sh: Fix NT_GNU_ABI_TAG type. Add testfile11 test diff --git a/tests/run-readelf-n.sh b/tests/run-readelf-n.sh index 7e2a845e..c2db2ce2 100755 --- a/tests/run-readelf-n.sh +++ b/tests/run-readelf-n.sh @@ -70,3 +70,58 @@ Note section [35] '.note' of 60 bytes at offset 0x13364: 01.01 0 VERSION 01.01 0 VERSION EOF + +# See run-annobingroup.sh +testfiles testfile-annobingroup.o +testrun_compare ${abs_top_builddir}/src/readelf -n testfile-annobingroup.o << EOF + +Note section [ 5] '.gnu.build.attributes' of 272 bytes at offset 0x50: + Owner Data size Type + GA 16 GNU Build Attribute OPEN + Address Range: 0 - 0 + VERSION: "3p8" + GA 0 GNU Build Attribute OPEN + TOOL: "gcc 8.1.1 20180712" + GA 0 GNU Build Attribute OPEN + "GOW": 5 + GA 0 GNU Build Attribute OPEN + STACK_PROT: 0 + GA 0 GNU Build Attribute OPEN + "stack_clash": FALSE + GA 0 GNU Build Attribute OPEN + "cf_protection": 0 + GA 0 GNU Build Attribute OPEN + PIC: 0 + GA 0 GNU Build Attribute OPEN + SHORT_ENUM: FALSE + GA 0 GNU Build Attribute OPEN + ABI: c001100000012 + GA 0 GNU Build Attribute OPEN + "stack_realign": FALSE + +Note section [ 7] '.gnu.build.attributes..text.unlikely' of 216 bytes at offset 0x160: + Owner Data size Type + GA 16 GNU Build Attribute FUNC + Address Range: 0 - 0 + ABI: c001100000012 + GA 0 GNU Build Attribute FUNC + "stack_realign": FALSE + GA 0 GNU Build Attribute FUNC + STACK_PROT: 0 + GA 0 GNU Build Attribute FUNC + "stack_clash": FALSE + GA 0 GNU Build Attribute FUNC + "cf_protection": 0 + GA 0 GNU Build Attribute FUNC + PIC: 0 + GA 0 GNU Build Attribute FUNC + "GOW": 5 + GA 0 GNU Build Attribute FUNC + SHORT_ENUM: FALSE + +Note section [22] '.note.gnu.property' of 48 bytes at offset 0x40c: + Owner Data size Type + GNU 32 GNU_PROPERTY_TYPE_0 + X86 0xc0000000 data: 00 00 00 00 + X86 0xc0000001 data: 00 00 00 00 +EOF |