From a39405c33ba268b1fd5effd6b1a9a977995ca159 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Thu, 15 Nov 2018 00:55:41 +0100 Subject: [PATCH] 0.174-5 Add elfutils-0.174-gnu-attribute-note.patch --- elfutils-0.174-gnu-attribute-note.patch | 373 ++++++++++++++++++++++++ elfutils.spec | 7 +- 2 files changed, 378 insertions(+), 2 deletions(-) create mode 100644 elfutils-0.174-gnu-attribute-note.patch diff --git a/elfutils-0.174-gnu-attribute-note.patch b/elfutils-0.174-gnu-attribute-note.patch new file mode 100644 index 0000000..ae884a6 --- /dev/null +++ b/elfutils-0.174-gnu-attribute-note.patch @@ -0,0 +1,373 @@ +commit 72e30c2e0cb49a9a300667fdd5ff09082f717950 +Author: Mark Wielaard +Date: Mon Nov 12 23:34:24 2018 +0100 + + Handle GNU Build Attribute ELF Notes. + + GNU Build Attribute ELF Notes are generated by the GCC annobin plugin + and described at https://fedoraproject.org/wiki/Toolchain/Watermark + + Unfortunately the constants aren't yet described in the standard glibc + elf.h so they have been added to the elfutils specific elf-knowledge.h. + + The notes abuse the name owner field to encode some data not in the + description. This makes it a bit hard to parse. We have to match the + note owner name prefix (to "GA") to be sure the type is valid. We also + cannot rely on the owner name being a valid C string since the attribute + name and value can contain zero (terminators). So pass around namesz + to the ebl note parsing functions. + + eu-elflint will recognize and eu-readelf -n will now show the notes: + + Note section [27] '.gnu.build.attributes' of 56080 bytes at offset 0x114564: + Owner Data size Type + GA 16 GNU Build Attribute OPEN + Address Range: 0x2f30f - 0x2f30f + VERSION: "3p8" + GA 0 GNU Build Attribute OPEN + TOOL: "gcc 8.2.1 20180801" + GA 0 GNU Build Attribute OPEN + "GOW": 45 + GA 0 GNU Build Attribute OPEN + STACK_PROT: 0 + GA 0 GNU Build Attribute OPEN + "stack_clash": TRUE + GA 0 GNU Build Attribute OPEN + "cf_protection": 0 + GA 0 GNU Build Attribute OPEN + "GLIBCXX_ASSERTIONS": TRUE + GA 0 GNU Build Attribute OPEN + "FORTIFY": 0 + GA 0 GNU Build Attribute OPEN + PIC: 3 + 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 + + A new test was added to run-readelf -n for the existing annobin file. + + Signed-off-by: Mark Wielaard + +diff --git a/libebl/eblobjnote.c b/libebl/eblobjnote.c +index 8fda7d9..58ac86d 100644 +--- a/libebl/eblobjnote.c ++++ b/libebl/eblobjnote.c +@@ -37,11 +37,14 @@ + #include + #include + ++#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 ("\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 ("\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 (": "); ++ 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 (""); ++ } ++ 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 8cdd781..29a5391 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 , 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 5830654..ca9b9fe 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/elf-knowledge.h b/libelf/elf-knowledge.h +index 64f5887..9d3be0f 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/elflint.c b/src/elflint.c +index dff74ee..184ca12 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 659e34f..3a73710 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/elfutils.spec b/elfutils.spec index 5814cd5..aa17080 100644 --- a/elfutils.spec +++ b/elfutils.spec @@ -1,7 +1,7 @@ Name: elfutils Summary: A collection of utilities and DSOs to handle ELF files and DWARF data Version: 0.174 -%global baserelease 4 +%global baserelease 5 URL: http://elfutils.org/ %global source_url ftp://sourceware.org/pub/elfutils/%{version}/ License: GPLv3+ and (GPLv2+ or LGPLv3+) @@ -28,6 +28,7 @@ Patch5: elfutils-0.174-ar-sh_entsize-zero.patch Patch6: elfutils-0.174-x86_64_unwind.patch Patch7: elfutils-0.174-gnu-property-note.patch Patch8: elfutils-0.174-version-note.patch +Patch9: elfutils-0.174-gnu-attribute-note.patch Requires: elfutils-libelf%{depsuffix} = %{version}-%{release} Requires: elfutils-libs%{depsuffix} = %{version}-%{release} @@ -204,6 +205,7 @@ profiling) of processes. %patch6 -p1 -b .x86_64_unwind %patch7 -p1 -b .gnu_prop_note %patch8 -p1 -b .version_note +%patch9 -p1 -b .gnu_attr_note # In case the above patches added any new test scripts, make sure they # are executable. @@ -336,10 +338,11 @@ fi %endif %changelog -* Wed Nov 14 2018 Mark Wielaard +* Wed Nov 14 2018 Mark Wielaard - 0.174-5 - Add elfutils-0.174-x86_64_unwind.patch. - Add elfutils-0.174-gnu-property-note.patch. - Add elfutils-0.174-version-note.patch. +- Add elfutils-0.174-gnu-attribute-note.patch * Tue Nov 6 2018 Mark Wielaard - 0.174-4 - Add elfutils-0.174-size-rec-ar.patch