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

Change-Id: I61cde98949e47e5c8c09c33260de17f30921be79
git-subtree-dir: third_party/elfutils
git-subtree-split: 555e15ebe8bf1eb33d00747173cfc80cc65648a4
diff --git a/libelf/elf_getshdrstrndx.c b/libelf/elf_getshdrstrndx.c
new file mode 100644
index 0000000..ad884fd
--- /dev/null
+++ b/libelf/elf_getshdrstrndx.c
@@ -0,0 +1,235 @@
+/* Return section index of section header string table.
+   Copyright (C) 2002, 2005, 2009, 2014, 2015 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 <assert.h>
+#include <errno.h>
+#include <gelf.h>
+#include <stddef.h>
+#include <unistd.h>
+
+#include <system.h>
+#include "libelfP.h"
+#include "common.h"
+
+
+int
+elf_getshdrstrndx (Elf *elf, size_t *dst)
+{
+  int result = 0;
+
+  if (elf == NULL)
+    return -1;
+
+  if (unlikely (elf->kind != ELF_K_ELF))
+    {
+      __libelf_seterrno (ELF_E_INVALID_HANDLE);
+      return -1;
+    }
+
+  rwlock_rdlock (elf->lock);
+
+  /* We rely here on the fact that the `elf' element is a common prefix
+     of `elf32' and `elf64'.  */
+  assert (offsetof (struct Elf, state.elf.ehdr)
+	  == offsetof (struct Elf, state.elf32.ehdr));
+  assert (sizeof (elf->state.elf.ehdr)
+	  == sizeof (elf->state.elf32.ehdr));
+  assert (offsetof (struct Elf, state.elf.ehdr)
+	  == offsetof (struct Elf, state.elf64.ehdr));
+  assert (sizeof (elf->state.elf.ehdr)
+	  == sizeof (elf->state.elf64.ehdr));
+
+  if (unlikely (elf->state.elf.ehdr == NULL))
+    {
+      __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
+      result = -1;
+    }
+  else
+    {
+      Elf32_Word num;
+
+      num = (elf->class == ELFCLASS32
+	     ? elf->state.elf32.ehdr->e_shstrndx
+	     : elf->state.elf64.ehdr->e_shstrndx);
+
+      /* Determine whether the index is too big to fit in the ELF
+	 header.  */
+      if (unlikely (num == SHN_XINDEX))
+	{
+	  /* Yes.  Search the zeroth section header.  */
+	  if (elf->class == ELFCLASS32)
+	    {
+	      size_t offset;
+	      if (unlikely (elf->state.elf32.scns.cnt == 0))
+		{
+		  /* Cannot use SHN_XINDEX without section headers.  */
+		  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
+		  result = -1;
+		  goto out;
+		}
+
+	      if (elf->state.elf32.scns.data[0].shdr.e32 != NULL)
+		{
+		  num = elf->state.elf32.scns.data[0].shdr.e32->sh_link;
+		  goto success;
+		}
+
+	      offset = elf->state.elf32.ehdr->e_shoff;
+
+	      if (elf->map_address != NULL
+		  && elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA
+		  && (ALLOW_UNALIGNED
+		      || (((size_t) ((char *) elf->map_address
+			   + elf->start_offset + offset))
+			  & (__alignof__ (Elf32_Shdr) - 1)) == 0))
+		{
+		  /* First see whether the information in the ELF header is
+		     valid and it does not ask for too much.  */
+		  if (unlikely (elf->maximum_size - offset
+				< sizeof (Elf32_Shdr)))
+		    {
+		      /* Something is wrong.  */
+		      __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
+		      result = -1;
+		      goto out;
+		    }
+
+		  /* We can directly access the memory.  */
+		  num = ((Elf32_Shdr *) (elf->map_address + elf->start_offset
+					 + offset))->sh_link;
+		}
+	      else
+		{
+		  /* We avoid reading in all the section headers.  Just read
+		     the first one.  */
+		  Elf32_Shdr shdr_mem;
+		  ssize_t r;
+
+		  if (unlikely ((r = pread_retry (elf->fildes, &shdr_mem,
+						  sizeof (Elf32_Shdr), offset))
+				!= sizeof (Elf32_Shdr)))
+		    {
+		      /* We must be able to read this ELF section header.  */
+		      if (r < 0)
+			__libelf_seterrno (ELF_E_INVALID_FILE);
+		      else
+			__libelf_seterrno (ELF_E_INVALID_ELF);
+		      result = -1;
+		      goto out;
+		    }
+
+		  if (elf->state.elf32.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
+		    CONVERT (shdr_mem.sh_link);
+		  num = shdr_mem.sh_link;
+		}
+	    }
+	  else
+	    {
+	      if (unlikely (elf->state.elf64.scns.cnt == 0))
+		{
+		  /* Cannot use SHN_XINDEX without section headers.  */
+		  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
+		  result = -1;
+		  goto out;
+		}
+
+	      if (elf->state.elf64.scns.data[0].shdr.e64 != NULL)
+		{
+		  num = elf->state.elf64.scns.data[0].shdr.e64->sh_link;
+		  goto success;
+		}
+
+	      size_t offset = elf->state.elf64.ehdr->e_shoff;
+
+	      if (elf->map_address != NULL
+		  && elf->state.elf64.ehdr->e_ident[EI_DATA] == MY_ELFDATA
+		  && (ALLOW_UNALIGNED
+		      || (((size_t) ((char *) elf->map_address
+			   + elf->start_offset + offset))
+			  & (__alignof__ (Elf64_Shdr) - 1)) == 0))
+		{
+		  /* First see whether the information in the ELF header is
+		     valid and it does not ask for too much.  */
+		  if (unlikely (elf->maximum_size - offset
+				< sizeof (Elf64_Shdr)))
+		    {
+		      /* Something is wrong.  */
+		      __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
+		      result = -1;
+		      goto out;
+		    }
+
+		  /* We can directly access the memory.  */
+		  num = ((Elf64_Shdr *) (elf->map_address + elf->start_offset
+					 + offset))->sh_link;
+		}
+	      else
+		{
+		  /* We avoid reading in all the section headers.  Just read
+		     the first one.  */
+		  Elf64_Shdr shdr_mem;
+		  ssize_t r;
+
+		  if (unlikely ((r = pread_retry (elf->fildes, &shdr_mem,
+						  sizeof (Elf64_Shdr), offset))
+				!= sizeof (Elf64_Shdr)))
+		    {
+		      /* We must be able to read this ELF section header.  */
+		      if (r < 0)
+			__libelf_seterrno (ELF_E_INVALID_FILE);
+		      else
+			__libelf_seterrno (ELF_E_INVALID_ELF);
+		      result = -1;
+		      goto out;
+		    }
+
+		  if (elf->state.elf64.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
+		    CONVERT (shdr_mem.sh_link);
+		  num = shdr_mem.sh_link;
+		}
+	    }
+	}
+
+      /* Store the result.  */
+    success:
+      *dst = num;
+    }
+
+ out:
+  rwlock_unlock (elf->lock);
+
+  return result;
+}
+INTDEF(elf_getshdrstrndx)
+/* Alias for the deprecated name.  */
+strong_alias (elf_getshdrstrndx, elf_getshstrndx)