import elfutils-0.174-6.el8

This commit is contained in:
CentOS Sources 2019-05-07 05:34:42 -04:00 committed by Andrew Lukoshko
commit 8e5aac4212
13 changed files with 3262 additions and 0 deletions

1
.elfutils.metadata Normal file
View File

@ -0,0 +1 @@
95899ce5fa55002e46bf4e02d01a249516e296fd SOURCES/elfutils-0.174.tar.bz2

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
SOURCES/elfutils-0.174.tar.bz2

View File

@ -0,0 +1,17 @@
diff --git a/src/elflint.c b/src/elflint.c
index eec799b2..31092f2e 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -3905,10 +3905,11 @@ section [%2zu] '%s': size not multiple of entry size\n"),
cnt, section_name (ebl, cnt),
(int) shdr->sh_type);
+#define SHF_GNU_BUILD_NOTE (1 << 20)
#define ALL_SH_FLAGS (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE \
| SHF_STRINGS | SHF_INFO_LINK | SHF_LINK_ORDER \
| SHF_OS_NONCONFORMING | SHF_GROUP | SHF_TLS \
- | SHF_COMPRESSED)
+ | SHF_COMPRESSED | SHF_GNU_BUILD_NOTE)
if (shdr->sh_flags & ~(GElf_Xword) ALL_SH_FLAGS)
{
GElf_Xword sh_flags = shdr->sh_flags & ~(GElf_Xword) ALL_SH_FLAGS;

View File

@ -0,0 +1,27 @@
commit 2b16a9be69939822dcafe075413468daac98b327
Author: Mark Wielaard <mark@klomp.org>
Date: Thu Oct 18 19:01:52 2018 +0200
arlib: Check that sh_entsize isn't zero.
A bogus ELF file could have sh_entsize as zero. Don't divide by zero,
but just assume there are no symbols in the section.
https://sourceware.org/bugzilla/show_bug.cgi?id=23786
Signed-off-by: Mark Wielaard <mark@klomp.org>
diff --git a/src/arlib.c b/src/arlib.c
index 778e087..a6521e3 100644
--- a/src/arlib.c
+++ b/src/arlib.c
@@ -252,6 +252,9 @@ arlib_add_symbols (Elf *elf, const char *arfname, const char *membername,
if (data == NULL)
continue;
+ if (shdr->sh_entsize == 0)
+ continue;
+
int nsyms = shdr->sh_size / shdr->sh_entsize;
for (int ndx = shdr->sh_info; ndx < nsyms; ++ndx)
{

View File

@ -0,0 +1,373 @@
commit 72e30c2e0cb49a9a300667fdd5ff09082f717950
Author: Mark Wielaard <mark@klomp.org>
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 <mark@klomp.org>
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 <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 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 <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 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);
}
}

View File

