Blame SOURCES/elfutils-0.174-gnu-attribute-note.patch

95a93d
commit 72e30c2e0cb49a9a300667fdd5ff09082f717950
95a93d
Author: Mark Wielaard <mark@klomp.org>
95a93d
Date:   Mon Nov 12 23:34:24 2018 +0100
95a93d
95a93d
    Handle GNU Build Attribute ELF Notes.
95a93d
    
95a93d
    GNU Build Attribute ELF Notes are generated by the GCC annobin plugin
95a93d
    and described at https://fedoraproject.org/wiki/Toolchain/Watermark
95a93d
    
95a93d
    Unfortunately the constants aren't yet described in the standard glibc
95a93d
    elf.h so they have been added to the elfutils specific elf-knowledge.h.
95a93d
    
95a93d
    The notes abuse the name owner field to encode some data not in the
95a93d
    description. This makes it a bit hard to parse. We have to match the
95a93d
    note owner name prefix (to "GA") to be sure the type is valid. We also
95a93d
    cannot rely on the owner name being a valid C string since the attribute
95a93d
    name and value can contain zero (terminators). So pass around namesz
95a93d
    to the ebl note parsing functions.
95a93d
    
95a93d
    eu-elflint will recognize and eu-readelf -n will now show the notes:
95a93d
    
95a93d
    Note section [27] '.gnu.build.attributes' of 56080 bytes at offset 0x114564:
95a93d
      Owner          Data size  Type
95a93d
      GA                    16  GNU Build Attribute OPEN
95a93d
        Address Range: 0x2f30f - 0x2f30f
95a93d
        VERSION: "3p8"
95a93d
      GA                     0  GNU Build Attribute OPEN
95a93d
        TOOL: "gcc 8.2.1 20180801"
95a93d
      GA                     0  GNU Build Attribute OPEN
95a93d
        "GOW": 45
95a93d
      GA                     0  GNU Build Attribute OPEN
95a93d
        STACK_PROT: 0
95a93d
      GA                     0  GNU Build Attribute OPEN
95a93d
        "stack_clash": TRUE
95a93d
      GA                     0  GNU Build Attribute OPEN
95a93d
        "cf_protection": 0
95a93d
      GA                     0  GNU Build Attribute OPEN
95a93d
        "GLIBCXX_ASSERTIONS": TRUE
95a93d
      GA                     0  GNU Build Attribute OPEN
95a93d
        "FORTIFY": 0
95a93d
      GA                     0  GNU Build Attribute OPEN
95a93d
        PIC: 3
95a93d
      GA                     0  GNU Build Attribute OPEN
95a93d
        SHORT_ENUM: FALSE
95a93d
      GA                     0  GNU Build Attribute OPEN
95a93d
        ABI: c001100000012
95a93d
      GA                     0  GNU Build Attribute OPEN
95a93d
        "stack_realign": FALSE
95a93d
    
95a93d
    A new test was added to run-readelf -n for the existing annobin file.
95a93d
    
95a93d
    Signed-off-by: Mark Wielaard <mark@klomp.org>
95a93d
95a93d
diff --git a/libebl/eblobjnote.c b/libebl/eblobjnote.c
95a93d
index 8fda7d9..58ac86d 100644
95a93d
--- a/libebl/eblobjnote.c
95a93d
+++ b/libebl/eblobjnote.c
95a93d
@@ -37,11 +37,14 @@
95a93d
 #include <string.h>
95a93d
 #include <libeblP.h>
95a93d
 
95a93d
+#include "common.h"
95a93d
 #include "libelfP.h"
95a93d
+#include "libdwP.h"
95a93d
+#include "memory-access.h"
95a93d
 
95a93d
 
95a93d
 void
