summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libebl/ChangeLog8
-rw-r--r--libebl/eblobjnote.c151
-rw-r--r--libebl/eblobjnotetypename.c25
-rw-r--r--libebl/libebl.h4
-rw-r--r--libelf/ChangeLog9
-rw-r--r--libelf/elf-knowledge.h21
-rw-r--r--src/ChangeLog8
-rw-r--r--src/elflint.c13
-rw-r--r--src/readelf.c16
-rw-r--r--tests/ChangeLog4
-rwxr-xr-xtests/run-readelf-n.sh55
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