@ -0,0 +1,820 @@
commit 5199e15870e05e5b0b9f98c20fc9b5427aa6dd6a
Author: Mark Wielaard <mark@klomp.org>
Date: Mon Oct 15 23:35:47 2018 +0200
Recognize and parse GNU Property notes.
GNU Property notes are different from normal notes because they use
variable alignment/padding of their fields. They are 8 byte aligned,
but use 4 byte fields. The name is aligned at 4 bytes and padded so
that, the desc is aligned at 8 bytes. The whole note is padded to
8 bytes again. For normal notes all fields are both 4 bytes wide and
4 bytes aligned.
To recognize these new kind of ELF Notes a new Elf_Type is introduced,
ELF_T_NHDR8. This type is used in the xlate functions to determine
how to align and pad the various fields. Since the fields themselves
can now have different alignments we will have to keep track of the
current alignement and use either NOTE_ALIGN4 or NOTE_ALIGN8 to
determine the padding.
To set the correct Elf_Type on the Elf_Data we use either the section
sh_addralign or the segment p_align values. Assuming 8 means the
section or segment contains the new style notes, otherwise normal
notes.
When we cannot determine the "alignment" directly, like when parsing
special kernel sys files, we check the name "GNU" and type
"GNU_PROPERTY_TYPE_0" fields.
ebl_object_note now parses the new NT_GNU_PROPERTY_TYPE_0 and can
extract the GNU_PROPERTY_STACK_SIZE, GNU_PROPERTY_NO_COPY_ON_PROTECTED
and GNU_PROPERTY_X86_FEATURE_1_AND types GNU_PROPERTY_X86_FEATURE_1_IBT
and GNU_PROPERTY_X86_FEATURE_1_SHSTK.
Tests are added for extracting the note from sections or segments
as set by gcc -fcf-protection.
Signed-off-by: Mark Wielaard <mark@klomp.org>
diff --git a/libdwelf/dwelf_elf_gnu_build_id.c b/libdwelf/dwelf_elf_gnu_build_id.c
index 8c78c70..dbcfc82 100644
--- a/libdwelf/dwelf_elf_gnu_build_id.c
+++ b/libdwelf/dwelf_elf_gnu_build_id.c
@@ -88,7 +88,9 @@ find_elf_build_id (Dwfl_Module *mod, int e_type, Elf *elf,
result = check_notes (elf_getdata_rawchunk (elf,
phdr->p_offset,
phdr->p_filesz,
- ELF_T_NHDR),
+ (phdr->p_align == 8
+ ? ELF_T_NHDR8
+ : ELF_T_NHDR)),
phdr->p_vaddr,
build_id_bits,
build_id_elfaddr,
diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c
index 84cb89a..01109f4 100644
--- a/libdwfl/core-file.c
+++ b/libdwfl/core-file.c
@@ -496,7 +496,9 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable)
Elf_Data *notes = elf_getdata_rawchunk (elf,
notes_phdr.p_offset,
notes_phdr.p_filesz,
- ELF_T_NHDR);
+ (notes_phdr.p_align == 8
+ ? ELF_T_NHDR8
+ : ELF_T_NHDR));
if (likely (notes != NULL))
{
size_t pos = 0;
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index 8749884..0d633ff 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -27,7 +27,7 @@
not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
-#include "../libelf/libelfP.h" /* For NOTE_ALIGN. */
+#include "../libelf/libelfP.h" /* For NOTE_ALIGN4 and NOTE_ALIGN8. */
#undef _
#include "libdwflP.h"
#include "common.h"
@@ -451,7 +451,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
GElf_Addr build_id_vaddr = 0;
/* Consider a PT_NOTE we've found in the image. */
- inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz)
+ inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz,
+ GElf_Xword align)
{
/* If we have already seen a build ID, we don't care any more. */
if (build_id != NULL || filesz == 0)
@@ -478,7 +479,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
notes = malloc (filesz);
if (unlikely (notes == NULL))
return;
- xlatefrom.d_type = xlateto.d_type = ELF_T_NHDR;
+ xlatefrom.d_type = xlateto.d_type = (align == 8
+ ? ELF_T_NHDR8 : ELF_T_NHDR);
xlatefrom.d_buf = (void *) data;
xlatefrom.d_size = filesz;
xlateto.d_buf = notes;
@@ -489,15 +491,23 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
}
const GElf_Nhdr *nh = notes;
- while ((const void *) nh < (const void *) notes + filesz)
- {
- const void *note_name = nh + 1;
- const void *note_desc = note_name + NOTE_ALIGN (nh->n_namesz);
- if (unlikely ((size_t) ((const void *) notes + filesz
- - note_desc) < nh->n_descsz))
+ size_t len = 0;
+ while (filesz > len + sizeof (*nh))
+ {
+ const void *note_name;
+ const void *note_desc;
+
+ len += sizeof (*nh);
+ note_name = notes + len;
+
+ len += nh->n_namesz;
+ len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len);
+ note_desc = notes + len;
+
+ if (unlikely (filesz < len + nh->n_descsz))
break;
- if (nh->n_type == NT_GNU_BUILD_ID
+ if (nh->n_type == NT_GNU_BUILD_ID
&& nh->n_descsz > 0
&& nh->n_namesz == sizeof "GNU"
&& !memcmp (note_name, "GNU", sizeof "GNU"))
@@ -510,7 +520,9 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
break;
}
- nh = note_desc + NOTE_ALIGN (nh->n_descsz);
+ len += nh->n_descsz;
+ len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len);
+ nh = (void *) notes + len;
}
done:
@@ -535,7 +547,7 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
case PT_NOTE:
/* We calculate from the p_offset of the note segment,
because we don't yet know the bias for its p_vaddr. */
- consider_notes (start + offset, filesz);
+ consider_notes (start + offset, filesz, align);
break;
case PT_LOAD:
diff --git a/libdwfl/linux-core-attach.c b/libdwfl/linux-core-attach.c
index 9f05f72..6c99b9e 100644
--- a/libdwfl/linux-core-attach.c
+++ b/libdwfl/linux-core-attach.c
@@ -355,7 +355,9 @@ dwfl_core_file_attach (Dwfl *dwfl, Elf *core)
if (phdr != NULL && phdr->p_type == PT_NOTE)
{
note_data = elf_getdata_rawchunk (core, phdr->p_offset,
- phdr->p_filesz, ELF_T_NHDR);
+ phdr->p_filesz, (phdr->p_align == 8
+ ? ELF_T_NHDR8
+ : ELF_T_NHDR));
break;
}
}
diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
index 9d0fef2..360e4ee 100644
--- a/libdwfl/linux-kernel-modules.c
+++ b/libdwfl/linux-kernel-modules.c
@@ -39,6 +39,7 @@
#include <config.h>
#include <system.h>
+#include "libelfP.h"
#include "libdwflP.h"
#include <inttypes.h>
#include <errno.h>
@@ -554,15 +555,41 @@ check_notes (Dwfl_Module *mod, const char *notesfile,
return 1;
unsigned char *p = buf.data;
+ size_t len = 0;
while (p < &buf.data[n])
{
/* No translation required since we are reading the native kernel. */
GElf_Nhdr *nhdr = (void *) p;
- p += sizeof *nhdr;
+ len += sizeof *nhdr;
+ p += len;
unsigned char *name = p;
- p += (nhdr->n_namesz + 3) & -4U;
- unsigned char *bits = p;
- p += (nhdr->n_descsz + 3) & -4U;
+ unsigned char *bits;
+ /* This is somewhat ugly, GNU Property notes use different padding,
+ but all we have is the file content, so we have to actually check
+ the name and type. */
+ if (nhdr->n_type == NT_GNU_PROPERTY_TYPE_0
+ && nhdr->n_namesz == sizeof "GNU"
+ && name + nhdr->n_namesz < &buf.data[n]
+ && !memcmp (name, "GNU", sizeof "GNU"))
+ {
+ len += nhdr->n_namesz;
+ len = NOTE_ALIGN8 (len);
+ p = buf.data + len;
+ bits = p;
+ len += nhdr->n_descsz;
+ len = NOTE_ALIGN8 (len);
+ p = buf.data + len;
+ }
+ else
+ {
+ len += nhdr->n_namesz;
+ len = NOTE_ALIGN4 (len);
+ p = buf.data + len;
+ bits = p;
+ len += nhdr->n_descsz;
+ len = NOTE_ALIGN4 (len);
+ p = buf.data + len;
+ }
if (p <= &buf.data[n]
&& nhdr->n_type == NT_GNU_BUILD_ID
diff --git a/libebl/eblobjnote.c b/libebl/eblobjnote.c
index ca4f155..57e9f52 100644
--- a/libebl/eblobjnote.c
+++ b/libebl/eblobjnote.c
@@ -1,5 +1,5 @@
/* Print contents of object file note.
- Copyright (C) 2002, 2007, 2009, 2011, 2015, 2016 Red Hat, Inc.
+ Copyright (C) 2002, 2007, 2009, 2011, 2015, 2016, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -37,6 +37,8 @@
#include <string.h>
#include <libeblP.h>
+#include "libelfP.h"
+
void
ebl_object_note (Ebl *ebl, const char *name, uint32_t type,
@@ -153,6 +155,187 @@ ebl_object_note (Ebl *ebl, const char *name, uint32_t type,
(int) descsz, desc);
break;
+ case NT_GNU_PROPERTY_TYPE_0:
+ if (strcmp (name, "GNU") == 0 && descsz > 0)
+ {
+ /* There are at least 2 words. type and datasz. */
+ while (descsz >= 8)
+ {
+ struct pr_prop
+ {
+ GElf_Word pr_type;
+ GElf_Word pr_datasz;
+ } prop;
+
+ Elf_Data in =
+ {
+ .d_version = EV_CURRENT,
+ .d_type = ELF_T_WORD,
+ .d_size = 8,
+ .d_buf = (void *) desc
+ };
+ Elf_Data out =
+ {
+ .d_version = EV_CURRENT,
+ .d_type = ELF_T_WORD,
+ .d_size = descsz,
+ .d_buf = (void *) &prop
+ };
+
+ if (gelf_xlatetom (ebl->elf, &out, &in,
+ elf_getident (ebl->elf,
+ NULL)[EI_DATA]) == NULL)
+ {
+ printf ("%s\n", elf_errmsg (-1));
+ return;
+ }
+
+ desc += 8;
+ descsz -= 8;
+
+ int elfclass = gelf_getclass (ebl->elf);
+ char *elfident = elf_getident (ebl->elf, NULL);
+ GElf_Ehdr ehdr;
+ gelf_getehdr (ebl->elf, &ehdr);
+
+ /* Prefix. */
+ printf (" ");
+ if (prop.pr_type == GNU_PROPERTY_STACK_SIZE)
+ {
+ printf ("STACK_SIZE ");
+ if (prop.pr_datasz == 4 || prop.pr_datasz == 8)
+ {
+ GElf_Addr addr;
+ in.d_type = ELF_T_ADDR;
+ out.d_type = ELF_T_ADDR;
+ in.d_size = prop.pr_datasz;
+ out.d_size = sizeof (addr);
+ in.d_buf = (void *) desc;
+ out.d_buf = (void *) &addr;
+
+ if (gelf_xlatetom (ebl->elf, &out, &in,
+ elfident[EI_DATA]) == NULL)
+ {
+ printf ("%s\n", elf_errmsg (-1));
+ return;
+ }
+ printf ("%#" PRIx64 "\n", addr);
+ }
+ else
+ printf (" (garbage datasz: %" PRIx32 ")\n",
+ prop.pr_datasz);
+ }
+ else if (prop.pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED)
+ {
+ printf ("NO_COPY_ON_PROTECTION");
+ if (prop.pr_datasz == 0)
+ printf ("\n");
+ else
+ printf (" (garbage datasz: %" PRIx32 ")\n",
+ prop.pr_datasz);
+ }
+ else if (prop.pr_type >= GNU_PROPERTY_LOPROC
+ && prop.pr_type <= GNU_PROPERTY_HIPROC
+ && (ehdr.e_machine == EM_386
+ || ehdr.e_machine == EM_X86_64))
+ {
+ printf ("X86 ");
+ if (prop.pr_type == GNU_PROPERTY_X86_FEATURE_1_AND)
+ {
+ printf ("FEATURE_1_AND: ");
+
+ if (prop.pr_datasz == 4)
+ {
+ GElf_Word data;
+ in.d_type = ELF_T_WORD;
+ out.d_type = ELF_T_WORD;
+ in.d_size = 4;
+ out.d_size = 4;
+ in.d_buf = (void *) desc;
+ out.d_buf = (void *) &data;
+
+ if (gelf_xlatetom (ebl->elf, &out, &in,
+ elfident[EI_DATA]) == NULL)
+ {
+ printf ("%s\n", elf_errmsg (-1));
+ return;
+ }
+ printf ("%08" PRIx32 " ", data);
+
+ if ((data & GNU_PROPERTY_X86_FEATURE_1_IBT)
+ != 0)
+ {
+ printf ("IBT");
+ data &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
+ if (data != 0)
+ printf (" ");
+ }
+
+ if ((data & GNU_PROPERTY_X86_FEATURE_1_SHSTK)
+ != 0)
+ {
+ printf ("SHSTK");
+ data &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ if (data != 0)
+ printf (" ");
+ }
+
+ if (data != 0)
+ printf ("UNKNOWN");
+ }
+ else
+ printf ("<bad datasz: %" PRId32 ">",
+ prop.pr_datasz);
+
+ printf ("\n");
+ }
+ else
+ {
+ printf ("%#" PRIx32, prop.pr_type);
+ if (prop.pr_datasz > 0)
+ {
+ printf (" data: ");
+ size_t i;
+ for (i = 0; i < prop.pr_datasz - 1; i++)
+ printf ("%02" PRIx8 " ", (uint8_t) desc[i]);
+ printf ("%02" PRIx8 "\n", (uint8_t) desc[i]);
+ }
+ }
+ }
+ else
+ {
+ if (prop.pr_type >= GNU_PROPERTY_LOPROC
+ && prop.pr_type <= GNU_PROPERTY_HIPROC)
+ printf ("proc_type %#" PRIx32, prop.pr_type);
+ else if (prop.pr_type >= GNU_PROPERTY_LOUSER
+ && prop.pr_type <= GNU_PROPERTY_HIUSER)
+ printf ("app_type %#" PRIx32, prop.pr_type);
+ else
+ printf ("unknown_type %#" PRIx32, prop.pr_type);
+
+ if (prop.pr_datasz > 0)
+ {
+ printf (" data: ");
+ size_t i;
+ for (i = 0; i < prop.pr_datasz - 1; i++)
+ printf ("%02" PRIx8 " ", (uint8_t) desc[i]);
+ printf ("%02" PRIx8 "\n", (uint8_t) desc[i]);
+ }
+ }
+ if (elfclass == ELFCLASS32)
+ {
+ desc += NOTE_ALIGN4 (prop.pr_datasz);
+ descsz -= NOTE_ALIGN4 (prop.pr_datasz);
+ }
+ else
+ {
+ desc += NOTE_ALIGN8 (prop.pr_datasz);
+ descsz -= NOTE_ALIGN8 (prop.pr_datasz);
+ }
+ }
+ }
+ break;
+
case NT_GNU_ABI_TAG:
if (strcmp (name, "GNU") == 0 && descsz >= 8 && descsz % 4 == 0)
{
diff --git a/libebl/eblobjnotetypename.c b/libebl/eblobjnotetypename.c
index db040d2..af23cae 100644
--- a/libebl/eblobjnotetypename.c
+++ b/libebl/eblobjnotetypename.c
@@ -91,6 +91,7 @@ ebl_object_note_type_name (Ebl *ebl, const char *name, uint32_t type,
KNOWNSTYPE (GNU_HWCAP),
KNOWNSTYPE (GNU_BUILD_ID),
KNOWNSTYPE (GNU_GOLD_VERSION),
+ KNOWNSTYPE (GNU_PROPERTY_TYPE_0),
};
/* Handle standard names. */
diff --git a/libelf/elf32_xlatetom.c b/libelf/elf32_xlatetom.c
index 13cd485..3b94cac 100644
--- a/libelf/elf32_xlatetom.c
+++ b/libelf/elf32_xlatetom.c
@@ -60,7 +60,7 @@ elfw2(LIBELFBITS, xlatetom) (Elf_Data *dest, const Elf_Data *src,
/* We shouldn't require integer number of records when processing
notes. Payload bytes follow the header immediately, it's not an
array of records as is the case otherwise. */
- if (src->d_type != ELF_T_NHDR
+ if (src->d_type != ELF_T_NHDR && src->d_type != ELF_T_NHDR8
&& src->d_size % recsize != 0)
{
__libelf_seterrno (ELF_E_INVALID_DATA);
diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c
index 711be59..fd412e8 100644
--- a/libelf/elf_compress.c
+++ b/libelf/elf_compress.c
@@ -513,7 +513,8 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags)
__libelf_reset_rawdata (scn, scn->zdata_base,
scn->zdata_size, scn->zdata_align,
- __libelf_data_type (elf, sh_type));
+ __libelf_data_type (elf, sh_type,
+ scn->zdata_align));
return 1;
}
diff --git a/libelf/elf_compress_gnu.c b/libelf/elf_compress_gnu.c
index dfa7c57..198dc7d 100644
--- a/libelf/elf_compress_gnu.c
+++ b/libelf/elf_compress_gnu.c
@@ -196,7 +196,7 @@ elf_compress_gnu (Elf_Scn *scn, int inflate, unsigned int flags)
}
__libelf_reset_rawdata (scn, buf_out, size, sh_addralign,
- __libelf_data_type (elf, sh_type));
+ __libelf_data_type (elf, sh_type, sh_addralign));
scn->zdata_base = buf_out;
diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c
index 278dfa8..4f80aaf 100644
--- a/libelf/elf_getdata.c
+++ b/libelf/elf_getdata.c
@@ -65,7 +65,7 @@ static const Elf_Type shtype_map[EV_NUM - 1][TYPEIDX (SHT_HISUNW) + 1] =
[SHT_PREINIT_ARRAY] = ELF_T_ADDR,
[SHT_GROUP] = ELF_T_WORD,
[SHT_SYMTAB_SHNDX] = ELF_T_WORD,
- [SHT_NOTE] = ELF_T_NHDR,
+ [SHT_NOTE] = ELF_T_NHDR, /* Need alignment to guess ELF_T_NHDR8. */
[TYPEIDX (SHT_GNU_verdef)] = ELF_T_VDEF,
[TYPEIDX (SHT_GNU_verneed)] = ELF_T_VNEED,
[TYPEIDX (SHT_GNU_versym)] = ELF_T_HALF,
@@ -106,6 +106,7 @@ const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM]
[ELF_T_GNUHASH] = __alignof__ (Elf32_Word), \
[ELF_T_AUXV] = __alignof__ (ElfW2(Bits,auxv_t)), \
[ELF_T_CHDR] = __alignof__ (ElfW2(Bits,Chdr)), \
+ [ELF_T_NHDR8] = 8 /* Special case for GNU Property note. */ \
}
[EV_CURRENT - 1] =
{
@@ -118,7 +119,7 @@ const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM]
Elf_Type
internal_function
-__libelf_data_type (Elf *elf, int sh_type)
+__libelf_data_type (Elf *elf, int sh_type, GElf_Xword align)
{
/* Some broken ELF ABI for 64-bit machines use the wrong hash table
entry size. See elf-knowledge.h for more information. */
@@ -129,7 +130,13 @@ __libelf_data_type (Elf *elf, int sh_type)
return (SH_ENTSIZE_HASH (ehdr) == 4 ? ELF_T_WORD : ELF_T_XWORD);
}
else
- return shtype_map[LIBELF_EV_IDX][TYPEIDX (sh_type)];
+ {
+ Elf_Type t = shtype_map[LIBELF_EV_IDX][TYPEIDX (sh_type)];
+ /* Special case for GNU Property notes. */
+ if (t == ELF_T_NHDR && align == 8)
+ t = ELF_T_NHDR8;
+ return t;
+ }
}
/* Convert the data in the current section. */
@@ -272,7 +279,9 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn)
else
{
Elf_Type t = shtype_map[LIBELF_EV_IDX][TYPEIDX (type)];
- if (t == ELF_T_VDEF || t == ELF_T_NHDR
+ if (t == ELF_T_NHDR && align == 8)
+ t = ELF_T_NHDR8;
+ if (t == ELF_T_VDEF || t == ELF_T_NHDR || t == ELF_T_NHDR8
|| (t == ELF_T_GNUHASH && elf->class == ELFCLASS64))
entsize = 1;
else
@@ -357,7 +366,7 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn)
if ((flags & SHF_COMPRESSED) != 0)
scn->rawdata.d.d_type = ELF_T_CHDR;
else
- scn->rawdata.d.d_type = __libelf_data_type (elf, type);
+ scn->rawdata.d.d_type = __libelf_data_type (elf, type, align);
scn->rawdata.d.d_off = 0;
/* Make sure the alignment makes sense. d_align should be aligned both
diff --git a/libelf/gelf_fsize.c b/libelf/gelf_fsize.c
index 0c50926..d04ec5d 100644
--- a/libelf/gelf_fsize.c
+++ b/libelf/gelf_fsize.c
@@ -64,6 +64,8 @@ const size_t __libelf_type_sizes[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] =
[ELF_T_VNEED] = sizeof (ElfW2(LIBELFBITS, Ext_Verneed)), \
[ELF_T_VNAUX] = sizeof (ElfW2(LIBELFBITS, Ext_Vernaux)), \
[ELF_T_NHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Nhdr)), \
+ /* Note the header size is the same, but padding is different. */ \
+ [ELF_T_NHDR8] = sizeof (ElfW2(LIBELFBITS, Ext_Nhdr)), \
[ELF_T_SYMINFO] = sizeof (ElfW2(LIBELFBITS, Ext_Syminfo)), \
[ELF_T_MOVE] = sizeof (ElfW2(LIBELFBITS, Ext_Move)), \
[ELF_T_LIB] = sizeof (ElfW2(LIBELFBITS, Ext_Lib)), \
diff --git a/libelf/gelf_getnote.c b/libelf/gelf_getnote.c
index c75edda..6d33b35 100644
--- a/libelf/gelf_getnote.c
+++ b/libelf/gelf_getnote.c
@@ -1,5 +1,5 @@
/* Get note information at the supplied offset.
- Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
+ Copyright (C) 2007, 2014, 2015, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -43,7 +43,7 @@ gelf_getnote (Elf_Data *data, size_t offset, GElf_Nhdr *result,
if (data == NULL)
return 0;
- if (unlikely (data->d_type != ELF_T_NHDR))
+ if (unlikely (data->d_type != ELF_T_NHDR && data->d_type != ELF_T_NHDR8))
{
__libelf_seterrno (ELF_E_INVALID_HANDLE);
return 0;
@@ -69,27 +69,42 @@ gelf_getnote (Elf_Data *data, size_t offset, GElf_Nhdr *result,
const GElf_Nhdr *n = data->d_buf + offset;
offset += sizeof *n;
- /* Include padding. Check below for overflow. */
- GElf_Word namesz = NOTE_ALIGN (n->n_namesz);
- GElf_Word descsz = NOTE_ALIGN (n->n_descsz);
-
- if (unlikely (offset > data->d_size
- || data->d_size - offset < namesz
- || (namesz == 0 && n->n_namesz != 0)))
+ if (offset > data->d_size)
offset = 0;
else
{
+ /* This is slightly tricky, offset is guaranteed to be 4
+ byte aligned, which is what we need for the name_offset.
+ And normally desc_offset is also 4 byte aligned, but not
+ for GNU Property notes, then it should be 8. So align
+ the offset, after adding the namesz, and include padding
+ in descsz to get to the end. */
*name_offset = offset;
- offset += namesz;
- if (unlikely (offset > data->d_size
- || data->d_size - offset < descsz
- || (descsz == 0 && n->n_descsz != 0)))
+ offset += n->n_namesz;
+ if (offset > data->d_size)
offset = 0;
else
{
- *desc_offset = offset;
- offset += descsz;
- *result = *n;
+ /* Include padding. Check below for overflow. */
+ GElf_Word descsz = (data->d_type == ELF_T_NHDR8
+ ? NOTE_ALIGN8 (n->n_descsz)
+ : NOTE_ALIGN4 (n->n_descsz));
+
+ if (data->d_type == ELF_T_NHDR8)
+ offset = NOTE_ALIGN8 (offset);
+ else
+ offset = NOTE_ALIGN4 (offset);
+
+ if (unlikely (offset > data->d_size
+ || data->d_size - offset < descsz
+ || (descsz == 0 && n->n_descsz != 0)))
+ offset = 0;
+ else
+ {
+ *desc_offset = offset;
+ offset += descsz;
+ *result = *n;
+ }
}
}
}
diff --git a/libelf/gelf_xlate.c b/libelf/gelf_xlate.c
index 479f143..b5d6ef3 100644
--- a/libelf/gelf_xlate.c
+++ b/libelf/gelf_xlate.c
@@ -195,7 +195,8 @@ const xfct_t __elf_xfctstom[EV_NUM - 1][EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM]
[ELF_T_VDAUX] = elf_cvt_Verdef, \
[ELF_T_VNEED] = elf_cvt_Verneed, \
[ELF_T_VNAUX] = elf_cvt_Verneed, \
- [ELF_T_NHDR] = elf_cvt_note, \
+ [ELF_T_NHDR] = elf_cvt_note4, \
+ [ELF_T_NHDR8] = elf_cvt_note8, \
[ELF_T_SYMINFO] = ElfW2(Bits, cvt_Syminfo), \
[ELF_T_MOVE] = ElfW2(Bits, cvt_Move), \
[ELF_T_LIB] = ElfW2(Bits, cvt_Lib), \
diff --git a/libelf/libelf.h b/libelf/libelf.h
index d11358c..1ff11c9 100644
--- a/libelf/libelf.h
+++ b/libelf/libelf.h
@@ -117,6 +117,8 @@ typedef enum
ELF_T_GNUHASH, /* GNU-style hash section. */
ELF_T_AUXV, /* Elf32_auxv_t, Elf64_auxv_t, ... */
ELF_T_CHDR, /* Compressed, Elf32_Chdr, Elf64_Chdr, ... */
+ ELF_T_NHDR8, /* Special GNU Properties note. Same as Nhdr,
+ except padding. */
/* Keep this the last entry. */
ELF_T_NUM
} Elf_Type;
diff --git a/libelf/libelfP.h b/libelf/libelfP.h
index ed216c8..fa6d55d 100644
--- a/libelf/libelfP.h
+++ b/libelf/libelfP.h
@@ -452,7 +452,8 @@ extern const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_
/* Given an Elf handle and a section type returns the Elf_Data d_type.
Should not be called when SHF_COMPRESSED is set, the d_type should
be ELF_T_BYTE. */
-extern Elf_Type __libelf_data_type (Elf *elf, int sh_type) internal_function;
+extern Elf_Type __libelf_data_type (Elf *elf, int sh_type, GElf_Xword align)
+ internal_function;
/* The libelf API does not have such a function but it is still useful.
Get the memory size for the given type.
@@ -624,8 +625,13 @@ extern void __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size,
} \
} while (0)
-/* Align offset to 4 bytes as needed for note name and descriptor data. */
-#define NOTE_ALIGN(n) (((n) + 3) & -4U)
+/* Align offset to 4 bytes as needed for note name and descriptor data.
+ This is almost always used, except for GNU Property notes, which use
+ 8 byte padding... */
+#define NOTE_ALIGN4(n) (((n) + 3) & -4U)
+
+/* Special note padding rule for GNU Property notes. */
+#define NOTE_ALIGN8(n) (((n) + 7) & -8U)
/* Convenience macro. */
#define INVALID_NDX(ndx, type, data) \
diff --git a/libelf/note_xlate.h b/libelf/note_xlate.h
index 62c6f63..9bdc3e2 100644
--- a/libelf/note_xlate.h
+++ b/libelf/note_xlate.h
@@ -1,5 +1,5 @@
/* Conversion functions for notes.
- Copyright (C) 2007, 2009, 2014 Red Hat, Inc.
+ Copyright (C) 2007, 2009, 2014, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -27,38 +27,60 @@
not, see <http://www.gnu.org/licenses/>. */
static void
-elf_cvt_note (void *dest, const void *src, size_t len, int encode)
+elf_cvt_note (void *dest, const void *src, size_t len, int encode,
+ bool nhdr8)
{
+ /* Note that the header is always the same size, but the padding
+ differs for GNU Property notes. */
assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
while (len >= sizeof (Elf32_Nhdr))
{
+ /* Convert the header. */
(1 ? Elf32_cvt_Nhdr : Elf64_cvt_Nhdr) (dest, src, sizeof (Elf32_Nhdr),
encode);
const Elf32_Nhdr *n = encode ? src : dest;
- Elf32_Word namesz = NOTE_ALIGN (n->n_namesz);
- Elf32_Word descsz = NOTE_ALIGN (n->n_descsz);
- len -= sizeof *n;
- src += sizeof *n;
- dest += sizeof *n;
+ size_t note_len = sizeof *n;
- if (namesz > len)
+ /* desc needs to be aligned. */
+ note_len += n->n_namesz;
+ note_len = nhdr8 ? NOTE_ALIGN8 (note_len) : NOTE_ALIGN4 (note_len);
+ if (note_len > len || note_len < 8)
break;
- len -= namesz;
- if (descsz > len)
+
+ /* data as a whole needs to be aligned. */
+ note_len += n->n_descsz;
+ note_len = nhdr8 ? NOTE_ALIGN8 (note_len) : NOTE_ALIGN4 (note_len);
+ if (note_len > len || note_len < 8)
break;
- len -= descsz;
+ /* Copy or skip the note data. */
+ size_t note_data_len = note_len - sizeof *n;
+ src += sizeof *n;
+ dest += sizeof *n;
if (src != dest)
- memcpy (dest, src, namesz + descsz);
+ memcpy (dest, src, note_data_len);
- src += namesz + descsz;
- dest += namesz + descsz;
+ src += note_data_len;
+ dest += note_data_len;
+ len -= note_len;
}
- /* Copy opver any leftover data unconcerted. Probably part of
+ /* Copy over any leftover data unconverted. Probably part of
truncated name/desc data. */
if (unlikely (len > 0) && src != dest)
memcpy (dest, src, len);
}
+
+static void
+elf_cvt_note4 (void *dest, const void *src, size_t len, int encode)
+{
+ elf_cvt_note (dest, src, len, encode, false);
+}
+
+static void
+elf_cvt_note8 (void *dest, const void *src, size_t len, int encode)
+{
+ elf_cvt_note (dest, src, len, encode, true);
+}
diff --git a/src/elflint.c b/src/elflint.c
index 3d44595..fa3af4c 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -4331,6 +4331,7 @@ section [%2d] '%s': unknown core file note type %" PRIu32
case NT_GNU_HWCAP:
case NT_GNU_BUILD_ID:
case NT_GNU_GOLD_VERSION:
+ case NT_GNU_PROPERTY_TYPE_0:
break;
case 0:
@@ -4376,7 +4377,8 @@ phdr[%d]: no note entries defined for the type of file\n"),
GElf_Off notes_size = 0;
Elf_Data *data = elf_getdata_rawchunk (ebl->elf,
phdr->p_offset, phdr->p_filesz,
- ELF_T_NHDR);
+ (phdr->p_align == 8
+ ? ELF_T_NHDR8 : ELF_T_NHDR));
if (data != NULL && data->d_buf != NULL)
notes_size = check_note_data (ebl, ehdr, data, 0, cnt, phdr->p_offset);
diff --git a/src/readelf.c b/src/readelf.c
index 72ae04e..ccd07eb 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -12300,7 +12300,8 @@ handle_notes (Ebl *ebl, GElf_Ehdr *ehdr)
handle_notes_data (ebl, ehdr, phdr->p_offset,
elf_getdata_rawchunk (ebl->elf,
phdr->p_offset, phdr->p_filesz,
- ELF_T_NHDR));
+ (phdr->p_align == 8
+ ? ELF_T_NHDR8 : ELF_T_NHDR)));
}
}

