125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Pedantic checking of ELF files compliance with gABI/psABI spec.
225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Copyright (C) 2001-2012 Red Hat, Inc.
325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   This file is part of Red Hat elfutils.
425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Written by Ulrich Drepper <drepper@redhat.com>, 2001.
525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is free software; you can redistribute it and/or modify
725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   it under the terms of the GNU General Public License as published by the
825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Free Software Foundation; version 2 of the License.
925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
1025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is distributed in the hope that it will be useful, but
1125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
1225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   General Public License for more details.
1425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
1525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   You should have received a copy of the GNU General Public License along
1625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   with Red Hat elfutils; if not, write to the Free Software Foundation,
1725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
1825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
1925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is an included package of the Open Invention Network.
2025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   An included package of the Open Invention Network is a package for which
2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Open Invention Network licensees cross-license their patents.  No patent
2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   license is granted, either expressly or impliedly, by designation as an
2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   included package.  Should you wish to participate in the Open Invention
2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Network licensing program, please visit www.openinventionnetwork.com
2525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   <http://www.openinventionnetwork.com>.  */
2625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#ifdef HAVE_CONFIG_H
2825b3c049e70834cf33790a28643ab058b507b35cBen Cheng# include <config.h>
2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
3025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <argp.h>
3225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <assert.h>
3325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <byteswap.h>
3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <endian.h>
3525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <error.h>
3625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <fcntl.h>
3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <gelf.h>
3825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <inttypes.h>
3925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <libintl.h>
4025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <locale.h>
4125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <stdbool.h>
4225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <stdlib.h>
4325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <string.h>
4425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <unistd.h>
4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <sys/stat.h>
4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <sys/param.h>
4725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <elf-knowledge.h>
4925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <system.h>
5025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "../libelf/libelfP.h"
5125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "../libelf/common.h"
5225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "../libebl/libeblP.h"
5325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "../libdw/libdwP.h"
5425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "../libdwfl/libdwflP.h"
5525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "../libdw/memory-access.h"
5625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Name and version of program.  */
5925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void print_version (FILE *stream, struct argp_state *state);
6025b3c049e70834cf33790a28643ab058b507b35cBen ChengARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
6125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6225b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Bug report address.  */
6325b3c049e70834cf33790a28643ab058b507b35cBen ChengARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
6425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define ARGP_strict	300
6625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define ARGP_gnuld	301
6725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Definitions of arguments for argp functions.  */
6925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic const struct argp_option options[] =
7025b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
7125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  { "strict", ARGP_strict, NULL, 0,
7225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    N_("Be extremely strict, flag level 2 features."), 0 },
7325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  { "quiet", 'q', NULL, 0, N_("Do not print anything if successful"), 0 },
7425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  { "debuginfo", 'd', NULL, 0, N_("Binary is a separate debuginfo file"), 0 },
7525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  { "gnu-ld", ARGP_gnuld, NULL, 0,
7625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    N_("Binary has been created with GNU ld and is therefore known to be \
7725b3c049e70834cf33790a28643ab058b507b35cBen Chengbroken in certain ways"), 0 },
7825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  { NULL, 0, NULL, 0, NULL, 0 }
7925b3c049e70834cf33790a28643ab058b507b35cBen Cheng};
8025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
8125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Short description of program.  */
8225b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic const char doc[] = N_("\
8325b3c049e70834cf33790a28643ab058b507b35cBen ChengPedantic checking of ELF files compliance with gABI/psABI spec.");
8425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
8525b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Strings for arguments in help texts.  */
8625b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic const char args_doc[] = N_("FILE...");
8725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
8825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Prototype for option handler.  */
8925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic error_t parse_opt (int key, char *arg, struct argp_state *state);
9025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Data structure to communicate with argp functions.  */
9225b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic struct argp argp =
9325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
9425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  options, parse_opt, args_doc, doc, NULL, NULL, NULL
9525b3c049e70834cf33790a28643ab058b507b35cBen Cheng};
9625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Declarations of local functions.  */
9925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void process_file (int fd, Elf *elf, const char *prefix,
10025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  const char *suffix, const char *fname, size_t size,
10125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  bool only_one);
10225b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void process_elf_file (Elf *elf, const char *prefix, const char *suffix,
10325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      const char *fname, size_t size, bool only_one);
10425b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void check_note_section (Ebl *ebl, GElf_Ehdr *ehdr,
10525b3c049e70834cf33790a28643ab058b507b35cBen Cheng				GElf_Shdr *shdr, int idx);
10625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
10725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
10825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Report an error.  */
10925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define ERROR(str, args...) \
11025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  do {									      \
11125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    printf (str, ##args);						      \
11225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ++error_count;							      \
11325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  } while (0)
11425b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic unsigned int error_count;
11525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
11625b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* True if we should perform very strict testing.  */
11725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool be_strict;
11825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
11925b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* True if no message is to be printed if the run is succesful.  */
12025b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool be_quiet;
12125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12225b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* True if binary is from strip -f, not a normal ELF file.  */
12325b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool is_debuginfo;
12425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12525b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* True if binary is assumed to be generated with GNU ld.  */
12625b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool gnuld;
12725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
12825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Index of section header string table.  */
12925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic uint32_t shstrndx;
13025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
13125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Array to count references in section groups.  */
13225b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int *scnref;
13325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
13425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
13525b3c049e70834cf33790a28643ab058b507b35cBen Chengint
13625b3c049e70834cf33790a28643ab058b507b35cBen Chengmain (int argc, char *argv[])
13725b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
13825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Set locale.  */
13925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  setlocale (LC_ALL, "");
14025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
14125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Initialize the message catalog.  */
14225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  textdomain (PACKAGE_TARNAME);
14325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
14425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Parse and process arguments.  */
14525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int remaining;
14625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
14725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
14825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Before we start tell the ELF library which version we are using.  */
14925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  elf_version (EV_CURRENT);
15025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
15125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Now process all the files given at the command line.  */
15225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool only_one = remaining + 1 == argc;
15325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  do
15425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
15525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Open the file.  */
15625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      int fd = open (argv[remaining], O_RDONLY);
15725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (fd == -1)
15825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
15925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  error (0, errno, gettext ("cannot open input file"));
16025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
16125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
16225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
16325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Create an `Elf' descriptor.  */
16425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
16525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf == NULL)
16625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("cannot generate Elf descriptor: %s\n"),
16725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       elf_errmsg (-1));
16825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
16925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
17025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  unsigned int prev_error_count = error_count;
17125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  struct stat64 st;
17225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (fstat64 (fd, &st) != 0)
17425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
17525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      printf ("cannot stat '%s': %m\n", argv[remaining]);
17625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      close (fd);
17725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      continue;
17825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
17925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
18025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  process_file (fd, elf, NULL, NULL, argv[remaining], st.st_size,
18125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			only_one);
18225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
18325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Now we can close the descriptor.  */
18425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (elf_end (elf) != 0)
18525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("error while closing Elf descriptor: %s\n"),
18625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   elf_errmsg (-1));
18725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
18825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (prev_error_count == error_count && !be_quiet)
18925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    puts (gettext ("No errors"));
19025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
19125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
19225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      close (fd);
19325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
19425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (++remaining < argc);
19525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
19625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return error_count != 0;
19725b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
19825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
19925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20025b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Handle program arguments.  */
20125b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic error_t
20225b3c049e70834cf33790a28643ab058b507b35cBen Chengparse_opt (int key, char *arg __attribute__ ((unused)),
20325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   struct argp_state *state __attribute__ ((unused)))
20425b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
20525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  switch (key)
20625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
20725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ARGP_strict:
20825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      be_strict = true;
20925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
21025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
21125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case 'q':
21225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      be_quiet = true;
21325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
21425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
21525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case 'd':
21625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      is_debuginfo = true;
21725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
21825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ARGP_gnuld:
21925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      gnuld = true;
22025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
22125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
22225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ARGP_KEY_NO_ARGS:
22325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      fputs (gettext ("Missing file name.\n"), stderr);
22425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      argp_help (&argp, stderr, ARGP_HELP_SEE, program_invocation_short_name);
22525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      exit (EXIT_FAILURE);
22625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
22725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    default:
22825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return ARGP_ERR_UNKNOWN;
22925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
23025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return 0;
23125b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
23225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23425b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Print the version information.  */
23525b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
23625b3c049e70834cf33790a28643ab058b507b35cBen Chengprint_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
23725b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
23825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  fprintf (stream, "elflint (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
23925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  fprintf (stream, gettext ("\
24025b3c049e70834cf33790a28643ab058b507b35cBen ChengCopyright (C) %s Red Hat, Inc.\n\
24125b3c049e70834cf33790a28643ab058b507b35cBen ChengThis is free software; see the source for copying conditions.  There is NO\n\
24225b3c049e70834cf33790a28643ab058b507b35cBen Chengwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
24325b3c049e70834cf33790a28643ab058b507b35cBen Cheng"), "2012");
24425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
24525b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
24625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Process one file.  */
24925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
25025b3c049e70834cf33790a28643ab058b507b35cBen Chengprocess_file (int fd, Elf *elf, const char *prefix, const char *suffix,
25125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      const char *fname, size_t size, bool only_one)
25225b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
25325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* We can handle two types of files: ELF files and archives.  */
25425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Kind kind = elf_kind (elf);
25525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
25625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  switch (kind)
25725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
25825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELF_K_ELF:
25925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Yes!  It's an ELF file.  */
26025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      process_elf_file (elf, prefix, suffix, fname, size, only_one);
26125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
26225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELF_K_AR:
26425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
26525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	Elf *subelf;
26625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	Elf_Cmd cmd = ELF_C_READ_MMAP;
26725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
26825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	size_t fname_len = strlen (fname) + 1;
26925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	char new_prefix[prefix_len + 1 + fname_len];
27025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	char new_suffix[(suffix == NULL ? 0 : strlen (suffix)) + 2];
27125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	char *cp = new_prefix;
27225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	/* Create the full name of the file.  */
27425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (prefix != NULL)
27525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
27625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    cp = mempcpy (cp, prefix, prefix_len);
27725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    *cp++ = '(';
27825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    strcpy (stpcpy (new_suffix, suffix), ")");
27925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
28025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	else
28125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  new_suffix[0] = '\0';
28225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	memcpy (cp, fname, fname_len);
28325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
28425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	/* It's an archive.  We process each file in it.  */
28525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
28625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
28725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    kind = elf_kind (subelf);
28825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
28925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    /* Call this function recursively.  */
29025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (kind == ELF_K_ELF || kind == ELF_K_AR)
29125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
29225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		Elf_Arhdr *arhdr = elf_getarhdr (subelf);
29325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		assert (arhdr != NULL);
29425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		process_file (fd, subelf, new_prefix, new_suffix,
29625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      arhdr->ar_name, arhdr->ar_size, false);
29725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      }
29825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    /* Get next archive element.  */
30025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    cmd = elf_next (subelf);
30125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (elf_end (subelf) != 0)
30225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext (" error while freeing sub-ELF descriptor: %s\n"),
30325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     elf_errmsg (-1));
30425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
30525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
30625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
30725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    default:
30925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* We cannot do anything.  */
31025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
31125b3c049e70834cf33790a28643ab058b507b35cBen ChengNot an ELF file - it has the wrong magic bytes at the start\n"));
31225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
31325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
31425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
31525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic const char *
31825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection_name (Ebl *ebl, int idx)
31925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
32025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr shdr_mem;
32125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *shdr;
32225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
32325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  shdr = gelf_getshdr (elf_getscn (ebl->elf, idx), &shdr_mem);
32425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
32525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
32625b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
32725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
32825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
32925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic const int valid_e_machine[] =
33025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
33125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    EM_M32, EM_SPARC, EM_386, EM_68K, EM_88K, EM_860, EM_MIPS, EM_S370,
33225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    EM_MIPS_RS3_LE, EM_PARISC, EM_VPP500, EM_SPARC32PLUS, EM_960, EM_PPC,
33325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    EM_PPC64, EM_S390, EM_V800, EM_FR20, EM_RH32, EM_RCE, EM_ARM,
33425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    EM_FAKE_ALPHA, EM_SH, EM_SPARCV9, EM_TRICORE, EM_ARC, EM_H8_300,
33525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    EM_H8_300H, EM_H8S, EM_H8_500, EM_IA_64, EM_MIPS_X, EM_COLDFIRE,
33625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    EM_68HC12, EM_MMA, EM_PCP, EM_NCPU, EM_NDR1, EM_STARCORE, EM_ME16,
33725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    EM_ST100, EM_TINYJ, EM_X86_64, EM_PDSP, EM_FX66, EM_ST9PLUS, EM_ST7,
33825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    EM_68HC16, EM_68HC11, EM_68HC08, EM_68HC05, EM_SVX, EM_ST19, EM_VAX,
33925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    EM_CRIS, EM_JAVELIN, EM_FIREPATH, EM_ZSP, EM_MMIX, EM_HUANY, EM_PRISM,
34025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    EM_AVR, EM_FR30, EM_D10V, EM_D30V, EM_V850, EM_M32R, EM_MN10300,
34125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    EM_MN10200, EM_PJ, EM_OPENRISC, EM_ARC_A5, EM_XTENSA, EM_ALPHA
34225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  };
34325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define nvalid_e_machine \
34425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  (sizeof (valid_e_machine) / sizeof (valid_e_machine[0]))
34525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
34625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
34725b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Numbers of sections and program headers.  */
34825b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic unsigned int shnum;
34925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic unsigned int phnum;
35025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
35125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
35225b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
35325b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_elf_header (Ebl *ebl, GElf_Ehdr *ehdr, size_t size)
35425b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
35525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  char buf[512];
35625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t cnt;
35725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
35825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check e_ident field.  */
35925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_ident[EI_MAG0] != ELFMAG0)
36025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR ("e_ident[%d] != '%c'\n", EI_MAG0, ELFMAG0);
36125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_ident[EI_MAG1] != ELFMAG1)
36225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR ("e_ident[%d] != '%c'\n", EI_MAG1, ELFMAG1);
36325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_ident[EI_MAG2] != ELFMAG2)
36425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR ("e_ident[%d] != '%c'\n", EI_MAG2, ELFMAG2);
36525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_ident[EI_MAG3] != ELFMAG3)
36625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR ("e_ident[%d] != '%c'\n", EI_MAG3, ELFMAG3);
36725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
36825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_ident[EI_CLASS] != ELFCLASS32
36925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && ehdr->e_ident[EI_CLASS] != ELFCLASS64)
37025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("e_ident[%d] == %d is no known class\n"),
37125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   EI_CLASS, ehdr->e_ident[EI_CLASS]);
37225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
37325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB
37425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
37525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("e_ident[%d] == %d is no known data encoding\n"),
37625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   EI_DATA, ehdr->e_ident[EI_DATA]);
37725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
37825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_ident[EI_VERSION] != EV_CURRENT)
37925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("unknown ELF header version number e_ident[%d] == %d\n"),
38025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   EI_VERSION, ehdr->e_ident[EI_VERSION]);
38125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
38225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* We currently don't handle any OS ABIs other than Linux.  */
38325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE
38425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && ehdr->e_ident[EI_OSABI] != ELFOSABI_LINUX)
38525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("unsupported OS ABI e_ident[%d] == '%s'\n"),
38625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   EI_OSABI,
38725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf)));
38825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
38925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* No ABI versions other than zero supported either.  */
39025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_ident[EI_ABIVERSION] != 0)
39125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("unsupport ABI version e_ident[%d] == %d\n"),
39225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   EI_ABIVERSION, ehdr->e_ident[EI_ABIVERSION]);
39325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
39425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (cnt = EI_PAD; cnt < EI_NIDENT; ++cnt)
39525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (ehdr->e_ident[cnt] != 0)
39625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("e_ident[%zu] is not zero\n"), cnt);
39725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
39825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the e_type field.  */
39925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_type != ET_REL && ehdr->e_type != ET_EXEC
40025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && ehdr->e_type != ET_DYN && ehdr->e_type != ET_CORE)
40125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("unknown object file type %d\n"), ehdr->e_type);
40225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
40325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the e_machine field.  */
40425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (cnt = 0; cnt < nvalid_e_machine; ++cnt)
40525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (valid_e_machine[cnt] == ehdr->e_machine)
40625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
40725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (cnt == nvalid_e_machine)
40825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("unknown machine type %d\n"), ehdr->e_machine);
40925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
41025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the e_version field.  */
41125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_version != EV_CURRENT)
41225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("unknown object file version\n"));
41325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
41425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the e_phoff and e_phnum fields.  */
41525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_phoff == 0)
41625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
41725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_phnum != 0)
41825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid program header offset\n"));
41925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)
42025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
42125b3c049e70834cf33790a28643ab058b507b35cBen Chengexecutables and DSOs cannot have zero program header offset\n"));
42225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
42325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else if (ehdr->e_phnum == 0)
42425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("invalid number of program header entries\n"));
42525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
42625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the e_shoff field.  */
42725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  shnum = ehdr->e_shnum;
42825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  shstrndx = ehdr->e_shstrndx;
42925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_shoff == 0)
43025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
43125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_shnum != 0)
43225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid section header table offset\n"));
43325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN
43425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       && ehdr->e_type != ET_CORE)
43525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section header table must be present\n"));
43625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
43725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
43825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
43925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_shnum == 0)
44025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
44125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Get the header of the zeroth section.  The sh_size field
44225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     might contain the section number.  */
44325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr shdr_mem;
44425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
44525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (shdr != NULL)
44625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
44725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* The error will be reported later.  */
44825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (shdr->sh_size == 0)
44925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
45025b3c049e70834cf33790a28643ab058b507b35cBen Chenginvalid number of section header table entries\n"));
45125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      else
45225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		shnum = shdr->sh_size;
45325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
45425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
45525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
45625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_shstrndx == SHN_XINDEX)
45725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
45825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Get the header of the zeroth section.  The sh_size field
45925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     might contain the section number.  */
46025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr shdr_mem;
46125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
46225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (shdr != NULL && shdr->sh_link < shnum)
46325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    shstrndx = shdr->sh_link;
46425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
46525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (shstrndx >= shnum)
46625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid section header index\n"));
46725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
46825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
46925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  phnum = ehdr->e_phnum;
47025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_phnum == PN_XNUM)
47125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
47225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Get the header of the zeroth section.  The sh_info field
47325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 might contain the phnum count.  */
47425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Shdr shdr_mem;
47525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
47625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr != NULL)
47725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
47825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* The error will be reported later.  */
47925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (shdr->sh_info < PN_XNUM)
48025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
48125b3c049e70834cf33790a28643ab058b507b35cBen Chenginvalid number of program header table entries\n"));
48225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
48325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    phnum = shdr->sh_info;
48425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
48525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
48625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
48725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the e_flags field.  */
48825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (!ebl_machine_flag_check (ebl, ehdr->e_flags))
48925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("invalid machine flags: %s\n"),
49025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf)));
49125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
49225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check e_ehsize, e_phentsize, and e_shentsize fields.  */
49325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (gelf_getclass (ebl->elf) == ELFCLASS32)
49425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
49525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_ehsize != 0 && ehdr->e_ehsize != sizeof (Elf32_Ehdr))
49625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid ELF header size: %hd\n"), ehdr->e_ehsize);
49725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
49825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf32_Phdr))
49925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid program header size: %hd\n"),
50025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       ehdr->e_phentsize);
50125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (ehdr->e_phoff + phnum * ehdr->e_phentsize > size)
50225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid program header position or size\n"));
50325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
50425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf32_Shdr))
50525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid section header size: %hd\n"),
50625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       ehdr->e_shentsize);
50725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (ehdr->e_shoff + shnum * ehdr->e_shentsize > size)
50825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid section header position or size\n"));
50925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
51025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else if (gelf_getclass (ebl->elf) == ELFCLASS64)
51125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
51225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_ehsize != 0 && ehdr->e_ehsize != sizeof (Elf64_Ehdr))
51325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid ELF header size: %hd\n"), ehdr->e_ehsize);
51425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
51525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf64_Phdr))
51625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid program header size: %hd\n"),
51725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       ehdr->e_phentsize);
51825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (ehdr->e_phoff + phnum * ehdr->e_phentsize > size)
51925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid program header position or size\n"));
52025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
52125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf64_Shdr))
52225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid section header size: %hd\n"),
52325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       ehdr->e_shentsize);
52425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size)
52525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("invalid section header position or size\n"));
52625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
52725b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
52825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
52925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
53025b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Check that there is a section group section with index < IDX which
53125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   contains section IDX and that there is exactly one.  */
53225b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
53325b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_scn_group (Ebl *ebl, int idx)
53425b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
53525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (scnref[idx] == 0)
53625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
53725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* No reference so far.  Search following sections, maybe the
53825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 order is wrong.  */
53925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      size_t cnt;
54025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
54125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      for (cnt = idx + 1; cnt < shnum; ++cnt)
54225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
54325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf_Scn *scn = elf_getscn (ebl->elf, cnt);
54425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr shdr_mem;
54525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
54625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (shdr == NULL)
54725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    /* We cannot get the section header so we cannot check it.
54825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       The error to get the section header will be shown
54925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       somewhere else.  */
55025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    continue;
55125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
55225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (shdr->sh_type != SHT_GROUP)
55325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    continue;
55425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
55525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf_Data *data = elf_getdata (scn, NULL);
55625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (data == NULL || data->d_size < sizeof (Elf32_Word))
55725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    /* Cannot check the section.  */
55825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    continue;
55925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
56025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf32_Word *grpdata = (Elf32_Word *) data->d_buf;
56125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  for (size_t inner = 1; inner < data->d_size / sizeof (Elf32_Word);
56225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       ++inner)
56325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (grpdata[inner] == (Elf32_Word) idx)
56425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      goto out;
56525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
56625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
56725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    out:
56825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (cnt == shnum)
56925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
57025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section with SHF_GROUP flag set not part of a section group\n"),
57125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
57225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
57325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
57425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section group [%2zu] '%s' does not precede group member\n"),
57525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx),
57625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       cnt, section_name (ebl, cnt));
57725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
57825b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
57925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
58025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
58125b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
58225b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_symtab (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
58325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
58425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool no_xndx_warned = false;
58525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int no_pt_tls = 0;
58625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
58725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
58825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
58925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
59025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
59125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
59225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
59325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
59425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr strshdr_mem;
59525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
59625b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     &strshdr_mem);
59725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (strshdr == NULL)
59825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
59925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
60025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (strshdr->sh_type != SHT_STRTAB)
60125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
60225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"),
60325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     shdr->sh_link, section_name (ebl, shdr->sh_link),
60425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
60525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      strshdr = NULL;
60625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
60725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
60825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Search for an extended section index table section.  */
60925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *xndxdata = NULL;
61025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf32_Word xndxscnidx = 0;
61125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool found_xndx = false;
61225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (size_t cnt = 1; cnt < shnum; ++cnt)
61325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (cnt != (size_t) idx)
61425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
61525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	Elf_Scn *xndxscn = elf_getscn (ebl->elf, cnt);
61625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Shdr xndxshdr_mem;
61725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
61825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (xndxshdr == NULL)
61925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
62025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
62125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX
62225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    && xndxshdr->sh_link == (GElf_Word) idx)
62325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
62425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (found_xndx)
62525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
62625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol table cannot have more than one extended index section\n"),
62725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     idx, section_name (ebl, idx));
62825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
62925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    xndxdata = elf_getdata (xndxscn, NULL);
63025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    xndxscnidx = elf_ndxscn (xndxscn);
63125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    found_xndx = true;
63225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
63325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
63425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
63525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT))
63625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
63725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2u] '%s': entry size is does not match ElfXX_Sym\n"),
63825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
63925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
64025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Test the zeroth entry.  */
64125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Sym sym_mem;
64225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf32_Word xndx;
64325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, 0, &sym_mem, &xndx);
64425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (sym == NULL)
64525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': cannot get symbol %d: %s\n"),
64625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx), 0, elf_errmsg (-1));
64725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
64825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
64925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sym->st_name != 0)
65025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
65125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "st_name");
65225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sym->st_value != 0)
65325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
65425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "st_value");
65525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sym->st_size != 0)
65625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
65725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "st_size");
65825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sym->st_info != 0)
65925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
66025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "st_info");
66125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sym->st_other != 0)
66225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
66325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "st_other");
66425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sym->st_shndx != 0)
66525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
66625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "st_shndx");
66725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (xndxdata != NULL && xndx != 0)
66825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
66925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': XINDEX for zeroth entry not zero\n"),
67025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       xndxscnidx, section_name (ebl, xndxscnidx));
67125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
67225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
67325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (size_t cnt = 1; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
67425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
67525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem, &xndx);
67625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sym == NULL)
67725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
67825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("section [%2d] '%s': cannot get symbol %zu: %s\n"),
67925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx), cnt, elf_errmsg (-1));
68025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
68125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
68225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
68325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const char *name = NULL;
68425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (strshdr == NULL)
68525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	name = "";
68625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (sym->st_name >= strshdr->sh_size)
68725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
68825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: invalid name value\n"),
68925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
69025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
69125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
69225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  name = elf_strptr (ebl->elf, shdr->sh_link, sym->st_name);
69325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  assert (name != NULL);
69425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
69525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
69625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sym->st_shndx == SHN_XINDEX)
69725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
69825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (xndxdata == NULL)
69925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
70025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (!no_xndx_warned)
70125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
70225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: too large section index but no extended section index section\n"),
70325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx), cnt);
70425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      no_xndx_warned = true;
70525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
70625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else if (xndx < SHN_LORESERVE)
70725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
70825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: XINDEX used for index which would fit in st_shndx (%" PRIu32 ")\n"),
70925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   xndxscnidx, section_name (ebl, xndxscnidx), cnt,
71025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   xndx);
71125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
71225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if ((sym->st_shndx >= SHN_LORESERVE
71325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		// && sym->st_shndx <= SHN_HIRESERVE    always true
71425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		&& sym->st_shndx != SHN_ABS
71525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		&& sym->st_shndx != SHN_COMMON)
71625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       || (sym->st_shndx >= shnum
71725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   && (sym->st_shndx < SHN_LORESERVE
71825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       /* || sym->st_shndx > SHN_HIRESERVE  always false */)))
71925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
72025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: invalid section index\n"),
72125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
72225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
72325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	xndx = sym->st_shndx;
72425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
72525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (GELF_ST_TYPE (sym->st_info) >= STT_NUM
72625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && !ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info), NULL, 0))
72725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': symbol %zu: unknown type\n"),
72825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
72925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
73025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (GELF_ST_BIND (sym->st_info) >= STB_NUM
73125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && !ebl_symbol_binding_name (ebl, GELF_ST_BIND (sym->st_info), NULL,
73225b3c049e70834cf33790a28643ab058b507b35cBen Cheng				       0))
73325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
73425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: unknown symbol binding\n"),
73525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
73625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (GELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE
73725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && GELF_ST_TYPE (sym->st_info) != STT_OBJECT)
73825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
73925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: unique symbol not of object type\n"),
74025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
74125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
74225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (xndx == SHN_COMMON)
74325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
74425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Common symbols can only appear in relocatable files.  */
74525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (ehdr->e_type != ET_REL)
74625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
74725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: COMMON only allowed in relocatable files\n"),
74825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), cnt);
74925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (cnt < shdr->sh_info)
75025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
75125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: local COMMON symbols are nonsense\n"),
75225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), cnt);
75325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (GELF_R_TYPE (sym->st_info) == STT_FUNC)
75425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
75525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"),
75625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), cnt);
75725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
75825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (xndx > 0 && xndx < shnum)
75925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
76025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr destshdr_mem;
76125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr *destshdr;
76225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
76325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  destshdr = gelf_getshdr (elf_getscn (ebl->elf, xndx), &destshdr_mem);
76425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (destshdr != NULL)
76525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
76625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Addr sh_addr = (ehdr->e_type == ET_REL ? 0
76725b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   : destshdr->sh_addr);
76825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (GELF_ST_TYPE (sym->st_info) != STT_TLS)
76925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
77025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (! ebl_check_special_symbol (ebl, ehdr, sym, name,
77125b3c049e70834cf33790a28643ab058b507b35cBen Cheng						  destshdr))
77225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
77325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (sym->st_value - sh_addr > destshdr->sh_size)
77425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			{
77525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  /* GNU ld has severe bugs.  When it decides to remove
77625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     empty sections it leaves symbols referencing them
77725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     behind.  These are symbols in .symtab.  */
77825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  if (!gnuld
77925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      || strcmp (section_name (ebl, idx), ".symtab")
78025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      || (strcmp (name, "__preinit_array_start") != 0
78125b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  && strcmp (name, "__preinit_array_end") != 0
78225b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  && strcmp (name, "__init_array_start") != 0
78325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  && strcmp (name, "__init_array_end") != 0
78425b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  && strcmp (name, "__fini_array_start") != 0
78525b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  && strcmp (name, "__fini_array_end") != 0))
78625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    ERROR (gettext ("\
78725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: st_value out of bounds\n"),
78825b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   idx, section_name (ebl, idx), cnt);
78925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			}
79025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      else if ((sym->st_value - sh_addr
79125b3c049e70834cf33790a28643ab058b507b35cBen Cheng				+ sym->st_size) > destshdr->sh_size)
79225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
79325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"),
79425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       idx, section_name (ebl, idx), cnt,
79525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       (int) xndx, section_name (ebl, xndx));
79625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
79725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
79825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      else
79925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
80025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if ((destshdr->sh_flags & SHF_TLS) == 0)
80125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    ERROR (gettext ("\
80225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: referenced section [%2d] '%s' does not have SHF_TLS flag set\n"),
80325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   idx, section_name (ebl, idx), cnt,
80425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   (int) xndx, section_name (ebl, xndx));
80525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
80625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (ehdr->e_type == ET_REL)
80725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
80825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      /* For object files the symbol value must fall
80925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 into the section.  */
81025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (sym->st_value > destshdr->sh_size)
81125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
81225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"),
81325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       idx, section_name (ebl, idx), cnt,
81425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       (int) xndx, section_name (ebl, xndx));
81525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      else if (sym->st_value + sym->st_size
81625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       > destshdr->sh_size)
81725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
81825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"),
81925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       idx, section_name (ebl, idx), cnt,
82025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       (int) xndx, section_name (ebl, xndx));
82125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
82225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  else
82325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
82425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      GElf_Phdr phdr_mem;
82525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      GElf_Phdr *phdr = NULL;
82625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      unsigned int pcnt;
82725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
82825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      for (pcnt = 0; pcnt < phnum; ++pcnt)
82925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			{
83025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem);
83125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  if (phdr != NULL && phdr->p_type == PT_TLS)
83225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    break;
83325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			}
83425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
83525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (pcnt == phnum)
83625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			{
83725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  if (no_pt_tls++ == 0)
83825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    ERROR (gettext ("\
83925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: TLS symbol but no TLS program header entry\n"),
84025b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   idx, section_name (ebl, idx), cnt);
84125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			}
84225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      else
84325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			{
84425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  if (sym->st_value
84525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      < destshdr->sh_offset - phdr->p_offset)
84625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    ERROR (gettext ("\
84725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: st_value short of referenced section [%2d] '%s'\n"),
84825b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   idx, section_name (ebl, idx), cnt,
84925b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   (int) xndx, section_name (ebl, xndx));
85025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  else if (sym->st_value
85125b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   > (destshdr->sh_offset - phdr->p_offset
85225b3c049e70834cf33790a28643ab058b507b35cBen Cheng				      + destshdr->sh_size))
85325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    ERROR (gettext ("\
85425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"),
85525b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   idx, section_name (ebl, idx), cnt,
85625b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   (int) xndx, section_name (ebl, xndx));
85725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  else if (sym->st_value + sym->st_size
85825b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   > (destshdr->sh_offset - phdr->p_offset
85925b3c049e70834cf33790a28643ab058b507b35cBen Cheng				      + destshdr->sh_size))
86025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    ERROR (gettext ("\
86125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"),
86225b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   idx, section_name (ebl, idx), cnt,
86325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   (int) xndx, section_name (ebl, xndx));
86425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			}
86525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
86625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
86725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
86825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
86925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
87025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (GELF_ST_BIND (sym->st_info) == STB_LOCAL)
87125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
87225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (cnt >= shdr->sh_info)
87325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
87425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: local symbol outside range described in sh_info\n"),
87525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), cnt);
87625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
87725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
87825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
87925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (cnt < shdr->sh_info)
88025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
88125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: non-local symbol outside range described in sh_info\n"),
88225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), cnt);
88325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
88425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
88525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (GELF_ST_TYPE (sym->st_info) == STT_SECTION
88625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && GELF_ST_BIND (sym->st_info) != STB_LOCAL)
88725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
88825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: non-local section symbol\n"),
88925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
89025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
89125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (name != NULL)
89225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
89325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
89425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
89525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* Check that address and size match the global offset table.  */
89625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
89725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Shdr destshdr_mem;
89825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, xndx),
89925b3c049e70834cf33790a28643ab058b507b35cBen Cheng						  &destshdr_mem);
90025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
90125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (destshdr == NULL && xndx == SHN_ABS)
90225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
90325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  /* In a DSO, we have to find the GOT section by name.  */
90425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  Elf_Scn *gotscn = NULL;
90525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  Elf_Scn *gscn = NULL;
90625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  while ((gscn = elf_nextscn (ebl->elf, gscn)) != NULL)
90725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
90825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      destshdr = gelf_getshdr (gscn, &destshdr_mem);
90925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      assert (destshdr != NULL);
91025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      const char *sname = elf_strptr (ebl->elf,
91125b3c049e70834cf33790a28643ab058b507b35cBen Cheng						      ehdr->e_shstrndx,
91225b3c049e70834cf33790a28643ab058b507b35cBen Cheng						      destshdr->sh_name);
91325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (sname != NULL)
91425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			{
91525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  if (strcmp (sname, ".got.plt") == 0)
91625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    break;
91725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  if (strcmp (sname, ".got") == 0)
91825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    /* Do not stop looking.
91925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       There might be a .got.plt section.  */
92025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    gotscn = gscn;
92125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			}
92225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
92325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      destshdr = NULL;
92425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
92525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
92625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (destshdr == NULL && gotscn != NULL)
92725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    destshdr = gelf_getshdr (gotscn, &destshdr_mem);
92825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
92925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
93025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      const char *sname = ((destshdr == NULL || xndx == SHN_UNDEF)
93125b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   ? NULL
93225b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   : elf_strptr (ebl->elf, ehdr->e_shstrndx,
93325b3c049e70834cf33790a28643ab058b507b35cBen Cheng						 destshdr->sh_name));
93425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (sname == NULL)
93525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
93625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (xndx != SHN_UNDEF || ehdr->e_type != ET_REL)
93725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    ERROR (gettext ("\
93825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to \
93925b3c049e70834cf33790a28643ab058b507b35cBen Chengbad section [%2d]\n"),
94025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   idx, section_name (ebl, idx), xndx);
94125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
94225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      else if (strcmp (sname, ".got.plt") != 0
94325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       && strcmp (sname, ".got") != 0)
94425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
94525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to \
94625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s'\n"),
94725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx), xndx, sname);
94825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
94925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (destshdr != NULL)
95025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
95125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  /* Found it.  */
95225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (!ebl_check_special_symbol (ebl, ehdr, sym, name,
95325b3c049e70834cf33790a28643ab058b507b35cBen Cheng						 destshdr))
95425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
95525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (ehdr->e_type != ET_REL
95625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  && sym->st_value != destshdr->sh_addr)
95725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			/* This test is more strict than the psABIs which
95825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   usually allow the symbol to be in the middle of
95925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   the .got section, allowing negative offsets.  */
96025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
96125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol value %#" PRIx64 " does not match %s section address %#" PRIx64 "\n"),
96225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       idx, section_name (ebl, idx),
96325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       (uint64_t) sym->st_value,
96425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       sname, (uint64_t) destshdr->sh_addr);
96525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
96625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (!gnuld && sym->st_size != destshdr->sh_size)
96725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
96825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol size %" PRIu64 " does not match %s section size %" PRIu64 "\n"),
96925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       idx, section_name (ebl, idx),
97025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       (uint64_t) sym->st_size,
97125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       sname, (uint64_t) destshdr->sh_size);
97225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
97325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
97425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      else
97525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
97625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol present, but no .got section\n"),
97725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx));
97825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
97925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else if (strcmp (name, "_DYNAMIC") == 0)
98025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    /* Check that address and size match the dynamic section.
98125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       We locate the dynamic section via the program header
98225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       entry.  */
98325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    for (unsigned int pcnt = 0; pcnt < phnum; ++pcnt)
98425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
98525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		GElf_Phdr phdr_mem;
98625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		GElf_Phdr *phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem);
98725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
98825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
98925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
99025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if (sym->st_value != phdr->p_vaddr)
99125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
99225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': _DYNAMIC_ symbol value %#" PRIx64 " does not match dynamic segment address %#" PRIx64 "\n"),
99325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     idx, section_name (ebl, idx),
99425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     (uint64_t) sym->st_value,
99525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     (uint64_t) phdr->p_vaddr);
99625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
99725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if (!gnuld && sym->st_size != phdr->p_memsz)
99825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
99925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': _DYNAMIC symbol size %" PRIu64 " does not match dynamic segment size %" PRIu64 "\n"),
100025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     idx, section_name (ebl, idx),
100125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     (uint64_t) sym->st_size,
100225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     (uint64_t) phdr->p_memsz);
100325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
100425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    break;
100525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  }
100625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
100725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
100825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
100925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (GELF_ST_VISIBILITY (sym->st_other) != STV_DEFAULT
101025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && shdr->sh_type == SHT_DYNSYM)
101125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
101225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: symbol in dynamic symbol table with non-default visibility\n"),
101325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
101425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (! ebl_check_st_other_bits (ebl, sym->st_other))
101525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
101625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %zu: unknown bit set in st_other\n"),
101725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
101825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
101925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
102025b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
102125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
102225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
102325b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool
102425b3c049e70834cf33790a28643ab058b507b35cBen Chengis_rel_dyn (Ebl *ebl, const GElf_Ehdr *ehdr, int idx, const GElf_Shdr *shdr,
102525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    bool is_rela)
102625b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
102725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* If this is no executable or DSO it cannot be a .rel.dyn section.  */
102825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
102925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return false;
103025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
103125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the section name.  Unfortunately necessary.  */
103225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (strcmp (section_name (ebl, idx), is_rela ? ".rela.dyn" : ".rel.dyn"))
103325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return false;
103425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
103525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* When a .rel.dyn section is used a DT_RELCOUNT dynamic section
103625b3c049e70834cf33790a28643ab058b507b35cBen Cheng     entry can be present as well.  */
103725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *scn = NULL;
103825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
103925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
104025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Shdr rcshdr_mem;
104125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const GElf_Shdr *rcshdr = gelf_getshdr (scn, &rcshdr_mem);
104225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      assert (rcshdr != NULL);
104325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
104425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (rcshdr->sh_type == SHT_DYNAMIC)
104525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
104625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Found the dynamic section.  Look through it.  */
104725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf_Data *d = elf_getdata (scn, NULL);
104825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  size_t cnt;
104925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
105025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  for (cnt = 1; cnt < rcshdr->sh_size / rcshdr->sh_entsize; ++cnt)
105125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
105225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Dyn dyn_mem;
105325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Dyn *dyn = gelf_getdyn (d, cnt, &dyn_mem);
105425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      assert (dyn != NULL);
105525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
105625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (dyn->d_tag == DT_RELCOUNT)
105725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
105825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  /* Found it.  Does the type match.  */
105925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (is_rela)
106025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    ERROR (gettext ("\
106125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': DT_RELCOUNT used for this RELA section\n"),
106225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   idx, section_name (ebl, idx));
106325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  else
106425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
106525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      /* Does the number specified number of relative
106625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 relocations exceed the total number of
106725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 relocations?  */
106825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (dyn->d_un.d_val > shdr->sh_size / shdr->sh_entsize)
106925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
107025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"),
107125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       idx, section_name (ebl, idx),
107225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       (int) dyn->d_un.d_val);
107325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
107425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      /* Make sure the specified number of relocations are
107525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 relative.  */
107625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf,
107725b3c049e70834cf33790a28643ab058b507b35cBen Cheng								   idx), NULL);
107825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (reldata != NULL)
107925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			for (size_t inner = 0;
108025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     inner < shdr->sh_size / shdr->sh_entsize;
108125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     ++inner)
108225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  {
108325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    GElf_Rel rel_mem;
108425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    GElf_Rel *rel = gelf_getrel (reldata, inner,
108525b3c049e70834cf33790a28643ab058b507b35cBen Cheng							 &rel_mem);
108625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    if (rel == NULL)
108725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      /* The problem will be reported elsewhere.  */
108825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      break;
108925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
109025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    if (ebl_relative_reloc_p (ebl,
109125b3c049e70834cf33790a28643ab058b507b35cBen Cheng						      GELF_R_TYPE (rel->r_info)))
109225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      {
109325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				if (inner >= dyn->d_un.d_val)
109425b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  ERROR (gettext ("\
109525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': relative relocations after index %d as specified by DT_RELCOUNT\n"),
109625b3c049e70834cf33790a28643ab058b507b35cBen Cheng					 idx, section_name (ebl, idx),
109725b3c049e70834cf33790a28643ab058b507b35cBen Cheng					 (int) dyn->d_un.d_val);
109825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      }
109925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    else if (inner < dyn->d_un.d_val)
110025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      ERROR (gettext ("\
110125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': non-relative relocation at index %zu; DT_RELCOUNT specified %d relative relocations\n"),
110225b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     idx, section_name (ebl, idx),
110325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     inner, (int) dyn->d_un.d_val);
110425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  }
110525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
110625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
110725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
110825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (dyn->d_tag == DT_RELACOUNT)
110925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
111025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  /* Found it.  Does the type match.  */
111125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (!is_rela)
111225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    ERROR (gettext ("\
111325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': DT_RELACOUNT used for this REL section\n"),
111425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   idx, section_name (ebl, idx));
111525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  else
111625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
111725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      /* Does the number specified number of relative
111825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 relocations exceed the total number of
111925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 relocations?  */
112025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (dyn->d_un.d_val > shdr->sh_size / shdr->sh_entsize)
112125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
112225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"),
112325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       idx, section_name (ebl, idx),
112425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       (int) dyn->d_un.d_val);
112525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
112625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      /* Make sure the specified number of relocations are
112725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 relative.  */
112825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf,
112925b3c049e70834cf33790a28643ab058b507b35cBen Cheng								   idx), NULL);
113025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (reldata != NULL)
113125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			for (size_t inner = 0;
113225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     inner < shdr->sh_size / shdr->sh_entsize;
113325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     ++inner)
113425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  {
113525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    GElf_Rela rela_mem;
113625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    GElf_Rela *rela = gelf_getrela (reldata, inner,
113725b3c049e70834cf33790a28643ab058b507b35cBen Cheng							    &rela_mem);
113825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    if (rela == NULL)
113925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      /* The problem will be reported elsewhere.  */
114025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      break;
114125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
114225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    if (ebl_relative_reloc_p (ebl,
114325b3c049e70834cf33790a28643ab058b507b35cBen Cheng						      GELF_R_TYPE (rela->r_info)))
114425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      {
114525b3c049e70834cf33790a28643ab058b507b35cBen Cheng				if (inner >= dyn->d_un.d_val)
114625b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  ERROR (gettext ("\
114725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': relative relocations after index %d as specified by DT_RELCOUNT\n"),
114825b3c049e70834cf33790a28643ab058b507b35cBen Cheng					 idx, section_name (ebl, idx),
114925b3c049e70834cf33790a28643ab058b507b35cBen Cheng					 (int) dyn->d_un.d_val);
115025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      }
115125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    else if (inner < dyn->d_un.d_val)
115225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      ERROR (gettext ("\
115325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': non-relative relocation at index %zu; DT_RELCOUNT specified %d relative relocations\n"),
115425b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     idx, section_name (ebl, idx),
115525b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     inner, (int) dyn->d_un.d_val);
115625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  }
115725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
115825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
115925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
116025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
116125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
116225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
116325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
116425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
116525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return true;
116625b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
116725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
116825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
116925b3c049e70834cf33790a28643ab058b507b35cBen Chengstruct loaded_segment
117025b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
117125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr from;
117225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr to;
117325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool read_only;
117425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  struct loaded_segment *next;
117525b3c049e70834cf33790a28643ab058b507b35cBen Cheng};
117625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
117725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
117825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Check whether binary has text relocation flag set.  */
117925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool textrel;
118025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
118125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Keep track of whether text relocation flag is needed.  */
118225b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool needed_textrel;
118325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
118425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
118525b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool
118625b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_reloc_shdr (Ebl *ebl, const GElf_Ehdr *ehdr, const GElf_Shdr *shdr,
118725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  int idx, int reltype, GElf_Shdr **destshdrp,
118825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  GElf_Shdr *destshdr_memp, struct loaded_segment **loadedp)
118925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
119025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool reldyn = false;
119125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
119225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check whether the link to the section we relocate is reasonable.  */
119325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_info >= shnum)
119425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2d] '%s': invalid destination section index\n"),
119525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
119625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else if (shdr->sh_info != 0)
119725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
119825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      *destshdrp = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
119925b3c049e70834cf33790a28643ab058b507b35cBen Cheng				 destshdr_memp);
120025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (*destshdrp != NULL)
120125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
120225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if((*destshdrp)->sh_type != SHT_PROGBITS
120325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     && (*destshdrp)->sh_type != SHT_NOBITS)
120425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
120525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      reldyn = is_rel_dyn (ebl, ehdr, idx, shdr, true);
120625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (!reldyn)
120725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
120825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': invalid destination section type\n"),
120925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx));
121025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      else
121125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
121225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  /* There is no standard, but we require that .rel{,a}.dyn
121325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     sections have a sh_info value of zero.  */
121425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (shdr->sh_info != 0)
121525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    ERROR (gettext ("\
121625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': sh_info should be zero\n"),
121725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   idx, section_name (ebl, idx));
121825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
121925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
122025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
122125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (((*destshdrp)->sh_flags & (SHF_MERGE | SHF_STRINGS)) != 0)
122225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
122325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': no relocations for merge-able sections possible\n"),
122425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx));
122525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
122625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
122725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
122825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_entsize != gelf_fsize (ebl->elf, reltype, 1, EV_CURRENT))
122925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext (reltype == ELF_T_RELA ? "\
123025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section entry size does not match ElfXX_Rela\n" : "\
123125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section entry size does not match ElfXX_Rel\n"),
123225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
123325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
123425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* In preparation of checking whether relocations are text
123525b3c049e70834cf33790a28643ab058b507b35cBen Cheng     relocations or not we need to determine whether the file is
123625b3c049e70834cf33790a28643ab058b507b35cBen Cheng     flagged to have text relocation and we need to determine a) what
123725b3c049e70834cf33790a28643ab058b507b35cBen Cheng     the loaded segments are and b) which are read-only.  This will
123825b3c049e70834cf33790a28643ab058b507b35cBen Cheng     also allow us to determine whether the same reloc section is
123925b3c049e70834cf33790a28643ab058b507b35cBen Cheng     modifying loaded and not loaded segments.  */
124025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (unsigned int i = 0; i < phnum; ++i)
124125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
124225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Phdr phdr_mem;
124325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Phdr *phdr = gelf_getphdr (ebl->elf, i, &phdr_mem);
124425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr == NULL)
124525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	continue;
124625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
124725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr->p_type == PT_LOAD)
124825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
124925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  struct loaded_segment *newp = xmalloc (sizeof (*newp));
125025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  newp->from = phdr->p_vaddr;
125125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  newp->to = phdr->p_vaddr + phdr->p_memsz;
125225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  newp->read_only = (phdr->p_flags & PF_W) == 0;
125325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  newp->next = *loadedp;
125425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  *loadedp = newp;
125525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
125625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (phdr->p_type == PT_DYNAMIC)
125725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
125825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf_Scn *dynscn = gelf_offscn (ebl->elf, phdr->p_offset);
125925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr dynshdr_mem;
126025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr *dynshdr = gelf_getshdr (dynscn, &dynshdr_mem);
126125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf_Data *dyndata = elf_getdata (dynscn, NULL);
126225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (dynshdr != NULL && dynshdr->sh_type == SHT_DYNAMIC
126325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      && dyndata != NULL)
126425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    for (size_t j = 0; j < dynshdr->sh_size / dynshdr->sh_entsize; ++j)
126525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
126625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		GElf_Dyn dyn_mem;
126725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		GElf_Dyn *dyn = gelf_getdyn (dyndata, j, &dyn_mem);
126825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		if (dyn != NULL
126925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    && (dyn->d_tag == DT_TEXTREL
127025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			|| (dyn->d_tag == DT_FLAGS
127125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    && (dyn->d_un.d_val & DF_TEXTREL) != 0)))
127225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
127325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    textrel = true;
127425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    break;
127525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  }
127625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      }
127725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
127825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
127925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
128025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* A quick test which can be easily done here (although it is a bit
128125b3c049e70834cf33790a28643ab058b507b35cBen Cheng     out of place): the text relocation flag makes only sense if there
128225b3c049e70834cf33790a28643ab058b507b35cBen Cheng     is a segment which is not writable.  */
128325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (textrel)
128425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
128525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      struct loaded_segment *seg = *loadedp;
128625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      while (seg != NULL && !seg->read_only)
128725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	seg = seg->next;
128825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (seg == NULL)
128925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
129025b3c049e70834cf33790a28643ab058b507b35cBen Chengtext relocation flag set but there is no read-only segment\n"));
129125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
129225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
129325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return reldyn;
129425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
129525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
129625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
129725b3c049e70834cf33790a28643ab058b507b35cBen Chengenum load_state
129825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
129925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    state_undecided,
130025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    state_loaded,
130125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    state_unloaded,
130225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    state_error
130325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  };
130425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
130525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
130625b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
130725b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_one_reloc (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *relshdr, int idx,
130825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 size_t cnt, const GElf_Shdr *symshdr, Elf_Data *symdata,
130925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 GElf_Addr r_offset, GElf_Xword r_info,
131025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 const GElf_Shdr *destshdr, bool reldyn,
131125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 struct loaded_segment *loaded, enum load_state *statep)
131225b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
131325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool known_broken = gnuld;
131425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
131525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (!ebl_reloc_type_check (ebl, GELF_R_TYPE (r_info)))
131625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2d] '%s': relocation %zu: invalid type\n"),
131725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), cnt);
131825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else if (((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
131925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    /* The executable/DSO can contain relocation sections with
132025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       all the relocations the linker has applied.  Those sections
132125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       are marked non-loaded, though.  */
132225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    || (relshdr->sh_flags & SHF_ALLOC) != 0)
132325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   && !ebl_reloc_valid_use (ebl, GELF_R_TYPE (r_info)))
132425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
132525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': relocation %zu: relocation type invalid for the file type\n"),
132625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), cnt);
132725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
132825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symshdr != NULL
132925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && ((GELF_R_SYM (r_info) + 1)
133025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  * gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT)
133125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  > symshdr->sh_size))
133225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
133325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': relocation %zu: invalid symbol index\n"),
133425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), cnt);
133525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
133625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* No more tests if this is a no-op relocation.  */
133725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ebl_none_reloc_p (ebl, GELF_R_TYPE (r_info)))
133825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
133925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
134025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ebl_gotpc_reloc_check (ebl, GELF_R_TYPE (r_info)))
134125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
134225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const char *name;
134325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      char buf[64];
134425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Sym sym_mem;
134525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (r_info), &sym_mem);
134625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sym != NULL
134725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Get the name for the symbol.  */
134825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && (name = elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name))
134925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && strcmp (name, "_GLOBAL_OFFSET_TABLE_") !=0 )
135025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
135125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': relocation %zu: only symbol '_GLOBAL_OFFSET_TABLE_' can be used with %s\n"),
135225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt,
135325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       ebl_reloc_type_name (ebl, GELF_R_SYM (r_info),
135425b3c049e70834cf33790a28643ab058b507b35cBen Cheng				    buf, sizeof (buf)));
135525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
135625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
135725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (reldyn)
135825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
135925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      // XXX TODO Check .rel.dyn section addresses.
136025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
136125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else if (!known_broken)
136225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
136325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (destshdr != NULL
136425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && GELF_R_TYPE (r_info) != 0
136525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && (r_offset - (ehdr->e_type == ET_REL ? 0
136625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  : destshdr->sh_addr)) >= destshdr->sh_size)
136725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
136825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': relocation %zu: offset out of bounds\n"),
136925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
137025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
137125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
137225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Sym sym_mem;
137325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (r_info), &sym_mem);
137425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
137525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ebl_copy_reloc_p (ebl, GELF_R_TYPE (r_info))
137625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Make sure the referenced symbol is an object or unspecified.  */
137725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && sym != NULL
137825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && GELF_ST_TYPE (sym->st_info) != STT_NOTYPE
137925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && GELF_ST_TYPE (sym->st_info) != STT_OBJECT)
138025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
138125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      char buf[64];
138225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': relocation %zu: copy relocation against symbol of type %s\n"),
138325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx), cnt,
138425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info),
138525b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   buf, sizeof (buf)));
138625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
138725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
138825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
138925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      || (relshdr->sh_flags & SHF_ALLOC) != 0)
139025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
139125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      bool in_loaded_seg = false;
139225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      while (loaded != NULL)
139325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
139425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (r_offset < loaded->to
139525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      && r_offset + (sym == NULL ? 0 : sym->st_size) >= loaded->from)
139625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
139725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* The symbol is in this segment.  */
139825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if  (loaded->read_only)
139925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
140025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (textrel)
140125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    needed_textrel = true;
140225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  else
140325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    ERROR (gettext ("section [%2d] '%s': relocation %zu: read-only section modified but text relocation flag not set\n"),
140425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   idx, section_name (ebl, idx), cnt);
140525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
140625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
140725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      in_loaded_seg = true;
140825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
140925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
141025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  loaded = loaded->next;
141125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
141225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
141325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (*statep == state_undecided)
141425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	*statep = in_loaded_seg ? state_loaded : state_unloaded;
141525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if ((*statep == state_unloaded && in_loaded_seg)
141625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       || (*statep == state_loaded && !in_loaded_seg))
141725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
141825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
141925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': relocations are against loaded and unloaded data\n"),
142025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx));
142125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  *statep = state_error;
142225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
142325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
142425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
142525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
142625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
142725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
142825b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_rela (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
142925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
143025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
143125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
143225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
143325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
143425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
143525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
143625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
143725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
143825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the fields of the section header.  */
143925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr destshdr_mem;
144025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *destshdr = NULL;
144125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  struct loaded_segment *loaded = NULL;
144225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool reldyn = check_reloc_shdr (ebl, ehdr, shdr, idx, ELF_T_RELA, &destshdr,
144325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  &destshdr_mem, &loaded);
144425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
144525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
144625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr symshdr_mem;
144725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
144825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *symdata = elf_getdata (symscn, NULL);
144925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  enum load_state state = state_undecided;
145025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
145125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (size_t cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
145225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
145325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Rela rela_mem;
145425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Rela *rela = gelf_getrela (data, cnt, &rela_mem);
145525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (rela == NULL)
145625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
145725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
145825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': cannot get relocation %zu: %s\n"),
145925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx), cnt, elf_errmsg (-1));
146025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
146125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
146225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
146325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      check_one_reloc (ebl, ehdr, shdr, idx, cnt, symshdr, symdata,
146425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       rela->r_offset, rela->r_info, destshdr, reldyn, loaded,
146525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       &state);
146625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
146725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
146825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (loaded != NULL)
146925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
147025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      struct loaded_segment *old = loaded;
147125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      loaded = loaded->next;
147225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      free (old);
147325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
147425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
147525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
147625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
147725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
147825b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_rel (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
147925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
148025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
148125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
148225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
148325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
148425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
148525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
148625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
148725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
148825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the fields of the section header.  */
148925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr destshdr_mem;
149025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *destshdr = NULL;
149125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  struct loaded_segment *loaded = NULL;
149225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool reldyn = check_reloc_shdr (ebl, ehdr, shdr, idx, ELF_T_REL, &destshdr,
149325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  &destshdr_mem, &loaded);
149425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
149525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
149625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr symshdr_mem;
149725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
149825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *symdata = elf_getdata (symscn, NULL);
149925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  enum load_state state = state_undecided;
150025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
150125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (size_t cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
150225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
150325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Rel rel_mem;
150425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Rel *rel = gelf_getrel (data, cnt, &rel_mem);
150525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (rel == NULL)
150625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
150725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
150825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': cannot get relocation %zu: %s\n"),
150925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx), cnt, elf_errmsg (-1));
151025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
151125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
151225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
151325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      check_one_reloc (ebl, ehdr, shdr, idx, cnt, symshdr, symdata,
151425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       rel->r_offset, rel->r_info, destshdr, reldyn, loaded,
151525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       &state);
151625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
151725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
151825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (loaded != NULL)
151925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
152025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      struct loaded_segment *old = loaded;
152125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      loaded = loaded->next;
152225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      free (old);
152325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
152425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
152525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
152625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
152725b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Number of dynamic sections.  */
152825b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int ndynamic;
152925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
153025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
153125b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
153225b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
153325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
153425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data;
153525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr strshdr_mem;
153625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *strshdr;
153725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t cnt;
153825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  static const bool dependencies[DT_NUM][DT_NUM] =
153925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
154025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_NEEDED] = { [DT_STRTAB] = true },
154125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_PLTRELSZ] = { [DT_JMPREL] = true },
154225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_HASH] = { [DT_SYMTAB] = true },
154325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_STRTAB] = { [DT_STRSZ] = true },
154425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_SYMTAB] = { [DT_STRTAB] = true, [DT_SYMENT] = true },
154525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_RELA] = { [DT_RELASZ] = true, [DT_RELAENT] = true },
154625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_RELASZ] = { [DT_RELA] = true },
154725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_RELAENT] = { [DT_RELA] = true },
154825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_STRSZ] = { [DT_STRTAB] = true },
154925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_SYMENT] = { [DT_SYMTAB] = true },
155025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_SONAME] = { [DT_STRTAB] = true },
155125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_RPATH] = { [DT_STRTAB] = true },
155225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_REL] = { [DT_RELSZ] = true, [DT_RELENT] = true },
155325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_RELSZ] = { [DT_REL] = true },
155425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_RELENT] = { [DT_REL] = true },
155525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_JMPREL] = { [DT_PLTRELSZ] = true, [DT_PLTREL] = true },
155625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_RUNPATH] = { [DT_STRTAB] = true },
155725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_PLTREL] = { [DT_JMPREL] = true },
155825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    };
155925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool has_dt[DT_NUM];
156025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool has_val_dt[DT_VALNUM];
156125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool has_addr_dt[DT_ADDRNUM];
156225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  static const bool level2[DT_NUM] =
156325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
156425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_RPATH] = true,
156525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_SYMBOLIC] = true,
156625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_TEXTREL] = true,
156725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_BIND_NOW] = true
156825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    };
156925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  static const bool mandatory[DT_NUM] =
157025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
157125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_NULL] = true,
157225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_STRTAB] = true,
157325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_SYMTAB] = true,
157425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_STRSZ] = true,
157525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      [DT_SYMENT] = true
157625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    };
157725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
157825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  memset (has_dt, '\0', sizeof (has_dt));
157925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  memset (has_val_dt, '\0', sizeof (has_val_dt));
158025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  memset (has_addr_dt, '\0', sizeof (has_addr_dt));
158125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
158225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (++ndynamic == 2)
158325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("more than one dynamic section present\n"));
158425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
158525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
158625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
158725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
158825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
158925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
159025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
159125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
159225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
159325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &strshdr_mem);
159425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (strshdr != NULL && strshdr->sh_type != SHT_STRTAB)
159525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
159625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"),
159725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   shdr->sh_link, section_name (ebl, shdr->sh_link),
159825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
159925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
160025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT))
160125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
160225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section entry size does not match ElfXX_Dyn\n"),
160325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
160425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
160525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_info != 0)
160625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2d] '%s': sh_info not zero\n"),
160725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
160825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
160925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool non_null_warned = false;
161025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
161125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
161225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Dyn dyn_mem;
161325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dyn_mem);
161425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (dyn == NULL)
161525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
161625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
161725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': cannot get dynamic section entry %zu: %s\n"),
161825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx), cnt, elf_errmsg (-1));
161925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
162025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
162125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
162225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (has_dt[DT_NULL] && dyn->d_tag != DT_NULL && ! non_null_warned)
162325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
162425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
162525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': non-DT_NULL entries follow DT_NULL entry\n"),
162625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx));
162725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  non_null_warned = true;
162825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
162925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
163025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (!ebl_dynamic_tag_check (ebl, dyn->d_tag))
163125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': entry %zu: unknown tag\n"),
163225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
163325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
163425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (dyn->d_tag >= 0 && dyn->d_tag < DT_NUM)
163525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
163625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (has_dt[dyn->d_tag]
163725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      && dyn->d_tag != DT_NEEDED
163825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      && dyn->d_tag != DT_NULL
163925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      && dyn->d_tag != DT_POSFLAG_1)
164025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
164125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      char buf[50];
164225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
164325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %zu: more than one entry with tag %s\n"),
164425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     idx, section_name (ebl, idx), cnt,
164525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     ebl_dynamic_tag_name (ebl, dyn->d_tag,
164625b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   buf, sizeof (buf)));
164725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
164825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
164925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (be_strict && level2[dyn->d_tag])
165025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
165125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      char buf[50];
165225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
165325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %zu: level 2 tag %s used\n"),
165425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     idx, section_name (ebl, idx), cnt,
165525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     ebl_dynamic_tag_name (ebl, dyn->d_tag,
165625b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   buf, sizeof (buf)));
165725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
165825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
165925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  has_dt[dyn->d_tag] = true;
166025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
166125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (dyn->d_tag <= DT_VALRNGHI
166225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       && DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
166325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	has_val_dt[DT_VALTAGIDX (dyn->d_tag)] = true;
166425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (dyn->d_tag <= DT_ADDRRNGHI
166525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       && DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
166625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	has_addr_dt[DT_ADDRTAGIDX (dyn->d_tag)] = true;
166725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
166825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (dyn->d_tag == DT_PLTREL && dyn->d_un.d_val != DT_REL
166925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && dyn->d_un.d_val != DT_RELA)
167025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
167125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %zu: DT_PLTREL value must be DT_REL or DT_RELA\n"),
167225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
167325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
167425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Check that addresses for entries are in loaded segments.  */
167525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      switch (dyn->d_tag)
167625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
167725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  size_t n;
167825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_STRTAB:
167925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* We require the referenced section is the same as the one
168025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     specified in sh_link.  */
168125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (strshdr->sh_addr != dyn->d_un.d_val)
168225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
168325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
168425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %zu: pointer does not match address of section [%2d] '%s' referenced by sh_link\n"),
168525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     idx, section_name (ebl, idx), cnt,
168625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     shdr->sh_link, section_name (ebl, shdr->sh_link));
168725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      break;
168825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
168925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  goto check_addr;
169025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
169125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	default:
169225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (dyn->d_tag < DT_ADDRRNGLO || dyn->d_tag > DT_ADDRRNGHI)
169325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    /* Value is no pointer.  */
169425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    break;
169525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* FALLTHROUGH */
169625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
169725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_AUXILIARY:
169825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_FILTER:
169925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_FINI:
170025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_FINI_ARRAY:
170125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_HASH:
170225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_INIT:
170325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_INIT_ARRAY:
170425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_JMPREL:
170525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_PLTGOT:
170625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_REL:
170725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_RELA:
170825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_SYMBOLIC:
170925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_SYMTAB:
171025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_VERDEF:
171125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_VERNEED:
171225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_VERSYM:
171325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	check_addr:
171425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  for (n = 0; n < phnum; ++n)
171525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
171625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Phdr phdr_mem;
171725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Phdr *phdr = gelf_getphdr (ebl->elf, n, &phdr_mem);
171825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (phdr != NULL && phdr->p_type == PT_LOAD
171925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  && phdr->p_vaddr <= dyn->d_un.d_ptr
172025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  && phdr->p_vaddr + phdr->p_memsz > dyn->d_un.d_ptr)
172125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		break;
172225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
172325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (unlikely (n >= phnum))
172425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
172525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      char buf[50];
172625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
172725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %zu: %s value must point into loaded segment\n"),
172825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     idx, section_name (ebl, idx), cnt,
172925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     ebl_dynamic_tag_name (ebl, dyn->d_tag, buf,
173025b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   sizeof (buf)));
173125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
173225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
173325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
173425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_NEEDED:
173525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_RPATH:
173625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_RUNPATH:
173725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case DT_SONAME:
173825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (dyn->d_un.d_ptr >= strshdr->sh_size)
173925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
174025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      char buf[50];
174125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
174225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %zu: %s value must be valid offset in section [%2d] '%s'\n"),
174325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     idx, section_name (ebl, idx), cnt,
174425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     ebl_dynamic_tag_name (ebl, dyn->d_tag, buf,
174525b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   sizeof (buf)),
174625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     shdr->sh_link, section_name (ebl, shdr->sh_link));
174725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
174825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
174925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
175025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
175125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
175225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (cnt = 1; cnt < DT_NUM; ++cnt)
175325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (has_dt[cnt])
175425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
175525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	for (int inner = 0; inner < DT_NUM; ++inner)
175625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (dependencies[cnt][inner] && ! has_dt[inner])
175725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
175825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      char buf1[50];
175925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      char buf2[50];
176025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
176125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
176225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': contains %s entry but not %s\n"),
176325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     idx, section_name (ebl, idx),
176425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     ebl_dynamic_tag_name (ebl, cnt, buf1, sizeof (buf1)),
176525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     ebl_dynamic_tag_name (ebl, inner, buf2, sizeof (buf2)));
176625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
176725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
176825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    else
176925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
177025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (mandatory[cnt])
177125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
177225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    char buf[50];
177325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
177425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': mandatory tag %s not present\n"),
177525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx),
177625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   ebl_dynamic_tag_name (ebl, cnt, buf, sizeof (buf)));
177725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
177825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
177925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
178025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Make sure we have an hash table.  */
178125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (!has_dt[DT_HASH] && !has_addr_dt[DT_ADDRTAGIDX (DT_GNU_HASH)])
178225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
178325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': no hash section present\n"),
178425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
178525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
178625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* The GNU-style hash table also needs a symbol table.  */
178725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (!has_dt[DT_HASH] && has_addr_dt[DT_ADDRTAGIDX (DT_GNU_HASH)]
178825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && !has_dt[DT_SYMTAB])
178925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
179025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': contains %s entry but not %s\n"),
179125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx),
179225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   "DT_GNU_HASH", "DT_SYMTAB");
179325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
179425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the rel/rela tags.  At least one group must be available.  */
179525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((has_dt[DT_RELA] || has_dt[DT_RELASZ] || has_dt[DT_RELAENT])
179625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && (!has_dt[DT_RELA] || !has_dt[DT_RELASZ] || !has_dt[DT_RELAENT]))
179725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
179825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': not all of %s, %s, and %s are present\n"),
179925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx),
180025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   "DT_RELA", "DT_RELASZ", "DT_RELAENT");
180125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
180225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((has_dt[DT_REL] || has_dt[DT_RELSZ] || has_dt[DT_RELENT])
180325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && (!has_dt[DT_REL] || !has_dt[DT_RELSZ] || !has_dt[DT_RELENT]))
180425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
180525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': not all of %s, %s, and %s are present\n"),
180625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx),
180725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   "DT_REL", "DT_RELSZ", "DT_RELENT");
180825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
180925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check that all prelink sections are present if any of them is.  */
181025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (has_val_dt[DT_VALTAGIDX (DT_GNU_PRELINKED)]
181125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      || has_val_dt[DT_VALTAGIDX (DT_CHECKSUM)])
181225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
181325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (!has_val_dt[DT_VALTAGIDX (DT_GNU_PRELINKED)])
181425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
181525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': %s tag missing in DSO marked during prelinking\n"),
181625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "DT_GNU_PRELINKED");
181725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (!has_val_dt[DT_VALTAGIDX (DT_CHECKSUM)])
181825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
181925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': %s tag missing in DSO marked during prelinking\n"),
182025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "DT_CHECKSUM");
182125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
182225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Only DSOs can be marked like this.  */
182325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_type != ET_DYN)
182425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
182525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': non-DSO file marked as dependency during prelink\n"),
182625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
182725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
182825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
182925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (has_val_dt[DT_VALTAGIDX (DT_GNU_CONFLICTSZ)]
183025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      || has_val_dt[DT_VALTAGIDX (DT_GNU_LIBLISTSZ)]
183125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      || has_addr_dt[DT_ADDRTAGIDX (DT_GNU_CONFLICT)]
183225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      || has_addr_dt[DT_ADDRTAGIDX (DT_GNU_LIBLIST)])
183325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
183425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (!has_val_dt[DT_VALTAGIDX (DT_GNU_CONFLICTSZ)])
183525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
183625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': %s tag missing in prelinked executable\n"),
183725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "DT_GNU_CONFLICTSZ");
183825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (!has_val_dt[DT_VALTAGIDX (DT_GNU_LIBLISTSZ)])
183925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
184025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': %s tag missing in prelinked executable\n"),
184125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "DT_GNU_LIBLISTSZ");
184225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (!has_addr_dt[DT_ADDRTAGIDX (DT_GNU_CONFLICT)])
184325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
184425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': %s tag missing in prelinked executable\n"),
184525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "DT_GNU_CONFLICT");
184625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (!has_addr_dt[DT_ADDRTAGIDX (DT_GNU_LIBLIST)])
184725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
184825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': %s tag missing in prelinked executable\n"),
184925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), "DT_GNU_LIBLIST");
185025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
185125b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
185225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
185325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
185425b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
185525b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_symtab_shndx (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
185625b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
185725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_type != ET_REL)
185825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
185925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
186025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': only relocatable files can have extended section index\n"),
186125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
186225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
186325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
186425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
186525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
186625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr symshdr_mem;
186725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
186825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symshdr != NULL && symshdr->sh_type != SHT_SYMTAB)
186925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
187025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': extended section index section not for symbol table\n"),
187125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
187225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *symdata = elf_getdata (symscn, NULL);
187325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symdata == NULL)
187425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("cannot get data for symbol section\n"));
187525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
187625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_entsize != sizeof (Elf32_Word))
187725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
187825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry size does not match Elf32_Word\n"),
187925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
188025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
188125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symshdr != NULL
188225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && (shdr->sh_size / shdr->sh_entsize
188325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  < symshdr->sh_size / symshdr->sh_entsize))
188425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
188525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': extended index table too small for symbol table\n"),
188625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
188725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
188825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_info != 0)
188925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2d] '%s': sh_info not zero\n"),
189025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
189125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
189225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (size_t cnt = idx + 1; cnt < shnum; ++cnt)
189325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
189425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Shdr rshdr_mem;
189525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Shdr *rshdr = gelf_getshdr (elf_getscn (ebl->elf, cnt), &rshdr_mem);
189625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (rshdr != NULL && rshdr->sh_type == SHT_SYMTAB_SHNDX
189725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && rshdr->sh_link == shdr->sh_link)
189825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
189925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
190025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': extended section index in section [%2zu] '%s' refers to same symbol table\n"),
190125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx),
190225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 cnt, section_name (ebl, cnt));
190325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
190425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
190525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
190625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
190725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
190825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
190925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (*((Elf32_Word *) data->d_buf) != 0)
191025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("symbol 0 should have zero extended section index\n"));
191125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
191225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (size_t cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt)
191325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
191425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf32_Word xndx = ((Elf32_Word *) data->d_buf)[cnt];
191525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
191625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (xndx != 0)
191725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
191825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Sym sym_data;
191925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Sym *sym = gelf_getsym (symdata, cnt, &sym_data);
192025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (sym == NULL)
192125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
192225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("cannot get data for symbol %zu\n"), cnt);
192325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      continue;
192425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
192525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
192625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (sym->st_shndx != SHN_XINDEX)
192725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
192825b3c049e70834cf33790a28643ab058b507b35cBen Chengextended section index is %" PRIu32 " but symbol index is not XINDEX\n"),
192925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   (uint32_t) xndx);
193025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
193125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
193225b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
193325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
193425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
193525b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
193625b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_sysv_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx,
193725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 GElf_Shdr *symshdr)
193825b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
193925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
194025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
194125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
194225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize)
194325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
194425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"),
194525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), (long int) shdr->sh_size,
194625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   (long int) ((2 + nbucket + nchain) * shdr->sh_entsize));
194725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
194825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t maxidx = nchain;
194925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
195025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symshdr != NULL)
195125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
195225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      size_t symsize = symshdr->sh_size / symshdr->sh_entsize;
195325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
195425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (nchain > symshdr->sh_size / symshdr->sh_entsize)
195525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': chain array too large\n"),
195625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
195725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
195825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      maxidx = symsize;
195925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
196025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
196125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t cnt;
196225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (cnt = 2; cnt < 2 + nbucket; ++cnt)
196325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (((Elf32_Word *) data->d_buf)[cnt] >= maxidx)
196425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
196525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash bucket reference %zu out of bounds\n"),
196625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx), cnt - 2);
196725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
196825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (; cnt < 2 + nbucket + nchain; ++cnt)
196925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (((Elf32_Word *) data->d_buf)[cnt] >= maxidx)
197025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
197125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash chain reference %zu out of bounds\n"),
197225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx), cnt - 2 - nbucket);
197325b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
197425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
197525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
197625b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
197725b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_sysv_hash64 (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx,
197825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 GElf_Shdr *symshdr)
197925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
198025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0];
198125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1];
198225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
198325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize)
198425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
198525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"),
198625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), (long int) shdr->sh_size,
198725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   (long int) ((2 + nbucket + nchain) * shdr->sh_entsize));
198825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
198925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t maxidx = nchain;
199025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
199125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symshdr != NULL)
199225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
199325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      size_t symsize = symshdr->sh_size / symshdr->sh_entsize;
199425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
199525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (nchain > symshdr->sh_size / symshdr->sh_entsize)
199625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': chain array too large\n"),
199725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
199825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
199925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      maxidx = symsize;
200025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
200125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
200225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t cnt;
200325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (cnt = 2; cnt < 2 + nbucket; ++cnt)
200425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (((Elf64_Xword *) data->d_buf)[cnt] >= maxidx)
200525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
200625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash bucket reference %zu out of bounds\n"),
200725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx), cnt - 2);
200825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
200925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (; cnt < 2 + nbucket + nchain; ++cnt)
201025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (((Elf64_Xword *) data->d_buf)[cnt] >= maxidx)
201125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
201225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash chain reference %" PRIu64 " out of bounds\n"),
201325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx), (uint64_t) (cnt - 2 - nbucket));
201425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
201525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
201625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
201725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
201825b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_gnu_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx,
201925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		GElf_Shdr *symshdr)
202025b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
202125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf32_Word nbuckets = ((Elf32_Word *) data->d_buf)[0];
202225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1];
202325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf32_Word bitmask_words = ((Elf32_Word *) data->d_buf)[2];
202425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
202525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (!powerof2 (bitmask_words))
202625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
202725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': bitmask size not power of 2: %u\n"),
202825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), bitmask_words);
202925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
203025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t bitmask_idxmask = bitmask_words - 1;
203125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (gelf_getclass (ebl->elf) == ELFCLASS64)
203225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    bitmask_words *= 2;
203325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf32_Word shift = ((Elf32_Word *) data->d_buf)[3];
203425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
203525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_size < (4 + bitmask_words + nbuckets) * sizeof (Elf32_Word))
203625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
203725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
203825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash table section is too small (is %ld, expected at least%ld)\n"),
203925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx), (long int) shdr->sh_size,
204025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     (long int) ((4 + bitmask_words + nbuckets) * sizeof (Elf32_Word)));
204125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
204225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
204325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
204425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shift > 31)
204525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
204625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': 2nd hash function shift too big: %u\n"),
204725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), shift);
204825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
204925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t maxidx = shdr->sh_size / sizeof (Elf32_Word) - (4 + bitmask_words
205025b3c049e70834cf33790a28643ab058b507b35cBen Cheng							 + nbuckets);
205125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
205225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symshdr != NULL)
205325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    maxidx = MIN (maxidx, symshdr->sh_size / symshdr->sh_entsize);
205425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
205525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* We need the symbol section data.  */
205625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *symdata = elf_getdata (elf_getscn (ebl->elf, shdr->sh_link), NULL);
205725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
205825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  union
205925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
206025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf32_Word *p32;
206125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf64_Xword *p64;
206225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  } bitmask = { .p32 = &((Elf32_Word *) data->d_buf)[4] },
206325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      collected = { .p32 = xcalloc (bitmask_words, sizeof (Elf32_Word)) };
206425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
206525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t classbits = gelf_getclass (ebl->elf) == ELFCLASS32 ? 32 : 64;
206625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
206725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t cnt;
206825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (cnt = 4 + bitmask_words; cnt < 4 + bitmask_words + nbuckets; ++cnt)
206925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
207025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf32_Word symidx = ((Elf32_Word *) data->d_buf)[cnt];
207125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
207225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (symidx == 0)
207325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	continue;
207425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
207525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (symidx < symbias)
207625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
207725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
207825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash chain for bucket %zu lower than symbol index bias\n"),
207925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx), cnt - (4 + bitmask_words));
208025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
208125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
208225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
208325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      while (symidx - symbias < maxidx)
208425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
208525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf32_Word chainhash = ((Elf32_Word *) data->d_buf)[4
208625b3c049e70834cf33790a28643ab058b507b35cBen Cheng							      + bitmask_words
208725b3c049e70834cf33790a28643ab058b507b35cBen Cheng							      + nbuckets
208825b3c049e70834cf33790a28643ab058b507b35cBen Cheng							      + symidx
208925b3c049e70834cf33790a28643ab058b507b35cBen Cheng							      - symbias];
209025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
209125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (symdata != NULL)
209225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
209325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* Check that the referenced symbol is not undefined.  */
209425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Sym sym_mem;
209525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Sym *sym = gelf_getsym (symdata, symidx, &sym_mem);
209625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (sym != NULL && sym->st_shndx == SHN_UNDEF
209725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  && GELF_ST_TYPE (sym->st_info) != STT_FUNC)
209825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
209925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %u referenced in chain for bucket %zu is undefined\n"),
210025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx), symidx,
210125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       cnt - (4 + bitmask_words));
210225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
210325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      const char *symname = elf_strptr (ebl->elf, symshdr->sh_link,
210425b3c049e70834cf33790a28643ab058b507b35cBen Cheng						sym->st_name);
210525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (symname != NULL)
210625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
210725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  Elf32_Word hval = elf_gnu_hash (symname);
210825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if ((hval & ~1u) != (chainhash & ~1u))
210925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    ERROR (gettext ("\
211025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash value for symbol %u in chain for bucket %zu wrong\n"),
211125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   idx, section_name (ebl, idx), symidx,
211225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   cnt - (4 + bitmask_words));
211325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
211425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  /* Set the bits in the bitmask.  */
211525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  size_t maskidx = (hval / classbits) & bitmask_idxmask;
211625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (classbits == 32)
211725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
211825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      collected.p32[maskidx]
211925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			|= UINT32_C (1) << (hval & (classbits - 1));
212025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      collected.p32[maskidx]
212125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			|= UINT32_C (1) << ((hval >> shift) & (classbits - 1));
212225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
212325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  else
212425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
212525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      collected.p64[maskidx]
212625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			|= UINT64_C (1) << (hval & (classbits - 1));
212725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      collected.p64[maskidx]
212825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			|= UINT64_C (1) << ((hval >> shift) & (classbits - 1));
212925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
213025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
213125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
213225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
213325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if ((chainhash & 1) != 0)
213425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    break;
213525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
213625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ++symidx;
213725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
213825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
213925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (symidx - symbias >= maxidx)
214025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
214125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash chain for bucket %zu out of bounds\n"),
214225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt - (4 + bitmask_words));
214325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (symshdr != NULL
214425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       && symidx > symshdr->sh_size / symshdr->sh_entsize)
214525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
214625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol reference in chain for bucket %zu out of bounds\n"),
214725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt - (4 + bitmask_words));
214825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
214925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
215025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (memcmp (collected.p32, bitmask.p32, bitmask_words * sizeof (Elf32_Word)))
215125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
215225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': bitmask does not match names in the hash table\n"),
215325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
215425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
215525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  free (collected.p32);
215625b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
215725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
215825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
215925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
216025b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_hash (int tag, Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
216125b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
216225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_type == ET_REL)
216325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
216425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
216525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': relocatable files cannot have hash tables\n"),
216625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
216725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
216825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
216925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
217025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
217125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
217225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
217325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
217425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
217525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
217625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
217725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
217825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr symshdr_mem;
217925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *symshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
218025b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     &symshdr_mem);
218125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symshdr != NULL && symshdr->sh_type != SHT_DYNSYM)
218225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
218325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash table not for dynamic symbol table\n"),
218425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
218525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
218625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_entsize != (tag == SHT_GNU_HASH
218725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   ? (gelf_getclass (ebl->elf) == ELFCLASS32
218825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      ? sizeof (Elf32_Word) : 0)
218925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   : (size_t) ebl_sysvhash_entrysize (ebl)))
219025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
219125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash table entry size incorrect\n"),
219225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
219325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
219425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((shdr->sh_flags & SHF_ALLOC) == 0)
219525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2d] '%s': not marked to be allocated\n"),
219625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
219725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
219825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_size < (tag == SHT_GNU_HASH ? 4 : 2) * (shdr->sh_entsize ?: 4))
219925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
220025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
220125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': hash table has not even room for initial administrative entries\n"),
220225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
220325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
220425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
220525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
220625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  switch (tag)
220725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
220825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case SHT_HASH:
220925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword))
221025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	check_sysv_hash64 (ebl, shdr, data, idx, symshdr);
221125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
221225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	check_sysv_hash (ebl, shdr, data, idx, symshdr);
221325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
221425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
221525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case SHT_GNU_HASH:
221625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      check_gnu_hash (ebl, shdr, data, idx, symshdr);
221725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
221825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
221925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    default:
222025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      assert (! "should not happen");
222125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
222225b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
222325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
222425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
222525b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Compare content of both hash tables, it must be identical.  */
222625b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
222725b3c049e70834cf33790a28643ab058b507b35cBen Chengcompare_hash_gnu_hash (Ebl *ebl, GElf_Ehdr *ehdr, size_t hash_idx,
222825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       size_t gnu_hash_idx)
222925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
223025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *hash_scn = elf_getscn (ebl->elf, hash_idx);
223125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *hash_data = elf_getdata (hash_scn, NULL);
223225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr hash_shdr_mem;
223325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *hash_shdr = gelf_getshdr (hash_scn, &hash_shdr_mem);
223425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *gnu_hash_scn = elf_getscn (ebl->elf, gnu_hash_idx);
223525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *gnu_hash_data = elf_getdata (gnu_hash_scn, NULL);
223625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr gnu_hash_shdr_mem;
223725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *gnu_hash_shdr = gelf_getshdr (gnu_hash_scn, &gnu_hash_shdr_mem);
223825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
223925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (hash_shdr == NULL || gnu_hash_shdr == NULL
224025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      || hash_data == NULL || gnu_hash_data == NULL)
224125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* None of these pointers should be NULL since we used the
224225b3c049e70834cf33790a28643ab058b507b35cBen Cheng       sections already.  We are careful nonetheless.  */
224325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
224425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
224525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* The link must point to the same symbol table.  */
224625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (hash_shdr->sh_link != gnu_hash_shdr->sh_link)
224725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
224825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
224925b3c049e70834cf33790a28643ab058b507b35cBen Chengsh_link in hash sections [%2zu] '%s' and [%2zu] '%s' not identical\n"),
225025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     hash_idx, elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name),
225125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     gnu_hash_idx,
225225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name));
225325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
225425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
225525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
225625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *sym_scn = elf_getscn (ebl->elf, hash_shdr->sh_link);
225725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *sym_data = elf_getdata (sym_scn, NULL);
225825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr sym_shdr_mem;
225925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *sym_shdr = gelf_getshdr (sym_scn, &sym_shdr_mem);
226025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
226125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (sym_data == NULL || sym_shdr == NULL)
226225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
226325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
226425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int nentries = sym_shdr->sh_size / sym_shdr->sh_entsize;
226525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  char *used = alloca (nentries);
226625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  memset (used, '\0', nentries);
226725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
226825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* First go over the GNU_HASH table and mark the entries as used.  */
226925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const Elf32_Word *gnu_hasharr = (Elf32_Word *) gnu_hash_data->d_buf;
227025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf32_Word gnu_nbucket = gnu_hasharr[0];
227125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const int bitmap_factor = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 1 : 2;
227225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const Elf32_Word *gnu_bucket = (gnu_hasharr
227325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  + (4 + gnu_hasharr[2] * bitmap_factor));
227425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const Elf32_Word *gnu_chain = gnu_bucket + gnu_hasharr[0] - gnu_hasharr[1];
227525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
227625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (Elf32_Word cnt = 0; cnt < gnu_nbucket; ++cnt)
227725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
227825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf32_Word symidx = gnu_bucket[cnt];
227925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (symidx != STN_UNDEF)
228025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	do
228125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  used[symidx] |= 1;
228225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	while ((gnu_chain[symidx++] & 1u) == 0);
228325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
228425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
228525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Now go over the old hash table and check that we cover the same
228625b3c049e70834cf33790a28643ab058b507b35cBen Cheng     entries.  */
228725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (hash_shdr->sh_entsize == sizeof (Elf32_Word))
228825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
228925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const Elf32_Word *hasharr = (Elf32_Word *) hash_data->d_buf;
229025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf32_Word nbucket = hasharr[0];
229125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const Elf32_Word *bucket = &hasharr[2];
229225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const Elf32_Word *chain = &hasharr[2 + nbucket];
229325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
229425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
229525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
229625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf32_Word symidx = bucket[cnt];
229725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  while (symidx != STN_UNDEF)
229825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
229925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      used[symidx] |= 2;
230025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      symidx = chain[symidx];
230125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
230225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
230325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
230425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
230525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
230625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const Elf64_Xword *hasharr = (Elf64_Xword *) hash_data->d_buf;
230725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf64_Xword nbucket = hasharr[0];
230825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const Elf64_Xword *bucket = &hasharr[2];
230925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const Elf64_Xword *chain = &hasharr[2 + nbucket];
231025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
231125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      for (Elf64_Xword cnt = 0; cnt < nbucket; ++cnt)
231225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
231325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf64_Xword symidx = bucket[cnt];
231425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  while (symidx != STN_UNDEF)
231525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
231625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      used[symidx] |= 2;
231725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      symidx = chain[symidx];
231825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
231925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
232025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
232125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
232225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Now see which entries are not set in one or both hash tables
232325b3c049e70834cf33790a28643ab058b507b35cBen Cheng     (unless the symbol is undefined in which case it can be omitted
232425b3c049e70834cf33790a28643ab058b507b35cBen Cheng     in the new table format).  */
232525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((used[0] & 1) != 0)
232625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2zu] '%s': reference to symbol index 0\n"),
232725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   gnu_hash_idx,
232825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name));
232925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((used[0] & 2) != 0)
233025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2zu] '%s': reference to symbol index 0\n"),
233125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   hash_idx, elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name));
233225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
233325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (int cnt = 1; cnt < nentries; ++cnt)
233425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (used[cnt] != 0 && used[cnt] != 3)
233525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
233625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (used[cnt] == 1)
233725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
233825b3c049e70834cf33790a28643ab058b507b35cBen Chengsymbol %d referenced in new hash table in [%2zu] '%s' but not in old hash table in [%2zu] '%s'\n"),
233925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 cnt, gnu_hash_idx,
234025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name),
234125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 hash_idx,
234225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name));
234325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	else
234425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
234525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    GElf_Sym sym_mem;
234625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    GElf_Sym *sym = gelf_getsym (sym_data, cnt, &sym_mem);
234725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
234825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (sym != NULL && sym->st_shndx != STN_UNDEF)
234925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
235025b3c049e70834cf33790a28643ab058b507b35cBen Chengsymbol %d referenced in old hash table in [%2zu] '%s' but not in new hash table in [%2zu] '%s'\n"),
235125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     cnt, hash_idx,
235225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name),
235325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     gnu_hash_idx,
235425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name));
235525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
235625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
235725b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
235825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
235925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
236025b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
236125b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_null (Ebl *ebl, GElf_Shdr *shdr, int idx)
236225b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
236325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define TEST(name, extra) \
236425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (extra && shdr->sh_##name != 0)					      \
236525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2d] '%s': nonzero sh_%s for NULL section\n"),  \
236625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), #name)
236725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
236825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  TEST (name, 1);
236925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  TEST (flags, 1);
237025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  TEST (addr, 1);
237125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  TEST (offset, 1);
237225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  TEST (size, idx != 0);
237325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  TEST (link, idx != 0);
237425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  TEST (info, 1);
237525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  TEST (addralign, 1);
237625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  TEST (entsize, 1);
237725b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
237825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
237925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
238025b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
238125b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_group (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
238225b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
238325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_type != ET_REL)
238425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
238525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
238625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section groups only allowed in relocatable object files\n"),
238725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
238825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
238925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
239025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
239125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check that sh_link is an index of a symbol table.  */
239225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
239325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr symshdr_mem;
239425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
239525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symshdr == NULL)
239625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2d] '%s': cannot get symbol table: %s\n"),
239725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), elf_errmsg (-1));
239825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
239925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
240025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (symshdr->sh_type != SHT_SYMTAB)
240125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
240225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section reference in sh_link is no symbol table\n"),
240325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
240425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
240525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_info >= symshdr->sh_size / gelf_fsize (ebl->elf, ELF_T_SYM,
240625b3c049e70834cf33790a28643ab058b507b35cBen Cheng							  1, EV_CURRENT))
240725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
240825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': invalid symbol index in sh_info\n"),
240925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
241025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
241125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_flags != 0)
241225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': sh_flags not zero\n"),
241325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
241425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
241525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Sym sym_data;
241625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Sym *sym = gelf_getsym (elf_getdata (symscn, NULL), shdr->sh_info,
241725b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   &sym_data);
241825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sym == NULL)
241925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
242025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': cannot get symbol for signature\n"),
242125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
242225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (strcmp (elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name),
242325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       "") == 0)
242425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
242525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': signature symbol cannot be empty string\n"),
242625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
242725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
242825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (be_strict
242925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && shdr->sh_entsize != elf32_fsize (ELF_T_WORD, 1, EV_CURRENT))
243025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': sh_flags not set correctly\n"),
243125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
243225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
243325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
243425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
243525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
243625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2d] '%s': cannot get data: %s\n"),
243725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), elf_errmsg (-1));
243825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
243925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
244025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      size_t elsize = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT);
244125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      size_t cnt;
244225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      Elf32_Word val;
244325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
244425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (data->d_size % elsize != 0)
244525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
244625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section size not multiple of sizeof(Elf32_Word)\n"),
244725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
244825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
244925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (data->d_size < elsize)
245025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
245125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section group without flags word\n"),
245225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
245325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (be_strict)
245425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
245525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (data->d_size < 2 * elsize)
245625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
245725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section group without member\n"),
245825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx));
245925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else if (data->d_size < 3 * elsize)
246025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
246125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section group with only one member\n"),
246225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx));
246325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
246425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
246525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#if ALLOW_UNALIGNED
246625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      val = *((Elf32_Word *) data->d_buf);
246725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#else
246825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      memcpy (&val, data->d_buf, elsize);
246925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
247025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((val & ~GRP_COMDAT) != 0)
247125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2d] '%s': unknown section group flags\n"),
247225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx));
247325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
247425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      for (cnt = elsize; cnt < data->d_size; cnt += elsize)
247525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
247625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#if ALLOW_UNALIGNED
247725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  val = *((Elf32_Word *) ((char *) data->d_buf + cnt));
247825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#else
247925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  memcpy (&val, (char *) data->d_buf + cnt, elsize);
248025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
248125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
248225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (val > shnum)
248325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
248425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section index %Zu out of range\n"),
248525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), cnt / elsize);
248625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
248725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
248825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Shdr refshdr_mem;
248925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Shdr *refshdr = gelf_getshdr (elf_getscn (ebl->elf, val),
249025b3c049e70834cf33790a28643ab058b507b35cBen Cheng						 &refshdr_mem);
249125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (refshdr == NULL)
249225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
249325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': cannot get section header for element %zu: %s\n"),
249425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx), cnt / elsize,
249525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       elf_errmsg (-1));
249625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      else
249725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
249825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (refshdr->sh_type == SHT_GROUP)
249925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    ERROR (gettext ("\
250025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': section group contains another group [%2d] '%s'\n"),
250125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   idx, section_name (ebl, idx),
250225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   val, section_name (ebl, val));
250325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
250425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if ((refshdr->sh_flags & SHF_GROUP) == 0)
250525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    ERROR (gettext ("\
250625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': element %Zu references section [%2d] '%s' without SHF_GROUP flag set\n"),
250725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   idx, section_name (ebl, idx), cnt / elsize,
250825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			   val, section_name (ebl, val));
250925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
251025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
251125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (++scnref[val] == 2)
251225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
251325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s' is contained in more than one section group\n"),
251425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       val, section_name (ebl, val));
251525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
251625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
251725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
251825b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
251925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
252025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
252125b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic const char *
252225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection_flags_string (GElf_Word flags, char *buf, size_t len)
252325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
252425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (flags == 0)
252525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return "none";
252625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
252725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  static const struct
252825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
252925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    GElf_Word flag;
253025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    const char *name;
253125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  } known_flags[] =
253225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
253325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define NEWFLAG(name) { SHF_##name, #name }
253425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      NEWFLAG (WRITE),
253525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      NEWFLAG (ALLOC),
253625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      NEWFLAG (EXECINSTR),
253725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      NEWFLAG (MERGE),
253825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      NEWFLAG (STRINGS),
253925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      NEWFLAG (INFO_LINK),
254025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      NEWFLAG (LINK_ORDER),
254125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      NEWFLAG (OS_NONCONFORMING),
254225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      NEWFLAG (GROUP),
254325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      NEWFLAG (TLS)
254425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    };
254525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#undef NEWFLAG
254625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const size_t nknown_flags = sizeof (known_flags) / sizeof (known_flags[0]);
254725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
254825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  char *cp = buf;
254925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
255025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (size_t cnt = 0; cnt < nknown_flags; ++cnt)
255125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if (flags & known_flags[cnt].flag)
255225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
255325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (cp != buf && len > 1)
255425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
255525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    *cp++ = '|';
255625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    --len;
255725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
255825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
255925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	size_t ncopy = MIN (len - 1, strlen (known_flags[cnt].name));
256025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	cp = mempcpy (cp, known_flags[cnt].name, ncopy);
256125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	len -= ncopy;
256225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
256325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	flags ^= known_flags[cnt].flag;
256425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
256525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
256625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (flags != 0 || cp == buf)
256725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    snprintf (cp, len - 1, "%" PRIx64, (uint64_t) flags);
256825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
256925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  *cp = '\0';
257025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
257125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return buf;
257225b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
257325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
257425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
257525b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int
257625b3c049e70834cf33790a28643ab058b507b35cBen Chenghas_copy_reloc (Ebl *ebl, unsigned int symscnndx, unsigned int symndx)
257725b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
257825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* First find the relocation section for the symbol table.  */
257925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *scn = NULL;
258025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr shdr_mem;
258125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *shdr = NULL;
258225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
258325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
258425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      shdr = gelf_getshdr (scn, &shdr_mem);
258525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr != NULL
258625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
258725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && shdr->sh_link == symscnndx)
258825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	/* Found the section.  */
258925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	break;
259025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
259125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
259225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (scn == NULL)
259325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return 0;
259425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
259525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (scn, NULL);
259625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
259725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return 0;
259825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
259925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_type == SHT_REL)
260025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    for (int i = 0; (size_t) i < shdr->sh_size / shdr->sh_entsize; ++i)
260125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
260225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Rel rel_mem;
260325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Rel *rel = gelf_getrel (data, i, &rel_mem);
260425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (rel == NULL)
260525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
260625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
260725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (GELF_R_SYM (rel->r_info) == symndx
260825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rel->r_info)))
260925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return 1;
261025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
261125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
261225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    for (int i = 0; (size_t) i < shdr->sh_size / shdr->sh_entsize; ++i)
261325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
261425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Rela rela_mem;
261525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Rela *rela = gelf_getrela (data, i, &rela_mem);
261625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (rela == NULL)
261725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
261825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
261925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (GELF_R_SYM (rela->r_info) == symndx
262025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rela->r_info)))
262125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return 1;
262225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
262325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
262425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return 0;
262525b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
262625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
262725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
262825b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int
262925b3c049e70834cf33790a28643ab058b507b35cBen Chengin_nobits_scn (Ebl *ebl, unsigned int shndx)
263025b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
263125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr shdr_mem;
263225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, shndx), &shdr_mem);
263325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return shdr != NULL && shdr->sh_type == SHT_NOBITS;
263425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
263525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
263625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
263725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic struct version_namelist
263825b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
263925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const char *objname;
264025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const char *name;
264125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Versym ndx;
264225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  enum { ver_def, ver_need } type;
264325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  struct version_namelist *next;
264425b3c049e70834cf33790a28643ab058b507b35cBen Cheng} *version_namelist;
264525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
264625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
264725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int
264825b3c049e70834cf33790a28643ab058b507b35cBen Chengadd_version (const char *objname, const char *name, GElf_Versym ndx, int type)
264925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
265025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check that there are no duplications.  */
265125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  struct version_namelist *nlp = version_namelist;
265225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (nlp != NULL)
265325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
265425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (((nlp->objname == NULL && objname == NULL)
265525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   || (nlp->objname != NULL && objname != NULL
265625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       && strcmp (nlp->objname, objname) == 0))
265725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && strcmp (nlp->name, name) == 0)
265825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	return nlp->type == ver_def ? 1 : -1;
265925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      nlp = nlp->next;
266025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
266125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
266225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  nlp = xmalloc (sizeof (*nlp));
266325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  nlp->objname = objname;
266425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  nlp->name = name;
266525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  nlp->ndx = ndx;
266625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  nlp->type = type;
266725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  nlp->next = version_namelist;
266825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  version_namelist = nlp;
266925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
267025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return 0;
267125b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
267225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
267325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
267425b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
267525b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_versym (Ebl *ebl, int idx)
267625b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
267725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *scn = elf_getscn (ebl->elf, idx);
267825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr shdr_mem;
267925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
268025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr == NULL)
268125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* The error has already been reported.  */
268225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
268325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
268425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (scn, NULL);
268525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
268625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
268725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
268825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
268925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
269025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
269125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
269225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
269325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr symshdr_mem;
269425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
269525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symshdr == NULL)
269625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* The error has already been reported.  */
269725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
269825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
269925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symshdr->sh_type != SHT_DYNSYM)
270025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
270125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("\
270225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s' refers in sh_link to section [%2d] '%s' which is no dynamic symbol table\n"),
270325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx),
270425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     shdr->sh_link, section_name (ebl, shdr->sh_link));
270525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
270625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
270725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
270825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* The number of elements in the version symbol table must be the
270925b3c049e70834cf33790a28643ab058b507b35cBen Cheng     same as the number of symbols.  */
271025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_size / shdr->sh_entsize
271125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      != symshdr->sh_size / symshdr->sh_entsize)
271225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
271325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s' has different number of entries than symbol table [%2d] '%s'\n"),
271425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx),
271525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   shdr->sh_link, section_name (ebl, shdr->sh_link));
271625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
271725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *symdata = elf_getdata (symscn, NULL);
271825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (symdata == NULL)
271925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* The error has already been reported.  */
272025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
272125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
272225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (int cnt = 1; (size_t) cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
272325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
272425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Versym versym_mem;
272525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Versym *versym = gelf_getversym (data, cnt, &versym_mem);
272625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (versym == NULL)
272725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
272825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
272925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %d: cannot read version data\n"),
273025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx), cnt);
273125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
273225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
273325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
273425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Sym sym_mem;
273525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Sym *sym = gelf_getsym (symdata, cnt, &sym_mem);
273625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (sym == NULL)
273725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	/* Already reported elsewhere.  */
273825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	continue;
273925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
274025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (*versym == VER_NDX_GLOBAL)
274125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
274225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Global symbol.  Make sure it is not defined as local.  */
274325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (GELF_ST_BIND (sym->st_info) == STB_LOCAL)
274425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
274525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %d: local symbol with global scope\n"),
274625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), cnt);
274725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
274825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (*versym != VER_NDX_LOCAL)
274925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
275025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Versioned symbol.  Make sure it is not defined as local.  */
275125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (!gnuld && GELF_ST_BIND (sym->st_info) == STB_LOCAL)
275225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
275325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %d: local symbol with version\n"),
275425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), cnt);
275525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
275625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Look through the list of defined versions and locate the
275725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     index we need for this symbol.  */
275825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  struct version_namelist *runp = version_namelist;
275925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  while (runp != NULL)
276025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (runp->ndx == (*versym & (GElf_Versym) 0x7fff))
276125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      break;
276225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    else
276325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      runp = runp->next;
276425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
276525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (runp == NULL)
276625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
276725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %d: invalid version index %d\n"),
276825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), cnt, (int) *versym);
276925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else if (sym->st_shndx == SHN_UNDEF
277025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   && runp->type == ver_def)
277125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
277225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %d: version index %d is for defined version\n"),
277325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), cnt, (int) *versym);
277425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else if (sym->st_shndx != SHN_UNDEF
277525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   && runp->type == ver_need)
277625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
277725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* Unless this symbol has a copy relocation associated
277825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 this must not happen.  */
277925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (!has_copy_reloc (ebl, shdr->sh_link, cnt)
278025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  && !in_nobits_scn (ebl, sym->st_shndx))
278125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
278225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': symbol %d: version index %d is for requested version\n"),
278325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx), cnt, (int) *versym);
278425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
278525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
278625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
278725b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
278825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
278925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
279025b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int
279125b3c049e70834cf33790a28643ab058b507b35cBen Chengunknown_dependency_p (Elf *elf, const char *fname)
279225b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
279325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Phdr phdr_mem;
279425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Phdr *phdr = NULL;
279525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
279625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  unsigned int i;
279725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (i = 0; i < phnum; ++i)
279825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    if ((phdr = gelf_getphdr (elf, i, &phdr_mem)) != NULL
279925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	&& phdr->p_type == PT_DYNAMIC)
280025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
280125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
280225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (i == phnum)
280325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return 1;
280425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  assert (phdr != NULL);
280525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Scn *scn = gelf_offscn (elf, phdr->p_offset);
280625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr shdr_mem;
280725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
280825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (scn, NULL);
280925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC && data != NULL)
281025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    for (size_t j = 0; j < shdr->sh_size / shdr->sh_entsize; ++j)
281125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
281225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Dyn dyn_mem;
281325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
281425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (dyn != NULL && dyn->d_tag == DT_NEEDED)
281525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
281625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    const char *str = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val);
281725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (str != NULL && strcmp (str, fname) == 0)
281825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* Found it.  */
281925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      return 0;
282025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
282125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
282225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
282325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return 1;
282425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
282525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
282625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
282725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic unsigned int nverneed;
282825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
282925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
283025b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_verneed (Ebl *ebl, GElf_Shdr *shdr, int idx)
283125b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
283225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (++nverneed == 2)
283325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("more than one version reference section present\n"));
283425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
283525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr strshdr_mem;
283625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
283725b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     &strshdr_mem);
283825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (strshdr == NULL)
283925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
284025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (strshdr->sh_type != SHT_STRTAB)
284125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
284225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': sh_link does not link to string table\n"),
284325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
284425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
284525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
284625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
284725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
284825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
284925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
285025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
285125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
285225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  unsigned int offset = 0;
285325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (int cnt = shdr->sh_info; --cnt >= 0; )
285425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
285525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Get the data at the next offset.  */
285625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Verneed needmem;
285725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Verneed *need = gelf_getverneed (data, offset, &needmem);
285825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (need == NULL)
285925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	break;
286025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
286125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      unsigned int auxoffset = offset + need->vn_aux;
286225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
286325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (need->vn_version != EV_CURRENT)
286425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
286525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has wrong version %d\n"),
286625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt, (int) need->vn_version);
286725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
286825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (need->vn_cnt > 0 && need->vn_aux < gelf_fsize (ebl->elf, ELF_T_VNEED,
286925b3c049e70834cf33790a28643ab058b507b35cBen Cheng							 1, EV_CURRENT))
287025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
287125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has wrong offset of auxiliary data\n"),
287225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
287325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
287425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const char *libname = elf_strptr (ebl->elf, shdr->sh_link,
287525b3c049e70834cf33790a28643ab058b507b35cBen Cheng					need->vn_file);
287625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (libname == NULL)
287725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
287825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
287925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has invalid file reference\n"),
288025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx), cnt);
288125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  goto next_need;
288225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
288325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
288425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Check that there is a DT_NEEDED entry for the referenced library.  */
288525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (unknown_dependency_p (ebl->elf, libname))
288625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
288725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d references unknown dependency\n"),
288825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
288925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
289025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
289125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
289225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Vernaux auxmem;
289325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Vernaux *aux = gelf_getvernaux (data, auxoffset, &auxmem);
289425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (aux == NULL)
289525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    break;
289625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
289725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if ((aux->vna_flags & ~VER_FLG_WEAK) != 0)
289825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
289925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': auxiliary entry %d of entry %d has unknown flag\n"),
290025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), need->vn_cnt - cnt2, cnt);
290125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
290225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  const char *verstr = elf_strptr (ebl->elf, shdr->sh_link,
290325b3c049e70834cf33790a28643ab058b507b35cBen Cheng					   aux->vna_name);
290425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (verstr == NULL)
290525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
290625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': auxiliary entry %d of entry %d has invalid name reference\n"),
290725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), need->vn_cnt - cnt2, cnt);
290825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
290925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
291025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Word hashval = elf_hash (verstr);
291125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (hashval != aux->vna_hash)
291225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
291325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': auxiliary entry %d of entry %d has wrong hash value: %#x, expected %#x\n"),
291425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx), need->vn_cnt - cnt2,
291525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       cnt, (int) hashval, (int) aux->vna_hash);
291625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
291725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      int res = add_version (libname, verstr, aux->vna_other,
291825b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     ver_need);
291925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (unlikely (res !=0))
292025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
292125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  assert (res > 0);
292225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  ERROR (gettext ("\
292325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': auxiliary entry %d of entry %d has duplicate version name '%s'\n"),
292425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 idx, section_name (ebl, idx), need->vn_cnt - cnt2,
292525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 cnt, verstr);
292625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
292725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
292825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
292925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if ((aux->vna_next != 0 || cnt2 > 0)
293025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      && aux->vna_next < gelf_fsize (ebl->elf, ELF_T_VNAUX, 1,
293125b3c049e70834cf33790a28643ab058b507b35cBen Cheng					     EV_CURRENT))
293225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
293325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
293425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': auxiliary entry %d of entry %d has wrong next field\n"),
293525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     idx, section_name (ebl, idx), need->vn_cnt - cnt2, cnt);
293625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      break;
293725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
293825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
293925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  auxoffset += MAX (aux->vna_next,
294025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    gelf_fsize (ebl->elf, ELF_T_VNAUX, 1, EV_CURRENT));
294125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
294225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
294325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Find the next offset.  */
294425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    next_need:
294525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      offset += need->vn_next;
294625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
294725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((need->vn_next != 0 || cnt > 0)
294825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && offset < auxoffset)
294925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
295025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has invalid offset to next entry\n"),
295125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
295225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
295325b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
295425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
295525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
295625b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic unsigned int nverdef;
295725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
295825b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
295925b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_verdef (Ebl *ebl, GElf_Shdr *shdr, int idx)
296025b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
296125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (++nverdef == 2)
296225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("more than one version definition section present\n"));
296325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
296425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr strshdr_mem;
296525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
296625b3c049e70834cf33790a28643ab058b507b35cBen Cheng				     &strshdr_mem);
296725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (strshdr == NULL)
296825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
296925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (strshdr->sh_type != SHT_STRTAB)
297025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
297125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': sh_link does not link to string table\n"),
297225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
297325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
297425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
297525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
297625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
297725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    no_data:
297825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
297925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
298025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
298125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
298225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
298325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Iterate over all version definition entries.  We check that there
298425b3c049e70834cf33790a28643ab058b507b35cBen Cheng     is a BASE entry and that each index is unique.  To do the later
298525b3c049e70834cf33790a28643ab058b507b35cBen Cheng     we collection the information in a list which is later
298625b3c049e70834cf33790a28643ab058b507b35cBen Cheng     examined.  */
298725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  struct namelist
298825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
298925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    const char *name;
299025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    struct namelist *next;
299125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  } *namelist = NULL;
299225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  struct namelist *refnamelist = NULL;
299325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
299425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool has_base = false;
299525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  unsigned int offset = 0;
299625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (int cnt = shdr->sh_info; --cnt >= 0; )
299725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
299825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Get the data at the next offset.  */
299925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Verdef defmem;
300025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Verdef *def = gelf_getverdef (data, offset, &defmem);
300125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (def == NULL)
300225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	goto no_data;
300325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
300425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((def->vd_flags & VER_FLG_BASE) != 0)
300525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
300625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (has_base)
300725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
300825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': more than one BASE definition\n"),
300925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx));
301025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (def->vd_ndx != VER_NDX_GLOBAL)
301125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
301225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': BASE definition must have index VER_NDX_GLOBAL\n"),
301325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx));
301425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  has_base = true;
301525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
301625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((def->vd_flags & ~(VER_FLG_BASE|VER_FLG_WEAK)) != 0)
301725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
301825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has unknown flag\n"),
301925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
302025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
302125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (def->vd_version != EV_CURRENT)
302225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
302325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has wrong version %d\n"),
302425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt, (int) def->vd_version);
302525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
302625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (def->vd_cnt > 0 && def->vd_aux < gelf_fsize (ebl->elf, ELF_T_VDEF,
302725b3c049e70834cf33790a28643ab058b507b35cBen Cheng						       1, EV_CURRENT))
302825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
302925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has wrong offset of auxiliary data\n"),
303025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
303125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
303225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      unsigned int auxoffset = offset + def->vd_aux;
303325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Verdaux auxmem;
303425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Verdaux *aux = gelf_getverdaux (data, auxoffset, &auxmem);
303525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (aux == NULL)
303625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	goto no_data;
303725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
303825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const char *name = elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name);
303925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (name == NULL)
304025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
304125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
304225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has invalid name reference\n"),
304325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx), cnt);
304425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  goto next_def;
304525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
304625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Word hashval = elf_hash (name);
304725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (def->vd_hash != hashval)
304825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
304925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has wrong hash value: %#x, expected %#x\n"),
305025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt, (int) hashval,
305125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       (int) def->vd_hash);
305225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
305325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      int res = add_version (NULL, name, def->vd_ndx, ver_def);
305425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (unlikely (res !=0))
305525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
305625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  assert (res > 0);
305725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
305825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has duplicate version name '%s'\n"),
305925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx), cnt, name);
306025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
306125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
306225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      struct namelist *newname = alloca (sizeof (*newname));
306325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      newname->name = name;
306425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      newname->next = namelist;
306525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      namelist = newname;
306625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
306725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      auxoffset += aux->vda_next;
306825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      for (int cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2)
306925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
307025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  aux = gelf_getverdaux (data, auxoffset, &auxmem);
307125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (aux == NULL)
307225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    goto no_data;
307325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
307425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  name = elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name);
307525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (name == NULL)
307625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
307725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has invalid name reference in auxiliary data\n"),
307825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   idx, section_name (ebl, idx), cnt);
307925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
308025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
308125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      newname = alloca (sizeof (*newname));
308225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      newname->name = name;
308325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      newname->next = refnamelist;
308425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      refnamelist = newname;
308525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
308625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
308725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if ((aux->vda_next != 0 || cnt2 + 1 < def->vd_cnt)
308825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      && aux->vda_next < gelf_fsize (ebl->elf, ELF_T_VDAUX, 1,
308925b3c049e70834cf33790a28643ab058b507b35cBen Cheng					     EV_CURRENT))
309025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
309125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
309225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has wrong next field in auxiliary data\n"),
309325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     idx, section_name (ebl, idx), cnt);
309425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      break;
309525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
309625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
309725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  auxoffset += MAX (aux->vda_next,
309825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    gelf_fsize (ebl->elf, ELF_T_VDAUX, 1, EV_CURRENT));
309925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
310025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
310125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Find the next offset.  */
310225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    next_def:
310325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      offset += def->vd_next;
310425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
310525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((def->vd_next != 0 || cnt > 0)
310625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && offset < auxoffset)
310725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
310825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': entry %d has invalid offset to next entry\n"),
310925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), cnt);
311025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
311125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
311225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (!has_base)
311325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2d] '%s': no BASE definition\n"),
311425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
311525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
311625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check whether the referenced names are available.  */
311725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (namelist != NULL)
311825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
311925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      struct version_namelist *runp = version_namelist;
312025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      while (runp != NULL)
312125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
312225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (runp->type == ver_def
312325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      && strcmp (runp->name, namelist->name) == 0)
312425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    break;
312525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  runp = runp->next;
312625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
312725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
312825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (runp == NULL)
312925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
313025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': unknown parent version '%s'\n"),
313125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), namelist->name);
313225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
313325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      namelist = namelist->next;
313425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
313525b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
313625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
313725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
313825b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
313925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
314025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_size == 0)
314125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
314225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': empty object attributes section\n"),
314325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
314425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
314525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
314625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
314725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_rawdata (elf_getscn (ebl->elf, idx), NULL);
314825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL || data->d_size == 0)
314925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
315025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
315125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
315225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
315325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
315425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
315525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline size_t pos (const unsigned char *p)
315625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
315725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return p - (const unsigned char *) data->d_buf;
315825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
315925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
316025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const unsigned char *p = data->d_buf;
316125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (*p++ != 'A')
316225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
316325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': unrecognized attribute format\n"),
316425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
316525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
316625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
316725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
316825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  inline size_t left (void)
316925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
317025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return (const unsigned char *) data->d_buf + data->d_size - p;
317125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  }
317225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
317325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (left () >= 4)
317425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
317525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      uint32_t len;
317625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      memcpy (&len, p, sizeof len);
317725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
317825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (len == 0)
317925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
318025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: zero length field in attribute section\n"),
318125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), pos (p));
318225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
318325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
318425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	CONVERT (len);
318525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
318625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (len > left ())
318725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
318825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
318925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: invalid length in attribute section\n"),
319025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx), pos (p));
319125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
319225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
319325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
319425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const unsigned char *name = p + sizeof len;
319525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      p += len;
319625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
319725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      unsigned const char *q = memchr (name, '\0', len);
319825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (q == NULL)
319925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
320025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
320125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: unterminated vendor name string\n"),
320225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 idx, section_name (ebl, idx), pos (p));
320325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
320425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
320525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ++q;
320625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
320725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (q - name == sizeof "gnu" && !memcmp (name, "gnu", sizeof "gnu"))
320825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	while (q < p)
320925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
321025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    unsigned const char *chunk = q;
321125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
321225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    unsigned int subsection_tag;
321325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    get_uleb128 (subsection_tag, q);
321425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
321525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (q >= p)
321625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
321725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
321825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: endless ULEB128 in attribute subsection tag\n"),
321925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx), pos (chunk));
322025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		break;
322125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      }
322225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
322325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    uint32_t subsection_len;
322425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (p - q < (ptrdiff_t) sizeof subsection_len)
322525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
322625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
322725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: truncated attribute section\n"),
322825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx), pos (q));
322925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		break;
323025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      }
323125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
323225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    memcpy (&subsection_len, q, sizeof subsection_len);
323325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (subsection_len == 0)
323425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
323525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
323625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: zero length field in attribute subsection\n"),
323725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx), pos (q));
323825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
323925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		q += sizeof subsection_len;
324025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		continue;
324125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      }
324225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
324325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
324425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      CONVERT (subsection_len);
324525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
324625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (p - chunk < (ptrdiff_t) subsection_len)
324725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
324825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
324925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: invalid length in attribute subsection\n"),
325025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       idx, section_name (ebl, idx), pos (q));
325125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		break;
325225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      }
325325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
325425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    const unsigned char *subsection_end = chunk + subsection_len;
325525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    chunk = q;
325625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    q = subsection_end;
325725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
325825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (subsection_tag != 1) /* Tag_File */
325925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
326025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: attribute subsection has unexpected tag %u\n"),
326125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     idx, section_name (ebl, idx), pos (chunk), subsection_tag);
326225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    else
326325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
326425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		chunk += sizeof subsection_len;
326525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		while (chunk < q)
326625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
326725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    unsigned int tag;
326825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    get_uleb128 (tag, chunk);
326925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
327025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    uint64_t value = 0;
327125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    const unsigned char *r = chunk;
327225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if (tag == 32 || (tag & 1) == 0)
327325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      {
327425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			get_uleb128 (value, r);
327525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			if (r > q)
327625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  {
327725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    ERROR (gettext ("\
327825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: endless ULEB128 in attribute tag\n"),
327925b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   idx, section_name (ebl, idx), pos (chunk));
328025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    break;
328125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  }
328225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      }
328325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if (tag == 32 || (tag & 1) != 0)
328425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      {
328525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			r = memchr (r, '\0', q - r);
328625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			if (r == NULL)
328725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  {
328825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    ERROR (gettext ("\
328925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: unterminated string in attribute\n"),
329025b3c049e70834cf33790a28643ab058b507b35cBen Cheng				   idx, section_name (ebl, idx), pos (chunk));
329125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    break;
329225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  }
329325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			++r;
329425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      }
329525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
329625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    const char *tag_name = NULL;
329725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    const char *value_name = NULL;
329825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if (!ebl_check_object_attribute (ebl, (const char *) name,
329925b3c049e70834cf33790a28643ab058b507b35cBen Cheng						     tag, value,
330025b3c049e70834cf33790a28643ab058b507b35cBen Cheng						     &tag_name, &value_name))
330125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
330225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: unrecognized attribute tag %u\n"),
330325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     idx, section_name (ebl, idx), pos (chunk), tag);
330425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    else if ((tag & 1) == 0 && value_name == NULL)
330525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
330625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: unrecognized %s attribute value %" PRIu64 "\n"),
330725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     idx, section_name (ebl, idx), pos (chunk),
330825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     tag_name, value);
330925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
331025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    chunk = r;
331125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  }
331225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      }
331325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
331425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
331525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
331625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: vendor '%s' unknown\n"),
331725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       idx, section_name (ebl, idx), pos (p), name);
331825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
331925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
332025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (left () != 0)
332125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
332225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': offset %zu: extra bytes after last attribute section\n"),
332325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), pos (p));
332425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
332525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
332625b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool has_loadable_segment;
332725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic bool has_interp_segment;
332825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
332925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic const struct
333025b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
333125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const char *name;
333225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t namelen;
333325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Word type;
333425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  enum { unused, exact, atleast, exact_or_gnuld } attrflag;
333525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Word attr;
333625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Word attr2;
333725b3c049e70834cf33790a28643ab058b507b35cBen Cheng} special_sections[] =
333825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
333925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* See figure 4-14 in the gABI.  */
334025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".bss", 5, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE, 0 },
334125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".comment", 8, SHT_PROGBITS, atleast, 0, SHF_MERGE | SHF_STRINGS },
334225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".data", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 },
334325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".data1", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 },
334425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".debug_str", 11, SHT_PROGBITS, exact_or_gnuld, SHF_MERGE | SHF_STRINGS, 0 },
334525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".debug", 6, SHT_PROGBITS, exact, 0, 0 },
334625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".dynamic", 9, SHT_DYNAMIC, atleast, SHF_ALLOC, SHF_WRITE },
334725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".dynstr", 8, SHT_STRTAB, exact, SHF_ALLOC, 0 },
334825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".dynsym", 8, SHT_DYNSYM, exact, SHF_ALLOC, 0 },
334925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".fini", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 },
335025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".fini_array", 12, SHT_FINI_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 },
335125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".got", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more info?
335225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".hash", 6, SHT_HASH, exact, SHF_ALLOC, 0 },
335325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".init", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 },
335425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".init_array", 12, SHT_INIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 },
335525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".interp", 8, SHT_PROGBITS, atleast, 0, SHF_ALLOC }, // XXX more tests?
335625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".line", 6, SHT_PROGBITS, exact, 0, 0 },
335725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".note", 6, SHT_NOTE, atleast, 0, SHF_ALLOC },
335825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".plt", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more tests
335925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".preinit_array", 15, SHT_PREINIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 },
336025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".rela", 5, SHT_RELA, atleast, 0, SHF_ALLOC }, // XXX more tests
336125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".rel", 4, SHT_REL, atleast, 0, SHF_ALLOC }, // XXX more tests
336225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".rodata", 8, SHT_PROGBITS, atleast, SHF_ALLOC, SHF_MERGE | SHF_STRINGS },
336325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".rodata1", 9, SHT_PROGBITS, atleast, SHF_ALLOC, SHF_MERGE | SHF_STRINGS },
336425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".shstrtab", 10, SHT_STRTAB, exact, 0, 0 },
336525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".strtab", 8, SHT_STRTAB, atleast, 0, SHF_ALLOC }, // XXX more tests
336625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".symtab", 8, SHT_SYMTAB, atleast, 0, SHF_ALLOC }, // XXX more tests
336725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".symtab_shndx", 14, SHT_SYMTAB_SHNDX, atleast, 0, SHF_ALLOC }, // XXX more tests
336825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".tbss", 6, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 },
336925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".tdata", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 },
337025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".tdata1", 8, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 },
337125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".text", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 },
337225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
337325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* The following are GNU extensions.  */
337425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".gnu.version", 13, SHT_GNU_versym, exact, SHF_ALLOC, 0 },
337525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".gnu.version_d", 15, SHT_GNU_verdef, exact, SHF_ALLOC, 0 },
337625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".gnu.version_r", 15, SHT_GNU_verneed, exact, SHF_ALLOC, 0 },
337725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    { ".gnu.attributes", 16, SHT_GNU_ATTRIBUTES, exact, 0, 0 },
337825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  };
337925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define nspecial_sections \
338025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  (sizeof (special_sections) / sizeof (special_sections[0]))
338125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
338225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define IS_KNOWN_SPECIAL(idx, string, prefix)			      \
338325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  (special_sections[idx].namelen == sizeof string - (prefix ? 1 : 0)  \
338425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   && !memcmp (special_sections[idx].name, string, \
338525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       sizeof string - (prefix ? 1 : 0)))
338625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
338725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
338825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Indeces of some sections we need later.  */
338925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic size_t eh_frame_hdr_scnndx;
339025b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic size_t eh_frame_scnndx;
339125b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic size_t gcc_except_table_scnndx;
339225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
339325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
339425b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
339525b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_sections (Ebl *ebl, GElf_Ehdr *ehdr)
339625b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
339725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_shoff == 0)
339825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* No section header.  */
339925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
340025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
340125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Allocate array to count references in section groups.  */
340225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  scnref = (int *) xcalloc (shnum, sizeof (int));
340325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
340425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the zeroth section first.  It must not have any contents
340525b3c049e70834cf33790a28643ab058b507b35cBen Cheng     and the section header must contain nonzero value at most in the
340625b3c049e70834cf33790a28643ab058b507b35cBen Cheng     sh_size and sh_link fields.  */
340725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr shdr_mem;
340825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
340925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr == NULL)
341025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("cannot get section header of zeroth section\n"));
341125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
341225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
341325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_name != 0)
341425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("zeroth section has nonzero name\n"));
341525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_type != 0)
341625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("zeroth section has nonzero type\n"));
341725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_flags != 0)
341825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("zeroth section has nonzero flags\n"));
341925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_addr != 0)
342025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("zeroth section has nonzero address\n"));
342125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_offset != 0)
342225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("zeroth section has nonzero offset\n"));
342325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_addralign != 0)
342425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("zeroth section has nonzero align value\n"));
342525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_entsize != 0)
342625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("zeroth section has nonzero entry size value\n"));
342725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
342825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_size != 0 && ehdr->e_shnum != 0)
342925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
343025b3c049e70834cf33790a28643ab058b507b35cBen Chengzeroth section has nonzero size value while ELF header has nonzero shnum value\n"));
343125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
343225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_link != 0 && ehdr->e_shstrndx != SHN_XINDEX)
343325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
343425b3c049e70834cf33790a28643ab058b507b35cBen Chengzeroth section has nonzero link value while ELF header does not signal overflow in shstrndx\n"));
343525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
343625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_info != 0 && ehdr->e_phnum != PN_XNUM)
343725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
343825b3c049e70834cf33790a28643ab058b507b35cBen Chengzeroth section has nonzero link value while ELF header does not signal overflow in phnum\n"));
343925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
344025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
344125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int *segment_flags = xcalloc (phnum, sizeof segment_flags[0]);
344225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
344325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool dot_interp_section = false;
344425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
344525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t hash_idx = 0;
344625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t gnu_hash_idx = 0;
344725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
344825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t versym_scnndx = 0;
344925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (size_t cnt = 1; cnt < shnum; ++cnt)
345025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
345125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      shdr = gelf_getshdr (elf_getscn (ebl->elf, cnt), &shdr_mem);
345225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr == NULL)
345325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
345425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("\
345525b3c049e70834cf33790a28643ab058b507b35cBen Chengcannot get section header for section [%2zu] '%s': %s\n"),
345625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 cnt, section_name (ebl, cnt), elf_errmsg (-1));
345725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
345825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
345925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
346025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      const char *scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
346125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
346225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (scnname == NULL)
346325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2zu]: invalid name\n"), cnt);
346425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
346525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
346625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Check whether it is one of the special sections defined in
346725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     the gABI.  */
346825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  size_t s;
346925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  for (s = 0; s < nspecial_sections; ++s)
347025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (strncmp (scnname, special_sections[s].name,
347125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 special_sections[s].namelen) == 0)
347225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
347325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		char stbuf1[100];
347425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		char stbuf2[100];
347525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		char stbuf3[100];
347625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
347725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		GElf_Word good_type = special_sections[s].type;
347825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		if (IS_KNOWN_SPECIAL (s, ".plt", false)
347925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    && ebl_bss_plt_p (ebl, ehdr))
348025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  good_type = SHT_NOBITS;
348125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
348225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		/* In a debuginfo file, any normal section can be SHT_NOBITS.
348325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   This is only invalid for DWARF sections and .shstrtab.  */
348425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		if (shdr->sh_type != good_type
348525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    && (shdr->sh_type != SHT_NOBITS
348625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			|| !is_debuginfo
348725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			|| IS_KNOWN_SPECIAL (s, ".debug_str", false)
348825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			|| IS_KNOWN_SPECIAL (s, ".debug", true)
348925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			|| IS_KNOWN_SPECIAL (s, ".shstrtab", false)))
349025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  ERROR (gettext ("\
349125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s' has wrong type: expected %s, is %s\n"),
349225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 (int) cnt, scnname,
349325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 ebl_section_type_name (ebl, special_sections[s].type,
349425b3c049e70834cf33790a28643ab058b507b35cBen Cheng						stbuf1, sizeof (stbuf1)),
349525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 ebl_section_type_name (ebl, shdr->sh_type,
349625b3c049e70834cf33790a28643ab058b507b35cBen Cheng						stbuf2, sizeof (stbuf2)));
349725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
349825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		if (special_sections[s].attrflag == exact
349925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    || special_sections[s].attrflag == exact_or_gnuld)
350025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
350125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    /* Except for the link order and group bit all the
350225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       other bits should match exactly.  */
350325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if ((shdr->sh_flags & ~(SHF_LINK_ORDER | SHF_GROUP))
350425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			!= special_sections[s].attr
350525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			&& (special_sections[s].attrflag == exact || !gnuld))
350625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
350725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' has wrong flags: expected %s, is %s\n"),
350825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     cnt, scnname,
350925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     section_flags_string (special_sections[s].attr,
351025b3c049e70834cf33790a28643ab058b507b35cBen Cheng						   stbuf1, sizeof (stbuf1)),
351125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     section_flags_string (shdr->sh_flags
351225b3c049e70834cf33790a28643ab058b507b35cBen Cheng						   & ~SHF_LINK_ORDER,
351325b3c049e70834cf33790a28643ab058b507b35cBen Cheng						   stbuf2, sizeof (stbuf2)));
351425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  }
351525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		else if (special_sections[s].attrflag == atleast)
351625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
351725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if ((shdr->sh_flags & special_sections[s].attr)
351825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			!= special_sections[s].attr
351925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			|| ((shdr->sh_flags & ~(SHF_LINK_ORDER | SHF_GROUP
352025b3c049e70834cf33790a28643ab058b507b35cBen Cheng						| special_sections[s].attr
352125b3c049e70834cf33790a28643ab058b507b35cBen Cheng						| special_sections[s].attr2))
352225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    != 0))
352325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
352425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' has wrong flags: expected %s and possibly %s, is %s\n"),
352525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     cnt, scnname,
352625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     section_flags_string (special_sections[s].attr,
352725b3c049e70834cf33790a28643ab058b507b35cBen Cheng						   stbuf1, sizeof (stbuf1)),
352825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     section_flags_string (special_sections[s].attr2,
352925b3c049e70834cf33790a28643ab058b507b35cBen Cheng						   stbuf2, sizeof (stbuf2)),
353025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     section_flags_string (shdr->sh_flags
353125b3c049e70834cf33790a28643ab058b507b35cBen Cheng						   & ~(SHF_LINK_ORDER
353225b3c049e70834cf33790a28643ab058b507b35cBen Cheng						       | SHF_GROUP),
353325b3c049e70834cf33790a28643ab058b507b35cBen Cheng						   stbuf3, sizeof (stbuf3)));
353425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  }
353525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
353625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		if (strcmp (scnname, ".interp") == 0)
353725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
353825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    dot_interp_section = true;
353925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
354025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if (ehdr->e_type == ET_REL)
354125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
354225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' present in object file\n"),
354325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     cnt, scnname);
354425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
354525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if ((shdr->sh_flags & SHF_ALLOC) != 0
354625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			&& !has_loadable_segment)
354725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
354825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' has SHF_ALLOC flag set but there is no loadable segment\n"),
354925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     cnt, scnname);
355025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    else if ((shdr->sh_flags & SHF_ALLOC) == 0
355125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     && has_loadable_segment)
355225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
355325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' has SHF_ALLOC flag not set but there are loadable segments\n"),
355425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     cnt, scnname);
355525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  }
355625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		else
355725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
355825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if (strcmp (scnname, ".symtab_shndx") == 0
355925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			&& ehdr->e_type != ET_REL)
356025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
356125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' is extension section index table in non-object file\n"),
356225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     cnt, scnname);
356325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
356425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    /* These sections must have the SHF_ALLOC flag set iff
356525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       a loadable segment is available.
356625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
356725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       .relxxx
356825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       .strtab
356925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       .symtab
357025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       .symtab_shndx
357125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
357225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       Check that if there is a reference from the
357325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       loaded section these sections also have the
357425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       ALLOC flag set.  */
357525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#if 0
357625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    // XXX TODO
357725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if ((shdr->sh_flags & SHF_ALLOC) != 0
357825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			&& !has_loadable_segment)
357925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
358025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' has SHF_ALLOC flag set but there is no loadable segment\n"),
358125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     cnt, scnname);
358225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    else if ((shdr->sh_flags & SHF_ALLOC) == 0
358325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     && has_loadable_segment)
358425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
358525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' has SHF_ALLOC flag not set but there are loadable segments\n"),
358625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			     cnt, scnname);
358725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
358825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  }
358925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
359025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		break;
359125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      }
359225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
359325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Remember a few special sections for later.  */
359425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (strcmp (scnname, ".eh_frame_hdr") == 0)
359525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    eh_frame_hdr_scnndx = cnt;
359625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else if (strcmp (scnname, ".eh_frame") == 0)
359725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    eh_frame_scnndx = cnt;
359825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else if (strcmp (scnname, ".gcc_except_table") == 0)
359925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    gcc_except_table_scnndx = cnt;
360025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
360125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
360225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_entsize != 0 && shdr->sh_size % shdr->sh_entsize)
360325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
360425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s': size not multiple of entry size\n"),
360525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       cnt, section_name (ebl, cnt));
360625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
360725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf_strptr (ebl->elf, shstrndx, shdr->sh_name) == NULL)
360825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("cannot get section header\n"));
360925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
361025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_type >= SHT_NUM
361125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && shdr->sh_type != SHT_GNU_ATTRIBUTES
361225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && shdr->sh_type != SHT_GNU_LIBLIST
361325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && shdr->sh_type != SHT_CHECKSUM
361425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && shdr->sh_type != SHT_GNU_verdef
361525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && shdr->sh_type != SHT_GNU_verneed
361625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && shdr->sh_type != SHT_GNU_versym
361725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && ebl_section_type_name (ebl, shdr->sh_type, NULL, 0) == NULL)
361825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("section [%2zu] '%s' has unsupported type %d\n"),
361925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       cnt, section_name (ebl, cnt),
362025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       (int) shdr->sh_type);
362125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
362225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#define ALL_SH_FLAGS (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE \
362325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      | SHF_STRINGS | SHF_INFO_LINK | SHF_LINK_ORDER \
362425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      | SHF_OS_NONCONFORMING | SHF_GROUP | SHF_TLS)
362525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_flags & ~(GElf_Xword) ALL_SH_FLAGS)
362625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
362725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Xword sh_flags = shdr->sh_flags & ~(GElf_Xword) ALL_SH_FLAGS;
362825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (sh_flags & SHF_MASKPROC)
362925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
363025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (!ebl_machine_section_flag_check (ebl,
363125b3c049e70834cf33790a28643ab058b507b35cBen Cheng						   sh_flags & SHF_MASKPROC))
363225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("section [%2zu] '%s'"
363325b3c049e70834cf33790a28643ab058b507b35cBen Cheng				" contains invalid processor-specific flag(s)"
363425b3c049e70834cf33790a28643ab058b507b35cBen Cheng				" %#" PRIx64 "\n"),
363525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       cnt, section_name (ebl, cnt), sh_flags & SHF_MASKPROC);
363625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      sh_flags &= ~(GElf_Xword) SHF_MASKPROC;
363725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
363825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (sh_flags != 0)
363925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("section [%2zu] '%s' contains unknown flag(s)"
364025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    " %#" PRIx64 "\n"),
364125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   cnt, section_name (ebl, cnt), sh_flags);
364225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
364325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_flags & SHF_TLS)
364425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
364525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  // XXX Correct?
364625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (shdr->sh_addr != 0 && !gnuld)
364725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
364825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s': thread-local data sections address not zero\n"),
364925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   cnt, section_name (ebl, cnt));
365025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
365125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  // XXX TODO more tests!?
365225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
365325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
365425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_link >= shnum)
365525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
365625b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s': invalid section reference in link value\n"),
365725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       cnt, section_name (ebl, cnt));
365825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
365925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (SH_INFO_LINK_P (shdr) && shdr->sh_info >= shnum)
366025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
366125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s': invalid section reference in info value\n"),
366225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       cnt, section_name (ebl, cnt));
366325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
366425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((shdr->sh_flags & SHF_MERGE) == 0
366525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && (shdr->sh_flags & SHF_STRINGS) != 0
366625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && be_strict)
366725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
366825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s': strings flag set without merge flag\n"),
366925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       cnt, section_name (ebl, cnt));
367025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
367125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((shdr->sh_flags & SHF_MERGE) != 0 && shdr->sh_entsize == 0)
367225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
367325b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s': merge flag set but entry size is zero\n"),
367425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       cnt, section_name (ebl, cnt));
367525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
367625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_flags & SHF_GROUP)
367725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	check_scn_group (ebl, cnt);
367825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
367925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (shdr->sh_flags & SHF_EXECINSTR)
368025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
368125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  switch (shdr->sh_type)
368225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
368325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    case SHT_PROGBITS:
368425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      break;
368525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
368625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    case SHT_NOBITS:
368725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (is_debuginfo)
368825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		break;
368925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    default:
369025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
369125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' has unexpected type %d for an executable section\n"),
369225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     cnt, section_name (ebl, cnt), shdr->sh_type);
369325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      break;
369425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
369525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
369625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if ((shdr->sh_flags & SHF_WRITE)
369725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      && !ebl_check_special_section (ebl, cnt, shdr,
369825b3c049e70834cf33790a28643ab058b507b35cBen Cheng					     section_name (ebl, cnt)))
369925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
370025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' is both executable and writable\n"),
370125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   cnt, section_name (ebl, cnt));
370225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
370325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
370425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_type != ET_REL && (shdr->sh_flags & SHF_ALLOC) != 0)
370525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
370625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Make sure the section is contained in a loaded segment
370725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     and that the initialization part matches NOBITS sections.  */
370825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  unsigned int pcnt;
370925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Phdr phdr_mem;
371025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Phdr *phdr;
371125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
371225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  for (pcnt = 0; pcnt < phnum; ++pcnt)
371325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if ((phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem)) != NULL
371425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		&& ((phdr->p_type == PT_LOAD
371525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     && (shdr->sh_flags & SHF_TLS) == 0)
371625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    || (phdr->p_type == PT_TLS
371725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			&& (shdr->sh_flags & SHF_TLS) != 0))
371825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		&& phdr->p_offset <= shdr->sh_offset
371925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		&& (phdr->p_offset + phdr->p_filesz > shdr->sh_offset
372025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    || (phdr->p_offset + phdr->p_memsz > shdr->sh_offset
372125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			&& shdr->sh_type == SHT_NOBITS)))
372225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      {
372325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		/* Found the segment.  */
372425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		if (phdr->p_offset + phdr->p_memsz
372525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    < shdr->sh_offset + shdr->sh_size)
372625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  ERROR (gettext ("\
372725b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' not fully contained in segment of program header entry %d\n"),
372825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 cnt, section_name (ebl, cnt), pcnt);
372925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
373025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		if (shdr->sh_type == SHT_NOBITS)
373125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
373225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if (shdr->sh_offset < phdr->p_offset + phdr->p_filesz
373325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			&& !is_debuginfo)
373425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
373525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' has type NOBITS but is read from the file in segment of program header entry %d\n"),
373625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 cnt, section_name (ebl, cnt), pcnt);
373725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  }
373825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		else
373925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
374025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    const GElf_Off end = phdr->p_offset + phdr->p_filesz;
374125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if (shdr->sh_offset > end ||
374225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			(shdr->sh_offset == end && shdr->sh_size != 0))
374325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      ERROR (gettext ("\
374425b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' has not type NOBITS but is not read from the file in segment of program header entry %d\n"),
374525b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 cnt, section_name (ebl, cnt), pcnt);
374625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  }
374725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
374825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		if (shdr->sh_type != SHT_NOBITS)
374925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  {
375025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if ((shdr->sh_flags & SHF_EXECINSTR) != 0)
375125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      {
375225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			segment_flags[pcnt] |= PF_X;
375325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			if ((phdr->p_flags & PF_X) == 0)
375425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  ERROR (gettext ("\
375525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' is executable in nonexecutable segment %d\n"),
375625b3c049e70834cf33790a28643ab058b507b35cBen Cheng				 cnt, section_name (ebl, cnt), pcnt);
375725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      }
375825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
375925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    if ((shdr->sh_flags & SHF_WRITE) != 0)
376025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      {
376125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			segment_flags[pcnt] |= PF_W;
376225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			if (0	/* XXX vdso images have this */
376325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			    && (phdr->p_flags & PF_W) == 0)
376425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  ERROR (gettext ("\
376525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' is writable in unwritable segment %d\n"),
376625b3c049e70834cf33790a28643ab058b507b35cBen Cheng				 cnt, section_name (ebl, cnt), pcnt);
376725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      }
376825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  }
376925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
377025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		break;
377125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      }
377225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
377325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (pcnt == phnum)
377425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
377525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s': alloc flag set but section not in any loaded segment\n"),
377625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   cnt, section_name (ebl, cnt));
377725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
377825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
377925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (cnt == shstrndx && shdr->sh_type != SHT_STRTAB)
378025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
378125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s': ELF header says this is the section header string table but type is not SHT_TYPE\n"),
378225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       cnt, section_name (ebl, cnt));
378325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
378425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      switch (shdr->sh_type)
378525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
378625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_DYNSYM:
378725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (ehdr->e_type == ET_REL)
378825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
378925b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"),
379025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		   cnt, section_name (ebl, cnt));
379125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* FALLTHROUGH */
379225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_SYMTAB:
379325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_symtab (ebl, ehdr, shdr, cnt);
379425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
379525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
379625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_RELA:
379725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_rela (ebl, ehdr, shdr, cnt);
379825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
379925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
380025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_REL:
380125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_rel (ebl, ehdr, shdr, cnt);
380225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
380325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
380425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_DYNAMIC:
380525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_dynamic (ebl, ehdr, shdr, cnt);
380625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
380725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
380825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_SYMTAB_SHNDX:
380925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_symtab_shndx (ebl, ehdr, shdr, cnt);
381025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
381125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
381225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_HASH:
381325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_hash (shdr->sh_type, ebl, ehdr, shdr, cnt);
381425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  hash_idx = cnt;
381525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
381625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
381725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_GNU_HASH:
381825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_hash (shdr->sh_type, ebl, ehdr, shdr, cnt);
381925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  gnu_hash_idx = cnt;
382025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
382125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
382225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_NULL:
382325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_null (ebl, shdr, cnt);
382425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
382525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
382625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_GROUP:
382725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_group (ebl, ehdr, shdr, cnt);
382825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
382925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
383025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_NOTE:
383125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_note_section (ebl, ehdr, shdr, cnt);
383225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
383325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
383425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_GNU_versym:
383525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* We cannot process this section now since we have no guarantee
383625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     that the verneed and verdef sections have already been read.
383725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     Just remember the section index.  */
383825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (versym_scnndx != 0)
383925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("more than one version symbol table present\n"));
384025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  versym_scnndx = cnt;
384125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
384225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
384325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_GNU_verneed:
384425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_verneed (ebl, shdr, cnt);
384525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
384625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
384725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_GNU_verdef:
384825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_verdef (ebl, shdr, cnt);
384925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
385025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
385125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	case SHT_GNU_ATTRIBUTES:
385225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  check_attributes (ebl, ehdr, shdr, cnt);
385325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
385425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
385525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	default:
385625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Nothing.  */
385725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  break;
385825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
385925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
386025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
386125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (has_interp_segment && !dot_interp_section)
386225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("INTERP program header entry but no .interp section\n"));
386325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
386425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (!is_debuginfo)
386525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    for (unsigned int pcnt = 0; pcnt < phnum; ++pcnt)
386625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      {
386725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Phdr phdr_mem;
386825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	GElf_Phdr *phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem);
386925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (phdr != NULL && (phdr->p_type == PT_LOAD || phdr->p_type == PT_TLS))
387025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
387125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if ((phdr->p_flags & PF_X) != 0
387225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		&& (segment_flags[pcnt] & PF_X) == 0)
387325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
387425b3c049e70834cf33790a28643ab058b507b35cBen Chengloadable segment [%u] is executable but contains no executable sections\n"),
387525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     pcnt);
387625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
387725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if ((phdr->p_flags & PF_W) != 0
387825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		&& (segment_flags[pcnt] & PF_W) == 0)
387925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
388025b3c049e70834cf33790a28643ab058b507b35cBen Chengloadable segment [%u] is writable but contains no writable sections\n"),
388125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     pcnt);
388225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
388325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      }
388425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
388525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  free (segment_flags);
388625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
388725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (version_namelist != NULL)
388825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
388925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (versym_scnndx == 0)
389025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
389125b3c049e70834cf33790a28643ab058b507b35cBen Chengno .gnu.versym section present but .gnu.versym_d or .gnu.versym_r section exist\n"));
389225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
389325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	check_versym (ebl, versym_scnndx);
389425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
389525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Check for duplicate index numbers.  */
389625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      do
389725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
389825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  struct version_namelist *runp = version_namelist->next;
389925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  while (runp != NULL)
390025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
390125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (version_namelist->ndx == runp->ndx)
390225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
390325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  ERROR (gettext ("duplicate version index %d\n"),
390425b3c049e70834cf33790a28643ab058b507b35cBen Cheng			 (int) version_namelist->ndx);
390525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  break;
390625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
390725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      runp = runp->next;
390825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
390925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
391025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  struct version_namelist *old = version_namelist;
391125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  version_namelist = version_namelist->next;
391225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  free (old);
391325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
391425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      while (version_namelist != NULL);
391525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
391625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else if (versym_scnndx != 0)
391725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
391825b3c049e70834cf33790a28643ab058b507b35cBen Cheng.gnu.versym section present without .gnu.versym_d or .gnu.versym_r\n"));
391925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
392025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (hash_idx != 0 && gnu_hash_idx != 0)
392125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    compare_hash_gnu_hash (ebl, ehdr, hash_idx, gnu_hash_idx);
392225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
392325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  free (scnref);
392425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
392525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
392625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
392725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic GElf_Off
392825b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_note_data (Ebl *ebl, const GElf_Ehdr *ehdr,
392925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 Elf_Data *data, int shndx, int phndx, GElf_Off start)
393025b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
393125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t offset = 0;
393225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t last_offset = 0;
393325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Nhdr nhdr;
393425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t name_offset;
393525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t desc_offset;
393625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  while (offset < data->d_size
393725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 && (offset = gelf_getnote (data, offset,
393825b3c049e70834cf33790a28643ab058b507b35cBen Cheng				    &nhdr, &name_offset, &desc_offset)) > 0)
393925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
394025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      last_offset = offset;
394125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
394225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Make sure it is one of the note types we know about.  */
394325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (ehdr->e_type == ET_CORE)
394425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	switch (nhdr.n_type)
394525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
394625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_PRSTATUS:
394725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_FPREGSET:
394825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_PRPSINFO:
394925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_TASKSTRUCT:		/* NT_PRXREG on Solaris.  */
395025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_PLATFORM:
395125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_AUXV:
395225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_GWINDOWS:
395325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_ASRS:
395425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_PSTATUS:
395525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_PSINFO:
395625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_PRCRED:
395725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_UTSNAME:
395825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_LWPSTATUS:
395925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_LWPSINFO:
396025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_PRFPXREG:
396125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    /* Known type.  */
396225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    break;
396325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
396425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  default:
396525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (shndx == 0)
396625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
396725b3c049e70834cf33790a28643ab058b507b35cBen Chengphdr[%d]: unknown core file note type %" PRIu32 " at offset %" PRIu64 "\n"),
396825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     phndx, (uint32_t) nhdr.n_type, start + offset);
396925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    else
397025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
397125b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': unknown core file note type %" PRIu32
397225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      " at offset %Zu\n"),
397325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     shndx, section_name (ebl, shndx),
397425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     (uint32_t) nhdr.n_type, offset);
397525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
397625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
397725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	switch (nhdr.n_type)
397825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  {
397925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_GNU_ABI_TAG:
398025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_GNU_HWCAP:
398125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_GNU_BUILD_ID:
398225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case NT_GNU_GOLD_VERSION:
398325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    break;
398425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
398525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  case 0:
398625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    /* Linux vDSOs use a type 0 note for the kernel version word.  */
398725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (nhdr.n_namesz == sizeof "Linux"
398825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		&& !memcmp (data->d_buf + name_offset, "Linux", sizeof "Linux"))
398925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      break;
399025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
399125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  default:
399225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    if (shndx == 0)
399325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
399425b3c049e70834cf33790a28643ab058b507b35cBen Chengphdr[%d]: unknown object file note type %" PRIu32 " at offset %Zu\n"),
399525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     phndx, (uint32_t) nhdr.n_type, offset);
399625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    else
399725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      ERROR (gettext ("\
399825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': unknown object file note type %" PRIu32
399925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      " at offset %Zu\n"),
400025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     shndx, section_name (ebl, shndx),
400125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		     (uint32_t) nhdr.n_type, offset);
400225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  }
400325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
400425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
400525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return last_offset;
400625b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
400725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
400825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
400925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
401025b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_note (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Phdr *phdr, int cnt)
401125b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
401225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL
401325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
401425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
401525b3c049e70834cf33790a28643ab058b507b35cBen Chengphdr[%d]: no note entries defined for the type of file\n"),
401625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   cnt);
401725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
401825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (is_debuginfo)
401925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* The p_offset values in a separate debug file are bogus.  */
402025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
402125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
402225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (phdr->p_filesz == 0)
402325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
402425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
402525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Off notes_size = 0;
402625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata_rawchunk (ebl->elf,
402725b3c049e70834cf33790a28643ab058b507b35cBen Cheng					 phdr->p_offset, phdr->p_filesz,
402825b3c049e70834cf33790a28643ab058b507b35cBen Cheng					 ELF_T_NHDR);
402925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data != NULL)
403025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    notes_size = check_note_data (ebl, ehdr, data, 0, cnt, phdr->p_offset);
403125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
403225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (notes_size == 0)
403325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("phdr[%d]: cannot get content of note section: %s\n"),
403425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   cnt, elf_errmsg (-1));
403525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else if (notes_size != phdr->p_filesz)
403625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("phdr[%d]: extra %" PRIu64 " bytes after last note\n"),
403725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   cnt, phdr->p_filesz - notes_size);
403825b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
403925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
404025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
404125b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
404225b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_note_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
404325b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
404425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (shdr->sh_size == 0)
404525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
404625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
404725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
404825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (data == NULL)
404925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
405025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
405125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
405225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
405325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
405425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
405525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL
405625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
405725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
405825b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2d] '%s': no note entries defined for the type of file\n"),
405925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     idx, section_name (ebl, idx));
406025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
406125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Off notes_size = check_note_data (ebl, ehdr, data, idx, 0, 0);
406225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
406325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (notes_size == 0)
406425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2d] '%s': cannot get content of note section\n"),
406525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx));
406625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else if (notes_size != shdr->sh_size)
406725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("section [%2d] '%s': extra %" PRIu64
406825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    " bytes after last note\n"),
406925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	   idx, section_name (ebl, idx), shdr->sh_size - notes_size);
407025b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
407125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
407225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
407325b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Index of the PT_GNU_EH_FRAME program eader entry.  */
407425b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic int pt_gnu_eh_frame_pndx;
407525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
407625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
407725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
407825b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_program_header (Ebl *ebl, GElf_Ehdr *ehdr)
407925b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
408025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_phoff == 0)
408125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    return;
408225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
408325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN
408425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && ehdr->e_type != ET_CORE)
408525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("\
408625b3c049e70834cf33790a28643ab058b507b35cBen Chengonly executables, shared objects, and core files can have program headers\n"));
408725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
408825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int num_pt_interp = 0;
408925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int num_pt_tls = 0;
409025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  int num_pt_relro = 0;
409125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
409225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  for (unsigned int cnt = 0; cnt < phnum; ++cnt)
409325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
409425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Phdr phdr_mem;
409525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      GElf_Phdr *phdr;
409625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
409725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem);
409825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr == NULL)
409925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
410025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ERROR (gettext ("cannot get program header entry %d: %s\n"),
410125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 cnt, elf_errmsg (-1));
410225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  continue;
410325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
410425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
410525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr->p_type >= PT_NUM && phdr->p_type != PT_GNU_EH_FRAME
410625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && phdr->p_type != PT_GNU_STACK && phdr->p_type != PT_GNU_RELRO
410725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Check for a known machine-specific type.  */
410825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && ebl_segment_type_name (ebl, phdr->p_type, NULL, 0) == NULL)
410925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
411025b3c049e70834cf33790a28643ab058b507b35cBen Chengprogram header entry %d: unknown program header entry type %#" PRIx64 "\n"),
411125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       cnt, (uint64_t) phdr->p_type);
411225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
411325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr->p_type == PT_LOAD)
411425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	has_loadable_segment = true;
411525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (phdr->p_type == PT_INTERP)
411625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
411725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (++num_pt_interp != 1)
411825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
411925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (num_pt_interp == 2)
412025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
412125b3c049e70834cf33790a28643ab058b507b35cBen Chengmore than one INTERP entry in program header\n"));
412225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
412325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  has_interp_segment = true;
412425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
412525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (phdr->p_type == PT_TLS)
412625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
412725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (++num_pt_tls == 2)
412825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("more than one TLS entry in program header\n"));
412925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
413025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (phdr->p_type == PT_NOTE)
413125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	check_note (ebl, ehdr, phdr, cnt);
413225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (phdr->p_type == PT_DYNAMIC)
413325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
413425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (ehdr->e_type == ET_EXEC && ! has_interp_segment)
413525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
413625b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic executable cannot have dynamic sections\n"));
413725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
413825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
413925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* Check that the .dynamic section, if it exists, has
414025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 the same address.  */
414125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      Elf_Scn *scn = NULL;
414225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
414325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
414425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  GElf_Shdr shdr_mem;
414525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
414625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC)
414725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
414825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (phdr->p_offset != shdr->sh_offset)
414925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
415025b3c049e70834cf33790a28643ab058b507b35cBen Chengdynamic section reference in program header has wrong offset\n"));
415125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (phdr->p_memsz != shdr->sh_size)
415225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
415325b3c049e70834cf33790a28643ab058b507b35cBen Chengdynamic section size mismatch in program and section header\n"));
415425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      break;
415525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
415625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
415725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
415825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
415925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (phdr->p_type == PT_GNU_RELRO)
416025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
416125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (++num_pt_relro == 2)
416225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
416325b3c049e70834cf33790a28643ab058b507b35cBen Chengmore than one GNU_RELRO entry in program header\n"));
416425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
416525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
416625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* Check that the region is in a writable segment.  */
416725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      unsigned int inner;
416825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      for (inner = 0; inner < phnum; ++inner)
416925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
417025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  GElf_Phdr phdr2_mem;
417125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  GElf_Phdr *phdr2;
417225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
417325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  phdr2 = gelf_getphdr (ebl->elf, inner, &phdr2_mem);
417425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (phdr2 == NULL)
417525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    continue;
417625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
417725b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (phdr2->p_type == PT_LOAD
417825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      && phdr->p_vaddr >= phdr2->p_vaddr
417925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      && (phdr->p_vaddr + phdr->p_memsz
418025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  <= phdr2->p_vaddr + phdr2->p_memsz))
418125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
418225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if ((phdr2->p_flags & PF_W) == 0)
418325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
418425b3c049e70834cf33790a28643ab058b507b35cBen Chengloadable segment GNU_RELRO applies to is not writable\n"));
418525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if ((phdr2->p_flags & ~PF_W) != (phdr->p_flags & ~PF_W))
418625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
418725b3c049e70834cf33790a28643ab058b507b35cBen Chengloadable segment [%u] flags do not match GNU_RELRO [%u] flags\n"),
418825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       cnt, inner);
418925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      break;
419025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
419125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
419225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
419325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (inner >= phnum)
419425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
419525b3c049e70834cf33790a28643ab058b507b35cBen Cheng%s segment not contained in a loaded segment\n"), "GNU_RELRO");
419625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
419725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
419825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (phdr->p_type == PT_PHDR)
419925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
420025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Check that the region is in a writable segment.  */
420125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  unsigned int inner;
420225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  for (inner = 0; inner < phnum; ++inner)
420325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
420425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Phdr phdr2_mem;
420525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      GElf_Phdr *phdr2;
420625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
420725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      phdr2 = gelf_getphdr (ebl->elf, inner, &phdr2_mem);
420825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (phdr2 != NULL
420925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  && phdr2->p_type == PT_LOAD
421025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  && phdr->p_vaddr >= phdr2->p_vaddr
421125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  && (phdr->p_vaddr + phdr->p_memsz
421225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      <= phdr2->p_vaddr + phdr2->p_memsz))
421325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		break;
421425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
421525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
421625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (inner >= phnum)
421725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
421825b3c049e70834cf33790a28643ab058b507b35cBen Cheng%s segment not contained in a loaded segment\n"), "PHDR");
421925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
422025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Check that offset in segment corresponds to offset in ELF
422125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     header.  */
422225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (phdr->p_offset != ehdr->e_phoff)
422325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
422425b3c049e70834cf33790a28643ab058b507b35cBen Chengprogram header offset in ELF header and PHDR entry do not match"));
422525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
422625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else if (phdr->p_type == PT_GNU_EH_FRAME)
422725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
422825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* If there is an .eh_frame_hdr section it must be
422925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	     referenced by this program header entry.  */
423025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  Elf_Scn *scn = NULL;
423125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr shdr_mem;
423225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Shdr *shdr = NULL;
423325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  bool any = false;
423425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
423525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
423625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      any = true;
423725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      shdr = gelf_getshdr (scn, &shdr_mem);
423825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (shdr != NULL
423925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  && shdr->sh_type == (is_debuginfo
424025b3c049e70834cf33790a28643ab058b507b35cBen Cheng				       ? SHT_NOBITS : SHT_PROGBITS)
424125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  && ! strcmp (".eh_frame_hdr",
424225b3c049e70834cf33790a28643ab058b507b35cBen Cheng			       elf_strptr (ebl->elf, shstrndx, shdr->sh_name)))
424325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		{
424425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  if (! is_debuginfo)
424525b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    {
424625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (phdr->p_offset != shdr->sh_offset)
424725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
424825b3c049e70834cf33790a28643ab058b507b35cBen Chengcall frame search table reference in program header has wrong offset\n"));
424925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      if (phdr->p_memsz != shdr->sh_size)
425025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ERROR (gettext ("\
425125b3c049e70834cf33790a28643ab058b507b35cBen Chengcall frame search table size mismatch in program and section header\n"));
425225b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    }
425325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  break;
425425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		}
425525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
425625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
425725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (scn == NULL)
425825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
425925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* If there is no section header table we don't
426025b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 complain.  But if there is one there should be an
426125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 entry for .eh_frame_hdr.  */
426225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if (any)
426325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
426425b3c049e70834cf33790a28643ab058b507b35cBen ChengPT_GNU_EH_FRAME present but no .eh_frame_hdr section\n"));
426525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
426625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else
426725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
426825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      /* The section must be allocated and not be writable and
426925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		 executable.  */
427025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if ((phdr->p_flags & PF_R) == 0)
427125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
427225b3c049e70834cf33790a28643ab058b507b35cBen Chengcall frame search table must be allocated\n"));
427325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      else if (shdr != NULL && (shdr->sh_flags & SHF_ALLOC) == 0)
427425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
427525b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' must be allocated\n"), elf_ndxscn (scn), ".eh_frame_hdr");
427625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
427725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if ((phdr->p_flags & PF_W) != 0)
427825b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
427925b3c049e70834cf33790a28643ab058b507b35cBen Chengcall frame search table must not be writable\n"));
428025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      else if (shdr != NULL && (shdr->sh_flags & SHF_WRITE) != 0)
428125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
428225b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' must not be writable\n"),
428325b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       elf_ndxscn (scn), ".eh_frame_hdr");
428425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
428525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      if ((phdr->p_flags & PF_X) != 0)
428625b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
428725b3c049e70834cf33790a28643ab058b507b35cBen Chengcall frame search table must not be executable\n"));
428825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      else if (shdr != NULL && (shdr->sh_flags & SHF_EXECINSTR) != 0)
428925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		ERROR (gettext ("\
429025b3c049e70834cf33790a28643ab058b507b35cBen Chengsection [%2zu] '%s' must not be executable\n"),
429125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		       elf_ndxscn (scn), ".eh_frame_hdr");
429225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
429325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
429425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  /* Remember which entry this is.  */
429525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  pt_gnu_eh_frame_pndx = cnt;
429625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
429725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
429825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr->p_filesz > phdr->p_memsz
429925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  && (phdr->p_memsz != 0 || phdr->p_type != PT_NOTE))
430025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	ERROR (gettext ("\
430125b3c049e70834cf33790a28643ab058b507b35cBen Chengprogram header entry %d: file size greater than memory size\n"),
430225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	       cnt);
430325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
430425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phdr->p_align > 1)
430525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
430625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (!powerof2 (phdr->p_align))
430725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
430825b3c049e70834cf33790a28643ab058b507b35cBen Chengprogram header entry %d: alignment not a power of 2\n"), cnt);
430925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  else if ((phdr->p_vaddr - phdr->p_offset) % phdr->p_align != 0)
431025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    ERROR (gettext ("\
431125b3c049e70834cf33790a28643ab058b507b35cBen Chengprogram header entry %d: file offset and virtual address not module of alignment\n"), cnt);
431225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
431325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
431425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
431525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
431625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
431725b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
431825b3c049e70834cf33790a28643ab058b507b35cBen Chengcheck_exception_data (Ebl *ebl __attribute__ ((unused)),
431925b3c049e70834cf33790a28643ab058b507b35cBen Cheng		      GElf_Ehdr *ehdr __attribute__ ((unused)))
432025b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
432125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)
432225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && pt_gnu_eh_frame_pndx == 0 && eh_frame_hdr_scnndx != 0)
432325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("executable/DSO with .eh_frame_hdr section does not have "
432425b3c049e70834cf33790a28643ab058b507b35cBen Cheng		    "a PT_GNU_EH_FRAME program header entry"));
432525b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
432625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
432725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
432825b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Process one file.  */
432925b3c049e70834cf33790a28643ab058b507b35cBen Chengstatic void
433025b3c049e70834cf33790a28643ab058b507b35cBen Chengprocess_elf_file (Elf *elf, const char *prefix, const char *suffix,
433125b3c049e70834cf33790a28643ab058b507b35cBen Cheng		  const char *fname, size_t size, bool only_one)
433225b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
433325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Reset variables.  */
433425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  ndynamic = 0;
433525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  nverneed = 0;
433625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  nverdef = 0;
433725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  textrel = false;
433825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  needed_textrel = false;
433925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  has_loadable_segment = false;
434025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  has_interp_segment = false;
434125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
434225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Ehdr ehdr_mem;
434325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
434425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Ebl *ebl;
434525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
434625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Print the file name.  */
434725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (!only_one)
434825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
434925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (prefix != NULL)
435025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	printf ("\n%s(%s)%s:\n", prefix, fname, suffix);
435125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      else
435225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	printf ("\n%s:\n", fname);
435325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
435425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
435525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (ehdr == NULL)
435625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
435725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      ERROR (gettext ("cannot read ELF header: %s\n"), elf_errmsg (-1));
435825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return;
435925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
436025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
436125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  ebl = ebl_openbackend (elf);
436225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* If there is no appropriate backend library we cannot test
436325b3c049e70834cf33790a28643ab058b507b35cBen Cheng     architecture and OS specific features.  Any encountered extension
436425b3c049e70834cf33790a28643ab058b507b35cBen Cheng     is an error.  */
436525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
436625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Go straight by the gABI, check all the parts in turn.  */
436725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  check_elf_header (ebl, ehdr, size);
436825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
436925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the program header.  */
437025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  check_program_header (ebl, ehdr);
437125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
437225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Next the section headers.  It is OK if there are no section
437325b3c049e70834cf33790a28643ab058b507b35cBen Cheng     headers at all.  */
437425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  check_sections (ebl, ehdr);
437525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
437625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Check the exception handling data, if it exists.  */
437725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (pt_gnu_eh_frame_pndx != 0 || eh_frame_hdr_scnndx != 0
437825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      || eh_frame_scnndx != 0 || gcc_except_table_scnndx != 0)
437925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    check_exception_data (ebl, ehdr);
438025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
438125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Report if no relocation section needed the text relocation flag.  */
438225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (textrel && !needed_textrel)
438325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ERROR (gettext ("text relocation flag set but not needed\n"));
438425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
438525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Free the resources.  */
438625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  ebl_closebackend (ebl);
438725b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
438825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
438925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
439025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "debugpred.h"
4391