Squashed 'third_party/elfutils/' content from commit 555e15e

Change-Id: I61cde98949e47e5c8c09c33260de17f30921be79
git-subtree-dir: third_party/elfutils
git-subtree-split: 555e15ebe8bf1eb33d00747173cfc80cc65648a4
diff --git a/libebl/eblobjnote.c b/libebl/eblobjnote.c
new file mode 100644
index 0000000..ca4f155
--- /dev/null
+++ b/libebl/eblobjnote.c
@@ -0,0 +1,233 @@
+/* Print contents of object file note.
+   Copyright (C) 2002, 2007, 2009, 2011, 2015, 2016 Red Hat, Inc.
+   This file is part of elfutils.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libeblP.h>
+
+
+void
+ebl_object_note (Ebl *ebl, const char *name, uint32_t type,
+		 uint32_t descsz, const char *desc)
+{
+  if (! ebl->object_note (name, type, descsz, desc))
+    {
+      /* The machine specific function did not know this type.  */
+
+      if (strcmp ("stapsdt", name) == 0)
+	{
+	  if (type != 3)
+	    {
+	      printf (gettext ("unknown SDT version %u\n"), type);
+	      return;
+	    }
+
+	  /* Descriptor starts with three addresses, pc, base ref and
+	     semaphore.  Then three zero terminated strings provider,
+	     name and arguments.  */
+
+	  union
+	  {
+	    Elf64_Addr a64[3];
+	    Elf32_Addr a32[3];
+	  } addrs;
+
+	  size_t addrs_size = gelf_fsize (ebl->elf, ELF_T_ADDR, 3, EV_CURRENT);
+	  if (descsz < addrs_size + 3)
+	    {
+	    invalid_sdt:
+	      printf (gettext ("invalid SDT probe descriptor\n"));
+	      return;
+	    }
+
+	  Elf_Data src =
+	    {
+	      .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
+	      .d_buf = (void *) desc, .d_size = addrs_size
+	    };
+
+	  Elf_Data dst =
+	    {
+	      .d_type = ELF_T_ADDR, .d_version = EV_CURRENT,
+	      .d_buf = &addrs, .d_size = addrs_size
+	    };
+
+	  if (gelf_xlatetom (ebl->elf, &dst, &src,
+			     elf_getident (ebl->elf, NULL)[EI_DATA]) == NULL)
+	    {
+	      printf ("%s\n", elf_errmsg (-1));
+	      return;
+	    }
+
+	  const char *provider = desc + addrs_size;
+	  const char *pname = memchr (provider, '\0', desc + descsz - provider);
+	  if (pname == NULL)
+	    goto invalid_sdt;
+
+	  ++pname;
+	  const char *args = memchr (pname, '\0', desc + descsz - pname);
+	  if (args == NULL ||
+	      memchr (++args, '\0', desc + descsz - pname) != desc + descsz - 1)
+	    goto invalid_sdt;
+
+	  GElf_Addr pc;
+	  GElf_Addr base;
+	  GElf_Addr sem;
+	  if (gelf_getclass (ebl->elf) == ELFCLASS32)
+	    {
+	      pc = addrs.a32[0];
+	      base = addrs.a32[1];
+	      sem = addrs.a32[2];
+	    }
+	  else
+	    {
+	      pc = addrs.a64[0];
+	      base = addrs.a64[1];
+	      sem = addrs.a64[2];
+	    }
+
+	  printf (gettext ("    PC: "));
+	  printf ("%#" PRIx64 ",", pc);
+	  printf (gettext (" Base: "));
+	  printf ("%#" PRIx64 ",", base);
+	  printf (gettext (" Semaphore: "));
+	  printf ("%#" PRIx64 "\n", sem);
+	  printf (gettext ("    Provider: "));
+	  printf ("%s,", provider);
+	  printf (gettext (" Name: "));
+	  printf ("%s,", pname);
+	  printf (gettext (" Args: "));
+	  printf ("'%s'\n", args);
+	  return;
+	}
+
+      switch (type)
+	{
+	case NT_GNU_BUILD_ID:
+	  if (strcmp (name, "GNU") == 0 && descsz > 0)
+	    {
+	      printf (gettext ("    Build ID: "));
+	      uint_fast32_t i;
+	      for (i = 0; i < descsz - 1; ++i)
+		printf ("%02" PRIx8, (uint8_t) desc[i]);
+	      printf ("%02" PRIx8 "\n", (uint8_t) desc[i]);
+	    }
+	  break;
+
+	case NT_GNU_GOLD_VERSION:
+	  if (strcmp (name, "GNU") == 0 && descsz > 0)
+	    /* A non-null terminated version string.  */
+	    printf (gettext ("    Linker version: %.*s\n"),
+		    (int) descsz, desc);
+	  break;
+
+	case NT_GNU_ABI_TAG:
+	  if (strcmp (name, "GNU") == 0 && descsz >= 8 && descsz % 4 == 0)
+	    {
+	      Elf_Data in =
+		{
+		  .d_version = EV_CURRENT,
+		  .d_type = ELF_T_WORD,
+		  .d_size = descsz,
+		  .d_buf = (void *) desc
+		};
+	      /* Normally NT_GNU_ABI_TAG is just 4 words (16 bytes).  If it
+		 is much (4*) larger dynamically allocate memory to convert.  */
+#define FIXED_TAG_BYTES 16
+	      uint32_t sbuf[FIXED_TAG_BYTES];
+	      uint32_t *buf;
+	      if (unlikely (descsz / 4 > FIXED_TAG_BYTES))
+		{
+		  buf = malloc (descsz);
+		  if (unlikely (buf == NULL))
+		    return;
+		}
+	      else
+		buf = sbuf;
+	      Elf_Data out =
+		{
+		  .d_version = EV_CURRENT,
+		  .d_type = ELF_T_WORD,
+		  .d_size = descsz,
+		  .d_buf = buf
+		};
+
+	      if (elf32_xlatetom (&out, &in, ebl->data) != NULL)
+		{
+		  const char *os;
+		  switch (buf[0])
+		    {
+		    case ELF_NOTE_OS_LINUX:
+		      os = "Linux";
+		      break;
+
+		    case ELF_NOTE_OS_GNU:
+		      os = "GNU";
+		      break;
+
+		    case ELF_NOTE_OS_SOLARIS2:
+		      os = "Solaris";
+		      break;
+
+		    case ELF_NOTE_OS_FREEBSD:
+		      os = "FreeBSD";
+		      break;
+
+		    default:
+		      os = "???";
+		      break;
+		    }
+
+		  printf (gettext ("    OS: %s, ABI: "), os);
+		  for (size_t cnt = 1; cnt < descsz / 4; ++cnt)
+		    {
+		      if (cnt > 1)
+			putchar_unlocked ('.');
+		      printf ("%" PRIu32, buf[cnt]);
+		    }
+		  putchar_unlocked ('\n');
+		}
+	      if (descsz / 4 > FIXED_TAG_BYTES)
+		free (buf);
+	      break;
+	    }
+	  FALLTHROUGH;
+
+	default:
+	  /* Unknown type.  */
+	  break;
+	}
+    }
+}