View File

@ -0,0 +1,58 @@
commit e8b9832af19e5975fb2a9dbe729eaba0373c781f
Author: Mark Wielaard <mark@klomp.org>
Date: Mon Dec 3 00:03:39 2018 +0100
libebl: Fix reading GNU_PROPERTY_STACK_SIZE reading from 32bit notes.
When reading a GNU_PROPERTY_STACK_SIZE we need to use the proper data
type. GElf_Addr is 64bit always and when reading a 32bit size part of
it would not be initialized. Use either Elf32_Addr or Elf64_Addr to
read and print the data.
Add 32bit and 64bit, little and big endian testcases.
Signed-off-by: Mark Wielaard <mark@klomp.org>
diff --git a/libebl/eblobjnote.c b/libebl/eblobjnote.c
index 58ac86d..c19ea37 100644
--- a/libebl/eblobjnote.c
+++ b/libebl/eblobjnote.c
@@ -360,15 +360,22 @@ ebl_object_note (Ebl *ebl, uint32_t namesz, const char *name, uint32_t type,
if (prop.pr_type == GNU_PROPERTY_STACK_SIZE)
{
printf ("STACK_SIZE ");
- if (prop.pr_datasz == 4 || prop.pr_datasz == 8)
+ union
+ {
+ Elf64_Addr a64;
+ Elf32_Addr a32;
+ } addr;
+ if ((elfclass == ELFCLASS32 && prop.pr_datasz == 4)
+ || (elfclass == ELFCLASS64 && prop.pr_datasz == 8))
{
- GElf_Addr addr;
in.d_type = ELF_T_ADDR;
out.d_type = ELF_T_ADDR;
in.d_size = prop.pr_datasz;
- out.d_size = sizeof (addr);
+ out.d_size = prop.pr_datasz;
in.d_buf = (void *) desc;
- out.d_buf = (void *) &addr;
+ out.d_buf = (elfclass == ELFCLASS32
+ ? (void *) &addr.a32
+ : (void *) &addr.a64);
if (gelf_xlatetom (ebl->elf, &out, &in,
elfident[EI_DATA]) == NULL)
@@ -376,7 +383,10 @@ ebl_object_note (Ebl *ebl, uint32_t namesz, const char *name, uint32_t type,
printf ("%s\n", elf_errmsg (-1));
return;
}
- printf ("%#" PRIx64 "\n", addr);
+ if (elfclass == ELFCLASS32)
+ printf ("%#" PRIx32 "\n", addr.a32);
+ else
+ printf ("%#" PRIx64 "\n", addr.a64);
}
else
printf (" (garbage datasz: %" PRIx32 ")\n",

View File

@ -0,0 +1,51 @@
commit 20f9de9b5f704cec55df92406a50bcbcfca96acd
Author: Mark Wielaard <mark@klomp.org>
Date: Sun Oct 14 16:45:48 2018 +0200
libdwfl: Sanity check partial core file data reads.
There were two issues when reading note data from a core file.
We didn't check if the data we already had in a buffer was big
enough. And if we did get the data, we should check if we got
everything, or just a part of the data.
https://sourceware.org/bugzilla/show_bug.cgi?id=23752
Signed-off-by: Mark Wielaard <mark@klomp.org>
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index 36e5c82..8749884 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -1,5 +1,5 @@
/* Sniff out modules from ELF headers visible in memory segments.
- Copyright (C) 2008-2012, 2014, 2015 Red Hat, Inc.
+ Copyright (C) 2008-2012, 2014, 2015, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -301,7 +301,10 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
inline bool read_portion (void **data, size_t *data_size,
GElf_Addr vaddr, size_t filesz)
{
- if (vaddr - start + filesz > buffer_available
+ /* Check whether we will have to read the segment data, or if it
+ can be returned from the existing buffer. */
+ if (filesz > buffer_available
+ || vaddr - start > buffer_available - filesz
/* If we're in string mode, then don't consider the buffer we have
sufficient unless it contains the terminator of the string. */
|| (filesz == 0 && memchr (vaddr - start + buffer, '\0',
@@ -459,6 +462,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
if (read_portion (&data, &data_size, vaddr, filesz))
return;
+ /* data_size will be zero if we got everything from the initial
+ buffer, otherwise it will be the size of the new buffer that
+ could be read. */
+ if (data_size != 0)
+ filesz = data_size;
+
assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
void *notes;

View File

@ -0,0 +1,31 @@
commit 22d2d082d57a7470fadc0eae67179553f4919209
Author: Mark Wielaard <mark@klomp.org>
Date: Thu Oct 18 23:15:48 2018 +0200
size: Handle recursive ELF ar files.
eu-size didn't handle an ELF ar file that contained an ar file itself
correctly. handle_ar would recursively call itself but close the ELF
file before returning. Only close the ELF file at the top-level.
https://sourceware.org/bugzilla/show_bug.cgi?id=23787
Signed-off-by: Mark Wielaard <mark@klomp.org>
diff --git a/src/size.c b/src/size.c
index 5ff3f2a..f01fd88 100644
--- a/src/size.c
+++ b/src/size.c
@@ -374,8 +374,10 @@ handle_ar (int fd, Elf *elf, const char *prefix, const char *fname)
INTERNAL_ERROR (fname);
}
- if (unlikely (elf_end (elf) != 0))
- INTERNAL_ERROR (fname);
+ /* Only close ELF handle if this was a "top level" ar file. */
+ if (prefix == NULL)
+ if (unlikely (elf_end (elf) != 0))
+ INTERNAL_ERROR (fname);
return result;
}

View File

@ -0,0 +1,226 @@
commit c06ab0bbb4761a69d2f188675d21d1a9131e9ecb
Author: Mark Wielaard <mark@klomp.org>
Date: Sat Oct 13 10:27:47 2018 +0200
strip, unstrip: Handle SHT_GROUP correctly.
The usage of annobin in Fedora showed a couple of bugs when using
eu-strip and eu-unstrip on ET_REL files that contain multiple group
sections.
When stripping we should not remove the SHF_GROUP flag from sections
even if the group section itself might be removed. Either the section
itself gets removed, and so the flag doesn't matter. Or it gets moved
together with the group section into the debug file, and then it still
needs to have the flag set. Also we would "renumber" the section group
flag field (which isn't a section index, and so shouldn't be changed).
Often the group sections have the exact same name (".group"), flags
(none) and sometimes the same sizes. Which makes matching them hard.
Extract the group signature and compare those when comparing two
group sections.
Signed-off-by: Mark Wielaard <mark@klomp.org>
diff --git a/src/strip.c b/src/strip.c
index 1f7b3ca..fdebc5e 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -792,9 +792,13 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
if (shdr_info[shdr_info[cnt].group_idx].idx == 0)
{
- /* The section group section will be removed. */
+ /* The section group section might be removed.
+ Don't remove the SHF_GROUP flag. The section is
+ either also removed, in which case the flag doesn't matter.
+ Or it moves with the group into the debug file, then
+ it will be reconnected with the new group and should
+ still have the flag set. */
shdr_info[cnt].group_idx = 0;
- shdr_info[cnt].shdr.sh_flags &= ~SHF_GROUP;
}
}
@@ -1368,7 +1372,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
&& shdr_info[cnt].data->d_buf != NULL);
Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
- for (size_t inner = 0;
+ /* First word is the section group flag.
+ Followed by section indexes, that need to be renumbered. */
+ for (size_t inner = 1;
inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
++inner)
if (grpref[inner] < shnum)
diff --git a/src/unstrip.c b/src/unstrip.c
index e6f0947..03a0346 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -696,6 +696,7 @@ struct section
{
Elf_Scn *scn;
const char *name;
+ const char *sig;
Elf_Scn *outscn;
Dwelf_Strent *strent;
GElf_Shdr shdr;
@@ -720,7 +721,8 @@ compare_alloc_sections (const struct section *s1, const struct section *s2,
static int
compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
- const char *name1, const char *name2)
+ const char *name1, const char *name2,
+ const char *sig1, const char *sig2)
{
/* Sort by sh_flags as an arbitrary ordering. */
if (shdr1->sh_flags < shdr2->sh_flags)
@@ -734,6 +736,10 @@ compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
if (shdr1->sh_size > shdr2->sh_size)
return 1;
+ /* Are they both SHT_GROUP sections? Then compare signatures. */
+ if (sig1 != NULL && sig2 != NULL)
+ return strcmp (sig1, sig2);
+
/* Sort by name as last resort. */
return strcmp (name1, name2);
}
@@ -751,7 +757,8 @@ compare_sections (const void *a, const void *b, bool rel)
return ((s1->shdr.sh_flags & SHF_ALLOC)
? compare_alloc_sections (s1, s2, rel)
: compare_unalloc_sections (&s1->shdr, &s2->shdr,
- s1->name, s2->name));
+ s1->name, s2->name,
+ s1->sig, s2->sig));
}
static int
@@ -986,6 +993,44 @@ get_section_name (size_t ndx, const GElf_Shdr *shdr, const Elf_Data *shstrtab)
return shstrtab->d_buf + shdr->sh_name;
}
+/* Returns the signature of a group section, or NULL if the given
+ section isn't a group. */
+static const char *
+get_group_sig (Elf *elf, GElf_Shdr *shdr)
+{
+ if (shdr->sh_type != SHT_GROUP)
+ return NULL;
+
+ Elf_Scn *symscn = elf_getscn (elf, shdr->sh_link);
+ if (symscn == NULL)
+ error (EXIT_FAILURE, 0, _("bad sh_link for group section: %s"),
+ elf_errmsg (-1));
+
+ GElf_Shdr symshdr_mem;
+ GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
+ if (symshdr == NULL)
+ error (EXIT_FAILURE, 0, _("couldn't get shdr for group section: %s"),
+ elf_errmsg (-1));
+
+ Elf_Data *symdata = elf_getdata (symscn, NULL);
+ if (symdata == NULL)
+ error (EXIT_FAILURE, 0, _("bad data for group symbol section: %s"),
+ elf_errmsg (-1));
+
+ GElf_Sym sym_mem;
+ GElf_Sym *sym = gelf_getsym (symdata, shdr->sh_info, &sym_mem);
+ if (sym == NULL)
+ error (EXIT_FAILURE, 0, _("couldn't get symbol for group section: %s"),
+ elf_errmsg (-1));
+
+ const char *sig = elf_strptr (elf, symshdr->sh_link, sym->st_name);
+ if (sig == NULL)
+ error (EXIT_FAILURE, 0, _("bad symbol name for group section: %s"),
+ elf_errmsg (-1));
+
+ return sig;
+}
+
/* Fix things up when prelink has moved some allocated sections around
and the debuginfo file's section headers no longer match up.
This fills in SECTIONS[0..NALLOC-1].outscn or exits.
@@ -1111,6 +1156,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
sec->scn = elf_getscn (main, i + 1); /* Really just for ndx. */
sec->outscn = NULL;
sec->strent = NULL;
+ sec->sig = get_group_sig (main, &sec->shdr);
++undo_nalloc;
}
}
@@ -1336,6 +1382,7 @@ more sections in stripped file than debug file -- arguments reversed?"));
sections[i].scn = scn;
sections[i].outscn = NULL;
sections[i].strent = NULL;
+ sections[i].sig = get_group_sig (stripped, shdr);
}
const struct section *stripped_symtab = NULL;
@@ -1354,7 +1401,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
/* Locate a matching unallocated section in SECTIONS. */
inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
- const char *name)
+ const char *name,
+ const char *sig)
{
size_t l = nalloc, u = stripped_shnum - 1;
while (l < u)
@@ -1362,7 +1410,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
size_t i = (l + u) / 2;
struct section *sec = &sections[i];
int cmp = compare_unalloc_sections (shdr, &sec->shdr,
- name, sec->name);
+ name, sec->name,
+ sig, sec->sig);
if (cmp < 0)
u = i;
else if (cmp > 0)
@@ -1435,7 +1484,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
else
{
/* Look for the section that matches. */
- sec = find_unalloc_section (shdr, name);
+ sec = find_unalloc_section (shdr, name,
+ get_group_sig (unstripped, shdr));
if (sec == NULL)
{
/* An additional unallocated section is fine if not SHT_NOBITS.
commit eee4269e53154daaf0251371aacd91ec5db3eb30
Author: Mark Wielaard <mark@klomp.org>
Date: Sat Oct 13 10:27:47 2018 +0200
unstrip: Renumber the group section indexes.
When unstripping we might need to renumber the group section indexes.
Just like we do when stripping.
Signed-off-by: Mark Wielaard <mark@klomp.org>
diff --git a/src/unstrip.c b/src/unstrip.c
index 03a0346..2cfd3b3 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -1708,6 +1708,20 @@ more sections in stripped file than debug file -- arguments reversed?"));
if (shdr_mem.sh_type == SHT_DYNSYM)
stripped_dynsym = sec;
}
+
+ if (shdr_mem.sh_type == SHT_GROUP)
+ {
+ /* We must adjust all the section indices in the group.
+ Skip the first word, which is the section group flag.
+ Everything else is a section index. */
+ Elf32_Word *shndx = (Elf32_Word *) outdata->d_buf;
+ for (size_t i = 1; i < shdr_mem.sh_size / sizeof (Elf32_Word); ++i)
+ if (shndx[i] == SHN_UNDEF || shndx[i] >= stripped_shnum)
+ error (EXIT_FAILURE, 0,
+ _("group has invalid section index [%zd]"), i);
+ else
+ shndx[i] = ndx_section[shndx[i] - 1];
+ }
}
/* We may need to update the symbol table. */