95a93d
-ebl_object_note (Ebl *ebl, const char *name, uint32_t type,
95a93d
+ebl_object_note (Ebl *ebl, uint32_t namesz, const char *name, uint32_t type,
95a93d
 		 uint32_t descsz, const char *desc)
95a93d
 {
95a93d
   if (! ebl->object_note (name, type, descsz, desc))
95a93d
@@ -135,6 +138,152 @@ ebl_object_note (Ebl *ebl, const char *name, uint32_t type,
95a93d
 	  return;
95a93d
 	}
95a93d
 
95a93d
+      if (strncmp (name, ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX,
95a93d
+		   strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)) == 0
95a93d
+	  && (type == NT_GNU_BUILD_ATTRIBUTE_OPEN
95a93d
+	      || type == NT_GNU_BUILD_ATTRIBUTE_FUNC))
95a93d
+	{
95a93d
+	  /* There might or might not be a pair of addresses in the desc.  */
95a93d
+	  if (descsz > 0)
95a93d
+	    {
95a93d
+	      printf ("    Address Range: ");
95a93d
+
95a93d
+	      union
95a93d
+	      {
95a93d
+		Elf64_Addr a64[2];
95a93d
+		Elf32_Addr a32[2];
95a93d
+	      } addrs;
95a93d
+
95a93d
+	      size_t addr_size = gelf_fsize (ebl->elf, ELF_T_ADDR,
95a93d
+					     2, EV_CURRENT);
95a93d
+	      if (descsz != addr_size)
95a93d
+		printf ("<unknown data>\n");
95a93d
+	      else
95a93d
+		{
95a93d
+		  Elf_Data src =
95a93d
+		    {
95a93d
+		     .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
95a93d
+		     .d_buf = (void *) desc, .d_size = descsz
95a93d
+		    };
95a93d
+
95a93d
+		  Elf_Data dst =
95a93d
+		    {
95a93d
+		     .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
95a93d
+		     .d_buf = &addrs, .d_size = descsz
95a93d
+		    };
95a93d
+
95a93d
+		  if (gelf_xlatetom (ebl->elf, &dst, &src,
95a93d
+				     elf_getident (ebl->elf,
95a93d
+						   NULL)[EI_DATA]) == NULL)
95a93d
+		    printf ("%s\n", elf_errmsg (-1));
95a93d
+		  else
95a93d
+		    {
95a93d
+		      if (addr_size == 4)
95a93d
+			printf ("%#" PRIx32 " - %#" PRIx32 "\n",
95a93d
+				addrs.a32[0], addrs.a32[1]);
95a93d
+		      else
95a93d
+			printf ("%#" PRIx64 " - %#" PRIx64 "\n",
95a93d
+				addrs.a64[0], addrs.a64[1]);
95a93d
+		    }
95a93d
+		}
95a93d
+	    }
95a93d
+
95a93d
+	  /* Most data actually is inside the name.
95a93d
+	     https://fedoraproject.org/wiki/Toolchain/Watermark  */
95a93d
+
95a93d
+	  /* We need at least 2 chars of data to describe the
95a93d
+	     attribute and value encodings.  */
95a93d
+	  const char *data = (name
95a93d
+			      + strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX));
95a93d
+	  if (namesz < 2)
95a93d
+	    {
95a93d
+	      printf ("<insufficient data>\n");
95a93d
+	      return;
95a93d
+	    }
95a93d
+
95a93d
+	  printf ("    ");
95a93d
+
95a93d
+	  /* In most cases the value comes right after the encoding bytes.  */
95a93d
+	  const char *value = &data[2];
95a93d
+	  switch (data[1])
95a93d
+	    {
95a93d
+	    case GNU_BUILD_ATTRIBUTE_VERSION:
95a93d
+	      printf ("VERSION: ");
95a93d
+	      break;
95a93d
+	    case GNU_BUILD_ATTRIBUTE_STACK_PROT:
95a93d
+	      printf ("STACK_PROT: ");
95a93d
+	      break;
95a93d
+	    case GNU_BUILD_ATTRIBUTE_RELRO:
95a93d
+	      printf ("RELRO: ");
95a93d
+	      break;
95a93d
+	    case GNU_BUILD_ATTRIBUTE_STACK_SIZE:
95a93d
+	      printf ("STACK_SIZE: ");
95a93d
+	      break;
95a93d
+	    case GNU_BUILD_ATTRIBUTE_TOOL:
95a93d
+	      printf ("TOOL: ");
95a93d
+	      break;
95a93d
+	    case GNU_BUILD_ATTRIBUTE_ABI:
95a93d
+	      printf ("ABI: ");
95a93d
+	      break;
95a93d
+	    case GNU_BUILD_ATTRIBUTE_PIC:
95a93d
+	      printf ("PIC: ");
95a93d
+	      break;
95a93d
+	    case GNU_BUILD_ATTRIBUTE_SHORT_ENUM:
95a93d
+	      printf ("SHORT_ENUM: ");
95a93d
+	      break;
95a93d
+	    case 32 ... 126:
95a93d
+	      printf ("\"%s\": ", &data[1]);
95a93d
+	      value += strlen (&data[1]) + 1;
95a93d
+	      break;
95a93d
+	    default:
95a93d
+	      printf ("<unknown>: ");
95a93d
+	      break;
95a93d
+	    }
95a93d
+
95a93d
+	  switch (data[0])
95a93d
+	    {
95a93d
+	    case GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC:
95a93d
+	      {
95a93d
+		/* Any numbers are always in (unsigned) little endian.  */
95a93d
+		static const Dwarf dbg
95a93d
+		  = { .other_byte_order = MY_ELFDATA != ELFDATA2LSB };
95a93d
+		size_t bytes = namesz - (value - name);
95a93d
+		uint64_t val;
95a93d
+		if (bytes == 1)
95a93d
+		  val = *(unsigned char *) value;
95a93d
+		else if (bytes == 2)
95a93d
+		  val = read_2ubyte_unaligned (&dbg, value);
95a93d
+		else if (bytes == 4)
95a93d
+		  val = read_4ubyte_unaligned (&dbg, value);
95a93d
+		else if (bytes == 8)
95a93d
+		  val = read_8ubyte_unaligned (&dbg, value);
95a93d
+		else
95a93d
+		  goto unknown;
95a93d
+		printf ("%" PRIx64, val);
95a93d
+	      }
95a93d
+	      break;
95a93d
+	    case GNU_BUILD_ATTRIBUTE_TYPE_STRING:
95a93d
+	      printf ("\"%s\"", value);
95a93d
+	      break;
95a93d
+	    case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE:
95a93d
+	      printf ("TRUE");
95a93d
+	      break;
95a93d
+	    case GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE:
95a93d
+	      printf ("FALSE");
95a93d
+	      break;
95a93d
+	    default:
95a93d
+	      {
95a93d
+	      unknown:
95a93d
+		printf ("<unknown>");
95a93d
+	      }
95a93d
+	      break;
95a93d
+	    }
95a93d
+
95a93d
+	  printf ("\n");
95a93d
+
95a93d
+	  return;
95a93d
+	}
95a93d
+
95a93d
       /* NT_VERSION doesn't have any info.  All data is in the name.  */