View File

@ -0,0 +1,156 @@
commit 7a3f6fe60b8519b5372f5a5521ccbac59411f33f
Author: Mark Wielaard <mark@klomp.org>
Date: Sun Nov 11 23:50:41 2018 +0100
Recognize NT_VERSION notes.
NT_VERSION notes are emitted by the gas .version directive.
They have an empty description and (ab)use the owner name to store the
version data string.
Signed-off-by: Mark Wielaard <mark@klomp.org>
diff --git a/libebl/eblobjnote.c b/libebl/eblobjnote.c
index 57e9f52..8fda7d9 100644
--- a/libebl/eblobjnote.c
+++ b/libebl/eblobjnote.c
@@ -135,6 +135,14 @@ ebl_object_note (Ebl *ebl, const char *name, uint32_t type,
return;
}
+ /* NT_VERSION doesn't have any info. All data is in the name. */
+ if (descsz == 0 && type == NT_VERSION)
+ return;
+
+ /* Everything else should have the "GNU" owner name. */
+ if (strcmp ("GNU", name) != 0)
+ return;
+
switch (type)
{
case NT_GNU_BUILD_ID:
@@ -337,7 +345,7 @@ ebl_object_note (Ebl *ebl, const char *name, uint32_t type,
break;
case NT_GNU_ABI_TAG:
- if (strcmp (name, "GNU") == 0 && descsz >= 8 && descsz % 4 == 0)
+ if (descsz >= 8 && descsz % 4 == 0)
{
Elf_Data in =
{
diff --git a/libebl/eblobjnotetypename.c b/libebl/eblobjnotetypename.c
index af23cae..8cdd781 100644
--- a/libebl/eblobjnotetypename.c
+++ b/libebl/eblobjnotetypename.c
@@ -39,6 +39,7 @@
const char *
ebl_object_note_type_name (Ebl *ebl, const char *name, uint32_t type,
+ GElf_Word descsz,
char *buf, size_t len)
{
const char *res = ebl->object_note_type_name (name, type, buf, len);
@@ -80,14 +81,19 @@ ebl_object_note_type_name (Ebl *ebl, const char *name, uint32_t type,
if (strcmp (name, "GNU") != 0)
{
+ /* NT_VERSION is special, all data is in the name. */
+ if (descsz == 0 && type == NT_VERSION)
+ return "VERSION";
+
snprintf (buf, len, "%s: %" PRIu32, gettext ("<unknown>"), type);
return buf;
}
+ /* And finally all the "GNU" note types. */
static const char *knowntypes[] =
{
#define KNOWNSTYPE(name) [NT_##name] = #name
- KNOWNSTYPE (VERSION),
+ KNOWNSTYPE (GNU_ABI_TAG),
KNOWNSTYPE (GNU_HWCAP),
KNOWNSTYPE (GNU_BUILD_ID),
KNOWNSTYPE (GNU_GOLD_VERSION),
diff --git a/libebl/libebl.h b/libebl/libebl.h
index a34fe48..5830654 100644
--- a/libebl/libebl.h
+++ b/libebl/libebl.h
@@ -175,8 +175,8 @@ extern const char *ebl_core_note_type_name (Ebl *ebl, uint32_t type, char *buf,
/* Return name of the note section type for an object file. */
extern const char *ebl_object_note_type_name (Ebl *ebl, const char *name,
- uint32_t type, char *buf,
- size_t len);
+ uint32_t type, GElf_Word descsz,
+ 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,
diff --git a/src/elflint.c b/src/elflint.c
index fa3af4c..dff74ee 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -1,5 +1,5 @@
/* Pedantic checking of ELF files compliance with gABI/psABI spec.
- Copyright (C) 2001-2015, 2017 Red Hat, Inc.
+ Copyright (C) 2001-2015, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2001.
@@ -4332,7 +4332,17 @@ section [%2d] '%s': unknown core file note type %" PRIu32
case NT_GNU_BUILD_ID:
case NT_GNU_GOLD_VERSION:
case NT_GNU_PROPERTY_TYPE_0:
- break;
+ if (nhdr.n_namesz == sizeof ELF_NOTE_GNU
+ && strcmp (data->d_buf + name_offset, ELF_NOTE_GNU) == 0)
+ break;
+ else
+ {
+ /* NT_VERSION is 1, same as NT_GNU_ABI_TAG. It has no
+ descriptor and (ab)uses the name as version string. */
+ if (nhdr.n_descsz == 0 && nhdr.n_type == NT_VERSION)
+ break;
+ }
+ goto unknown_note;
case 0:
/* Linux vDSOs use a type 0 note for the kernel version word. */
@@ -4341,16 +4351,21 @@ section [%2d] '%s': unknown core file note type %" PRIu32
break;
FALLTHROUGH;
default:
+ {
+ unknown_note:
if (shndx == 0)
ERROR (gettext ("\
-phdr[%d]: unknown object file note type %" PRIu32 " at offset %zu\n"),
- phndx, (uint32_t) nhdr.n_type, offset);
+phdr[%d]: unknown object file note type %" PRIu32 " with owner name '%s' at offset %zu\n"),
+ phndx, (uint32_t) nhdr.n_type,
+ (char *) data->d_buf + name_offset, offset);
else
ERROR (gettext ("\
section [%2d] '%s': unknown object file note type %" PRIu32
- " at offset %zu\n"),
+ " with owner name '%s' at offset %zu\n"),
shndx, section_name (ebl, shndx),
- (uint32_t) nhdr.n_type, offset);
+ (uint32_t) nhdr.n_type,
+ (char *) data->d_buf + name_offset, offset);
+ }
}
}
diff --git a/src/readelf.c b/src/readelf.c
index c6c3fb3..659e34f 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -12201,6 +12201,7 @@ handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
? ebl_core_note_type_name (ebl, nhdr.n_type,
buf, sizeof (buf))
: ebl_object_note_type_name (ebl, name, nhdr.n_type,
+ nhdr.n_descsz,
buf2, sizeof (buf2)));
/* Filter out invalid entries. */

View File

@ -0,0 +1,127 @@
commit 825e48c4e942e3cbdab1b75c04b8c014867d66ab
Author: Milian Wolff <milian.wolff@kdab.com>
Date: Mon Oct 29 16:21:26 2018 +0100
Also find CFI in sections of type SHT_X86_64_UNWIND
On my system with g++ (GCC) 8.2.1 20180831 with GNU gold (GNU Binutils
2.31.1) 1.16, the .eh_frame section does not have type PROGBITS
but rather is using X86_64_UNWIND nowadays:
```
$ echo "int main(){ return 0; }" > test.c
$ gcc test.c
$ readelf --sections a.out | grep .eh_frame
[14] .eh_frame X86_64_UNWIND 0000000000000670 00000670
[15] .eh_frame_hdr X86_64_UNWIND 0000000000000724 00000724
```
Without this patch, libdw refuses to use the available unwind
information, leading to broken backtraces while unwinding. With the
patch applied, unwinding works once more in such situations.
Signed-off-by: Milian Wolff <milian.wolff@kdab.com>
Signed-off-by: Mark Wielaard <mark@klomp.org>
Tested-by: Milian Wolff <milian.wolff@kdab.com>
diff --git a/libdw/dwarf_getcfi_elf.c b/libdw/dwarf_getcfi_elf.c
index 315cc02..adcaea0 100644
--- a/libdw/dwarf_getcfi_elf.c
+++ b/libdw/dwarf_getcfi_elf.c
@@ -298,7 +298,7 @@ getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
}
else if (!strcmp (name, ".eh_frame"))
{
- if (shdr->sh_type == SHT_PROGBITS)
+ if (shdr->sh_type != SHT_NOBITS)
return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
hdr_scn, hdr_vaddr);
else
commit 4b0342b85b5b1a3d3636e06e3b5320954828dfb1
Author: Mark Wielaard <mark@klomp.org>
Date: Tue Nov 6 12:01:25 2018 +0100
backends: Add x86_64 section_type_name for SHT_X86_64_UNWIND.
Makes sure that eu-readelf and eu-elflint recognize and show the
x86_64 specific section type correctly.
Signed-off-by: Mark Wielaard <mark@klomp.org>
Tested-by: Milian Wolff <milian.wolff@kdab.com>
diff --git a/backends/x86_64_init.c b/backends/x86_64_init.c
index adfa479..49f6c6c 100644
--- a/backends/x86_64_init.c
+++ b/backends/x86_64_init.c
@@ -1,5 +1,5 @@
/* Initialization of x86-64 specific backend library.
- Copyright (C) 2002-2009, 2013 Red Hat, Inc.
+ Copyright (C) 2002-2009, 2013, 2018 Red Hat, Inc.
Copyright (C) H.J. Lu <hjl.tools@gmail.com>, 2015.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -55,6 +55,7 @@ x86_64_init (Elf *elf __attribute__ ((unused)),
eh->name = "AMD x86-64";
x86_64_init_reloc (eh);
HOOK (eh, reloc_simple_type);
+ HOOK (eh, section_type_name);
if (eh->class == ELFCLASS32)
eh->core_note = x32_core_note;
else
diff --git a/backends/x86_64_symbol.c b/backends/x86_64_symbol.c
index e07b180..98457bc 100644
--- a/backends/x86_64_symbol.c
+++ b/backends/x86_64_symbol.c
@@ -1,5 +1,5 @@
/* x86_64 specific symbolic name handling.
- Copyright (C) 2002, 2005 Red Hat, Inc.
+ Copyright (C) 2002, 2005, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
@@ -59,3 +59,15 @@ x86_64_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type,
return ELF_T_NUM;
}
}
+
+/* Return symbolic representation of section type. */
+const char *
+x86_64_section_type_name (int type,
+ char *buf __attribute__ ((unused)),
+ size_t len __attribute__ ((unused)))
+{
+ if (type == SHT_X86_64_UNWIND)
+ return "X86_64_UNWIND";
+
+ return NULL;
+}
commit 22ec8efc1dd87cdc7892523457eb55990b967224
Author: Mark Wielaard <mark@klomp.org>
Date: Sat Nov 10 23:33:03 2018 +0100
elflint: Allow PT_GNU_EH_FRAME segment to match SHT_X86_64_UNWIND section.
The gold linker might generate an .eh_frame_hdr with a SHT_X86_64_UNWIND
type instead of a SHT_PROGBITS type.
Signed-off-by: Mark Wielaard <mark@klomp.org>
diff --git a/src/elflint.c b/src/elflint.c
index 184ca12..810c8bd 100644
--- a/src/elflint.c
+++ b/src/elflint.c
@@ -4633,8 +4633,10 @@ program header offset in ELF header and PHDR entry do not match"));
any = true;
shdr = gelf_getshdr (scn, &shdr_mem);
if (shdr != NULL
- && shdr->sh_type == (is_debuginfo
- ? SHT_NOBITS : SHT_PROGBITS)
+ && ((is_debuginfo && shdr->sh_type == SHT_NOBITS)
+ || (! is_debuginfo
+ && (shdr->sh_type == SHT_PROGBITS
+ || shdr->sh_type == SHT_X86_64_UNWIND)))
&& elf_strptr (ebl->elf, shstrndx, shdr->sh_name) != NULL
&& ! strcmp (".eh_frame_hdr",
elf_strptr (ebl->elf, shstrndx, shdr->sh_name)))

1374
SPECS/elfutils.spec Normal file

File diff suppressed because it is too large Load Diff