95a93d
       if (descsz == 0 && type == NT_VERSION)
95a93d
 	return;
95a93d
diff --git a/libebl/eblobjnotetypename.c b/libebl/eblobjnotetypename.c
95a93d
index 8cdd781..29a5391 100644
95a93d
--- a/libebl/eblobjnotetypename.c
95a93d
+++ b/libebl/eblobjnotetypename.c
95a93d
@@ -1,5 +1,5 @@
95a93d
 /* Return note type name.
95a93d
-   Copyright (C) 2002, 2007, 2009, 2011, 2016 Red Hat, Inc.
95a93d
+   Copyright (C) 2002, 2007, 2009, 2011, 2016, 2018 Red Hat, Inc.
95a93d
    This file is part of elfutils.
95a93d
    Written by Ulrich Drepper <drepper@redhat.com>, 2002.
95a93d
 
95a93d
@@ -79,6 +79,29 @@ ebl_object_note_type_name (Ebl *ebl, const char *name, uint32_t type,
95a93d
 	    }
95a93d
 	}
95a93d
 
95a93d
+      if (strncmp (name, ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX,
95a93d
+		   strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)) == 0)
95a93d
+	{
95a93d
+	  /* GNU Build Attribute notes (ab)use the owner name to store
95a93d
+	     most of their data.  Don't decode everything here.  Just
95a93d
+	     the type.*/
95a93d
+	  char *t = buf;
95a93d
+	  const char *gba = "GNU Build Attribute";
95a93d
+	  int w = snprintf (t, len, "%s ", gba);
95a93d
+	  t += w;
95a93d
+	  len -= w;
95a93d
+	  if (type == NT_GNU_BUILD_ATTRIBUTE_OPEN)
95a93d
+	    w = snprintf (t, len, "OPEN");
95a93d
+	  else if (type == NT_GNU_BUILD_ATTRIBUTE_FUNC)
95a93d
+	    w = snprintf (t, len, "FUNC");
95a93d
+	  else
95a93d
+	    w = snprintf (t, len, "%x", type);
95a93d
+	  t += w;
95a93d
+	  len -= w;
95a93d
+
95a93d
+	  return buf;
95a93d
+	}
95a93d
+
95a93d
       if (strcmp (name, "GNU") != 0)
95a93d
 	{
95a93d
 	  /* NT_VERSION is special, all data is in the name.  */
95a93d
diff --git a/libebl/libebl.h b/libebl/libebl.h
95a93d
index 5830654..ca9b9fe 100644
95a93d
--- a/libebl/libebl.h
95a93d
+++ b/libebl/libebl.h
95a93d
@@ -179,8 +179,8 @@ extern const char *ebl_object_note_type_name (Ebl *ebl, const char *name,
95a93d
 					      char *buf, size_t len);
95a93d
 
95a93d
 /* Print information about object note if available.  */
95a93d
-extern void ebl_object_note (Ebl *ebl, const char *name, uint32_t type,
95a93d
-			     uint32_t descsz, const char *desc);
95a93d
+extern void ebl_object_note (Ebl *ebl, uint32_t namesz, const char *name,
95a93d
+			     uint32_t type, uint32_t descsz, const char *desc);
95a93d
 
95a93d
 /* Check whether an attribute in a .gnu_attributes section is recognized.
95a93d
    Fills in *TAG_NAME with the name for this tag.
95a93d
diff --git a/libelf/elf-knowledge.h b/libelf/elf-knowledge.h
95a93d
index 64f5887..9d3be0f 100644
95a93d
--- a/libelf/elf-knowledge.h
95a93d
+++ b/libelf/elf-knowledge.h
95a93d
@@ -77,4 +77,25 @@
95a93d
    || ((Ehdr)->e_machine == EM_S390					      \
95a93d
        && (Ehdr)->e_ident[EI_CLASS] == ELFCLASS64) ? 8 : 4)
95a93d
 
95a93d
+/* GNU Annobin notes are not fully standardized and abuses the owner name.  */
95a93d
+
95a93d
+#define ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX "GA"
95a93d
+
95a93d
+#define NT_GNU_BUILD_ATTRIBUTE_OPEN 0x100
95a93d
+#define NT_GNU_BUILD_ATTRIBUTE_FUNC 0x101
95a93d
+
95a93d
+#define GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC	'*'
95a93d
+#define GNU_BUILD_ATTRIBUTE_TYPE_STRING		'$'
95a93d
+#define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE	'+'
95a93d
+#define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE	'!'
95a93d
+
95a93d
+#define GNU_BUILD_ATTRIBUTE_VERSION	1
95a93d
+#define GNU_BUILD_ATTRIBUTE_STACK_PROT	2
95a93d
+#define GNU_BUILD_ATTRIBUTE_RELRO	3
95a93d
+#define GNU_BUILD_ATTRIBUTE_STACK_SIZE	4
95a93d
+#define GNU_BUILD_ATTRIBUTE_TOOL	5
95a93d
+#define GNU_BUILD_ATTRIBUTE_ABI		6
95a93d
+#define GNU_BUILD_ATTRIBUTE_PIC		7
95a93d
+#define GNU_BUILD_ATTRIBUTE_SHORT_ENUM	8
95a93d
+
95a93d
 #endif	/* elf-knowledge.h */
95a93d
diff --git a/src/elflint.c b/src/elflint.c
95a93d
index dff74ee..184ca12 100644
95a93d
--- a/src/elflint.c
95a93d
+++ b/src/elflint.c
95a93d
@@ -4344,6 +4344,19 @@ section [%2d] '%s': unknown core file note type %" PRIu32
95a93d
 	      }
95a93d
 	      goto unknown_note;
95a93d
 
95a93d
+	  case NT_GNU_BUILD_ATTRIBUTE_OPEN:
95a93d
+	  case NT_GNU_BUILD_ATTRIBUTE_FUNC:
95a93d
+	    /* GNU Build Attributes store most data in the owner
95a93d
+	       name, which must start with the
95a93d
+	       ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX "GA".  */
95a93d
+	    if (nhdr.n_namesz >= sizeof ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX
95a93d
+		&& strncmp (data->d_buf + name_offset,
95a93d
+			    ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX,
95a93d
+			    strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)) == 0)
95a93d
+	      break;
95a93d
+	    else
95a93d
+	      goto unknown_note;
95a93d
+
95a93d
 	  case 0:
95a93d
 	    /* Linux vDSOs use a type 0 note for the kernel version word.  */
95a93d
 	    if (nhdr.n_namesz == sizeof "Linux"
95a93d
diff --git a/src/readelf.c b/src/readelf.c
95a93d
index 659e34f..3a73710 100644
95a93d
--- a/src/readelf.c
95a93d
+++ b/src/readelf.c
95a93d
@@ -12193,10 +12193,21 @@ handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
95a93d
       const char *name = nhdr.n_namesz == 0 ? "" : data->d_buf + name_offset;
95a93d
       const char *desc = data->d_buf + desc_offset;
95a93d
 
95a93d
+      /* GNU Build Attributes are weird, they store most of their data
95a93d
+	 into the owner name field.  Extract just the owner name
95a93d
+	 prefix here, then use the rest later as data.  */
95a93d
+      bool is_gnu_build_attr
95a93d
+	= strncmp (name, ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX,
95a93d
+		   strlen (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX)) == 0;
95a93d
+      const char *print_name = (is_gnu_build_attr
95a93d
+				? ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX : name);
95a93d
+      size_t print_namesz = (is_gnu_build_attr
95a93d
+			     ? strlen (print_name) : nhdr.n_namesz);
95a93d
+
95a93d
       char buf[100];
95a93d
       char buf2[100];
95a93d
       printf (gettext ("  %-13.*s  %9" PRId32 "  %s\n"),
95a93d
-	      (int) nhdr.n_namesz, name, nhdr.n_descsz,
95a93d
+	      (int) print_namesz, print_name, nhdr.n_descsz,
95a93d
 	      ehdr->e_type == ET_CORE
95a93d
 	      ? ebl_core_note_type_name (ebl, nhdr.n_type,
95a93d
 					 buf, sizeof (buf))
95a93d
@@ -12237,7 +12248,8 @@ handle_notes_data (Ebl *ebl, const GElf_Ehdr *ehdr,
95a93d
 		handle_core_note (ebl, &nhdr, name, desc);
95a93d
 	    }
95a93d
 	  else
95a93d
-	    ebl_object_note (ebl, name, nhdr.n_type, nhdr.n_descsz, desc);
95a93d
+	    ebl_object_note (ebl, nhdr.n_namesz, name, nhdr.n_type,
95a93d
+			     nhdr.n_descsz, desc);
95a93d
 	}
95a93d
     }
95a93d