1441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Pedantic checking of ELF files compliance with gABI/psABI spec.
2cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc.
3cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   This file is part of Red Hat elfutils.
4441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project   Written by Ulrich Drepper <drepper@redhat.com>, 2001.
5441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
6cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is free software; you can redistribute it and/or modify
7cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   it under the terms of the GNU General Public License as published by the
8cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Free Software Foundation; version 2 of the License.
9441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
10cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is distributed in the hope that it will be useful, but
11cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
12cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   General Public License for more details.
14cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
15cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   You should have received a copy of the GNU General Public License along
16cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   with Red Hat elfutils; if not, write to the Free Software Foundation,
17cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
19cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is an included package of the Open Invention Network.
20cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   An included package of the Open Invention Network is a package for which
21cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Open Invention Network licensees cross-license their patents.  No patent
22cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   license is granted, either expressly or impliedly, by designation as an
23cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   included package.  Should you wish to participate in the Open Invention
24cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Network licensing program, please visit www.openinventionnetwork.com
25cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   <http://www.openinventionnetwork.com>.  */
26441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
27441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#ifdef HAVE_CONFIG_H
28441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project# include <config.h>
29441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#endif
30441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
31441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <argp.h>
32441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <assert.h>
33441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <byteswap.h>
34441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <endian.h>
35441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <error.h>
36441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <fcntl.h>
37441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <gelf.h>
38441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <inttypes.h>
39441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <libintl.h>
40441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <locale.h>
41441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <stdbool.h>
42441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <stdlib.h>
43441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <string.h>
44441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <unistd.h>
45441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <sys/param.h>
46441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
47441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <elf-knowledge.h>
48441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <system.h>
49cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "../libelf/libelfP.h"
50cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "../libelf/common.h"
51cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "../libebl/libeblP.h"
52cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "../libdw/libdwP.h"
53cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "../libdwfl/libdwflP.h"
54cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "../libdw/memory-access.h"
55441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
56441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
57441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Name and version of program.  */
58441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void print_version (FILE *stream, struct argp_state *state);
59441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectvoid (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
60441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
61cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Bug report address.  */
62cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengconst char *argp_program_bug_address = PACKAGE_BUGREPORT;
63441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
64441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#define ARGP_strict	300
65441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#define ARGP_gnuld	301
66441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
67441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Definitions of arguments for argp functions.  */
68441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic const struct argp_option options[] =
69441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
70441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
71441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  { "strict", ARGP_strict, NULL, 0,
72cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    N_("Be extremely strict, flag level 2 features."), 0 },
73cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { "quiet", 'q', NULL, 0, N_("Do not print anything if successful"), 0 },
74cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { "debuginfo", 'd', NULL, 0, N_("Binary is a separate debuginfo file"), 0 },
75441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  { "gnu-ld", ARGP_gnuld, NULL, 0,
76441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    N_("Binary has been created with GNU ld and is therefore known to be \
77cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengbroken in certain ways"), 0 },
78cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  { NULL, 0, NULL, 0, NULL, 0 }
79441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project};
80441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
81441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Short description of program.  */
82441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic const char doc[] = N_("\
83441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source ProjectPedantic checking of ELF files compliance with gABI/psABI spec.");
84441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
85441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Strings for arguments in help texts.  */
86441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic const char args_doc[] = N_("FILE...");
87441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
88441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Prototype for option handler.  */
89441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic error_t parse_opt (int key, char *arg, struct argp_state *state);
90441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
91441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Data structure to communicate with argp functions.  */
92441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic struct argp argp =
93441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
94cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  options, parse_opt, args_doc, doc, NULL, NULL, NULL
95441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project};
96441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
97441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
98441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Declarations of local functions.  */
99441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void process_file (int fd, Elf *elf, const char *prefix,
100441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			  const char *suffix, const char *fname, size_t size,
101441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			  bool only_one);
102441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void process_elf_file (Elf *elf, const char *prefix, const char *suffix,
103441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			      const char *fname, size_t size, bool only_one);
104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void check_note_section (Ebl *ebl, GElf_Ehdr *ehdr,
105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				GElf_Shdr *shdr, int idx);
106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
107441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
108441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Report an error.  */
109441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#define ERROR(str, args...) \
110441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  do {									      \
111441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    printf (str, ##args);						      \
112441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ++error_count;							      \
113441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  } while (0)
114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic unsigned int error_count;
115441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
116441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* True if we should perform very strict testing.  */
117441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic bool be_strict;
118441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
119441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* True if no message is to be printed if the run is succesful.  */
120441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic bool be_quiet;
121441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* True if binary is from strip -f, not a normal ELF file.  */
123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic bool is_debuginfo;
124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
125441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* True if binary is assumed to be generated with GNU ld.  */
126441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic bool gnuld;
127441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
128441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Index of section header string table.  */
129441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic uint32_t shstrndx;
130441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
131441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Array to count references in section groups.  */
132441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic int *scnref;
133441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
134441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
135441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectint
136441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectmain (int argc, char *argv[])
137441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
138441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Set locale.  */
139441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  setlocale (LC_ALL, "");
140441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
141441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Initialize the message catalog.  */
142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  textdomain (PACKAGE_TARNAME);
143441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
144441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Parse and process arguments.  */
145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  int remaining;
146441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
147441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
148441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Before we start tell the ELF library which version we are using.  */
149441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  elf_version (EV_CURRENT);
150441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
151441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Now process all the files given at the command line.  */
152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool only_one = remaining + 1 == argc;
153441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  do
154441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
155441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* Open the file.  */
156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      int fd = open (argv[remaining], O_RDONLY);
157441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (fd == -1)
158441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
159441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  error (0, errno, gettext ("cannot open input file"));
160441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  continue;
161441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
162441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
163441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* Create an `Elf' descriptor.  */
164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
165441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (elf == NULL)
166441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("cannot generate Elf descriptor: %s\n"),
167441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       elf_errmsg (-1));
168441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
169441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
170441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  unsigned int prev_error_count = error_count;
171441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  struct stat64 st;
172441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
173441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (fstat64 (fd, &st) != 0)
174441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
175441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      printf ("cannot stat '%s': %m\n", argv[remaining]);
176441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      close (fd);
177441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      continue;
178441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
179441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
180441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  process_file (fd, elf, NULL, NULL, argv[remaining], st.st_size,
181441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			only_one);
182441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
183441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* Now we can close the descriptor.  */
184441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (elf_end (elf) != 0)
185441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("error while closing Elf descriptor: %s\n"),
186441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		   elf_errmsg (-1));
187441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
188441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (prev_error_count == error_count && !be_quiet)
189441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    puts (gettext ("No errors"));
190441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
191441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
192441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      close (fd);
193441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
194441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  while (++remaining < argc);
195441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
196441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return error_count != 0;
197441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
198441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
199441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
200441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Handle program arguments.  */
201441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic error_t
202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengparse_opt (int key, char *arg __attribute__ ((unused)),
203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   struct argp_state *state __attribute__ ((unused)))
204441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
205441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  switch (key)
206441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
207441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ARGP_strict:
208441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      be_strict = true;
209441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
210441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
211441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case 'q':
212441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      be_quiet = true;
213441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
214441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case 'd':
216cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      is_debuginfo = true;
217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
218441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ARGP_gnuld:
219441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      gnuld = true;
220441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
221441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
222cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case ARGP_KEY_NO_ARGS:
223cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      fputs (gettext ("Missing file name.\n"), stderr);
224cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      argp_help (&argp, stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 program_invocation_short_name);
226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      exit (1);
227cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
228441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    default:
229441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return ARGP_ERR_UNKNOWN;
230441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
231441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return 0;
232441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
233441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
234441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
235441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Print the version information.  */
236441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengprint_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
238441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  fprintf (stream, "elflint (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
240441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  fprintf (stream, gettext ("\
241441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source ProjectCopyright (C) %s Red Hat, Inc.\n\
242441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source ProjectThis is free software; see the source for copying conditions.  There is NO\n\
243441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng"), "2008");
245441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
246441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
247441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
248441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
249441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Process one file.  */
250441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
251441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectprocess_file (int fd, Elf *elf, const char *prefix, const char *suffix,
252441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      const char *fname, size_t size, bool only_one)
253441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
254441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* We can handle two types of files: ELF files and archives.  */
255441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf_Kind kind = elf_kind (elf);
256441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
257441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  switch (kind)
258441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
259441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_K_ELF:
260441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* Yes!  It's an ELF file.  */
261441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      process_elf_file (elf, prefix, suffix, fname, size, only_one);
262441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
263441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
264441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_K_AR:
265441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      {
266441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	Elf *subelf;
267441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	Elf_Cmd cmd = ELF_C_READ_MMAP;
268441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
269441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	size_t fname_len = strlen (fname) + 1;
270441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	char new_prefix[prefix_len + 1 + fname_len];
271441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	char new_suffix[(suffix == NULL ? 0 : strlen (suffix)) + 2];
272441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	char *cp = new_prefix;
273441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
274441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	/* Create the full name of the file.  */
275441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	if (prefix != NULL)
276441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  {
277441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    cp = mempcpy (cp, prefix, prefix_len);
278441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    *cp++ = '(';
279441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    strcpy (stpcpy (new_suffix, suffix), ")");
280441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  }
281441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	else
282441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  new_suffix[0] = '\0';
283441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	memcpy (cp, fname, fname_len);
284441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
285441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	/* It's an archive.  We process each file in it.  */
286441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
287441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  {
288441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    kind = elf_kind (subelf);
289441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
290441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    /* Call this function recursively.  */
291441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    if (kind == ELF_K_ELF || kind == ELF_K_AR)
292441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      {
293441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		Elf_Arhdr *arhdr = elf_getarhdr (subelf);
294441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		assert (arhdr != NULL);
295441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
296441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		process_file (fd, subelf, new_prefix, new_suffix,
297441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			      arhdr->ar_name, arhdr->ar_size, false);
298441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      }
299441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
300441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    /* Get next archive element.  */
301441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    cmd = elf_next (subelf);
302441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    if (elf_end (subelf) != 0)
303441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      ERROR (gettext (" error while freeing sub-ELF descriptor: %s\n"),
304441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		     elf_errmsg (-1));
305441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  }
306441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      }
307441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
308441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
309441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    default:
310441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* We cannot do anything.  */
311441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ERROR (gettext ("\
312cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengNot an ELF file - it has the wrong magic bytes at the start\n"));
313441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
314441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
315441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
316441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
317441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
318441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic const char *
319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection_name (Ebl *ebl, int idx)
320441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
321441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Shdr shdr_mem;
322441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Shdr *shdr;
323441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
324441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  shdr = gelf_getshdr (elf_getscn (ebl->elf, idx), &shdr_mem);
325441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
326441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
327441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
328441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
329441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
330441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic const int valid_e_machine[] =
331441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  {
332441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    EM_M32, EM_SPARC, EM_386, EM_68K, EM_88K, EM_860, EM_MIPS, EM_S370,
333441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    EM_MIPS_RS3_LE, EM_PARISC, EM_VPP500, EM_SPARC32PLUS, EM_960, EM_PPC,
334441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    EM_PPC64, EM_S390, EM_V800, EM_FR20, EM_RH32, EM_RCE, EM_ARM,
335441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    EM_FAKE_ALPHA, EM_SH, EM_SPARCV9, EM_TRICORE, EM_ARC, EM_H8_300,
336441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    EM_H8_300H, EM_H8S, EM_H8_500, EM_IA_64, EM_MIPS_X, EM_COLDFIRE,
337441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    EM_68HC12, EM_MMA, EM_PCP, EM_NCPU, EM_NDR1, EM_STARCORE, EM_ME16,
338441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    EM_ST100, EM_TINYJ, EM_X86_64, EM_PDSP, EM_FX66, EM_ST9PLUS, EM_ST7,
339441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    EM_68HC16, EM_68HC11, EM_68HC08, EM_68HC05, EM_SVX, EM_ST19, EM_VAX,
340441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    EM_CRIS, EM_JAVELIN, EM_FIREPATH, EM_ZSP, EM_MMIX, EM_HUANY, EM_PRISM,
341441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    EM_AVR, EM_FR30, EM_D10V, EM_D30V, EM_V850, EM_M32R, EM_MN10300,
342cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    EM_MN10200, EM_PJ, EM_OPENRISC, EM_ARC_A5, EM_XTENSA, EM_ALPHA
343441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  };
344441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#define nvalid_e_machine \
345441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  (sizeof (valid_e_machine) / sizeof (valid_e_machine[0]))
346441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
347441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
348441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Number of sections.  */
349441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic unsigned int shnum;
350441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
351441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
352441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
353441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectcheck_elf_header (Ebl *ebl, GElf_Ehdr *ehdr, size_t size)
354441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
355441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  char buf[512];
356441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  size_t cnt;
357441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
358441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check e_ident field.  */
359441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_ident[EI_MAG0] != ELFMAG0)
360441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR ("e_ident[%d] != '%c'\n", EI_MAG0, ELFMAG0);
361441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_ident[EI_MAG1] != ELFMAG1)
362441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR ("e_ident[%d] != '%c'\n", EI_MAG1, ELFMAG1);
363441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_ident[EI_MAG2] != ELFMAG2)
364441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR ("e_ident[%d] != '%c'\n", EI_MAG2, ELFMAG2);
365441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_ident[EI_MAG3] != ELFMAG3)
366441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR ("e_ident[%d] != '%c'\n", EI_MAG3, ELFMAG3);
367441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
368441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_ident[EI_CLASS] != ELFCLASS32
369441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      && ehdr->e_ident[EI_CLASS] != ELFCLASS64)
370441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("e_ident[%d] == %d is no known class\n"),
371441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   EI_CLASS, ehdr->e_ident[EI_CLASS]);
372441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
373441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB
374441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      && ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
375441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("e_ident[%d] == %d is no known data encoding\n"),
376441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   EI_DATA, ehdr->e_ident[EI_DATA]);
377441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
378441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_ident[EI_VERSION] != EV_CURRENT)
379441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("unknown ELF header version number e_ident[%d] == %d\n"),
380441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   EI_VERSION, ehdr->e_ident[EI_VERSION]);
381441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
382441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* We currently don't handle any OS ABIs.  */
383441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE)
384cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("unsupported OS ABI e_ident[%d] == '%s'\n"),
385441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   EI_OSABI,
386441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   ebl_osabi_name (ebl, ehdr->e_ident[EI_OSABI], buf, sizeof (buf)));
387441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
388441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* No ABI versions other than zero supported either.  */
389441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_ident[EI_ABIVERSION] != 0)
390441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("unsupport ABI version e_ident[%d] == %d\n"),
391441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   EI_ABIVERSION, ehdr->e_ident[EI_ABIVERSION]);
392441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
393441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  for (cnt = EI_PAD; cnt < EI_NIDENT; ++cnt)
394441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    if (ehdr->e_ident[cnt] != 0)
395441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ERROR (gettext ("e_ident[%zu] is not zero\n"), cnt);
396441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
397441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check the e_type field.  */
398441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_type != ET_REL && ehdr->e_type != ET_EXEC
399441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      && ehdr->e_type != ET_DYN && ehdr->e_type != ET_CORE)
400441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("unknown object file type %d\n"), ehdr->e_type);
401441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
402441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check the e_machine field.  */
403441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  for (cnt = 0; cnt < nvalid_e_machine; ++cnt)
404441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    if (valid_e_machine[cnt] == ehdr->e_machine)
405441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
406441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (cnt == nvalid_e_machine)
407441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("unknown machine type %d\n"), ehdr->e_machine);
408441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
409441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check the e_version field.  */
410441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_version != EV_CURRENT)
411441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("unknown object file version\n"));
412441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
413441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check the e_phoff and e_phnum fields.  */
414441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_phoff == 0)
415441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
416441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_phnum != 0)
417441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid program header offset\n"));
418441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN)
419441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
420441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectexecutables and DSOs cannot have zero program header offset\n"));
421441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
422441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  else if (ehdr->e_phnum == 0)
423441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("invalid number of program header entries\n"));
424441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
425441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check the e_shoff field.  */
426441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  shnum = ehdr->e_shnum;
427441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  shstrndx = ehdr->e_shstrndx;
428441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_shoff == 0)
429441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
430441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_shnum != 0)
431441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid section header table offset\n"));
432441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN
433441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       && ehdr->e_type != ET_CORE)
434441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("section header table must be present\n"));
435441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
436441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  else
437441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
438441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_shnum == 0)
439441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
440441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* Get the header of the zeroth section.  The sh_size field
441441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	     might contain the section number.  */
442441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  GElf_Shdr shdr_mem;
443cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
444441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (shdr != NULL)
445441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
446441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      /* The error will be reported later.  */
447441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      if (shdr->sh_size == 0)
448441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		ERROR (gettext ("\
449441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectinvalid number of section header table entries\n"));
450441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      else
451441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		shnum = shdr->sh_size;
452441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
453441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
454441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
455441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_shstrndx == SHN_XINDEX)
456441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
457441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* Get the header of the zeroth section.  The sh_size field
458441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	     might contain the section number.  */
459441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  GElf_Shdr shdr_mem;
460cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
461cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (shdr != NULL && shdr->sh_link < shnum)
462cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    shstrndx = shdr->sh_link;
463441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
464441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (shstrndx >= shnum)
465441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid section header index\n"));
466441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
467441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
468441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check the e_flags field.  */
469441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (!ebl_machine_flag_check (ebl, ehdr->e_flags))
470441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("invalid machine flags: %s\n"),
471441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   ebl_machine_flag_name (ebl, ehdr->e_flags, buf, sizeof (buf)));
472441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
473441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check e_ehsize, e_phentsize, and e_shentsize fields.  */
474441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (gelf_getclass (ebl->elf) == ELFCLASS32)
475441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
476441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_ehsize != 0 && ehdr->e_ehsize != sizeof (Elf32_Ehdr))
477441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid ELF header size: %hd\n"), ehdr->e_ehsize);
478441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
479441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf32_Phdr))
480441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid program header size: %hd\n"),
481441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       ehdr->e_phentsize);
482441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > size)
483441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid program header position or size\n"));
484441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
485441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf32_Shdr))
486441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid section header size: %hd\n"),
487441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       ehdr->e_shentsize);
488441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size)
489441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid section header position or size\n"));
490441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
491441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  else if (gelf_getclass (ebl->elf) == ELFCLASS64)
492441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
493441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_ehsize != 0 && ehdr->e_ehsize != sizeof (Elf64_Ehdr))
494441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid ELF header size: %hd\n"), ehdr->e_ehsize);
495441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
496441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_phentsize != 0 && ehdr->e_phentsize != sizeof (Elf64_Phdr))
497441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid program header size: %hd\n"),
498441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       ehdr->e_phentsize);
499441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (ehdr->e_phoff + ehdr->e_phnum * ehdr->e_phentsize > size)
500441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid program header position or size\n"));
501441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
502441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf64_Shdr))
503441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid section header size: %hd\n"),
504441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       ehdr->e_shentsize);
505441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size)
506441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("invalid section header position or size\n"));
507441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
508441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
509441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
510441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
511441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Check that there is a section group section with index < IDX which
512441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project   contains section IDX and that there is exactly one.  */
513441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
514cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_scn_group (Ebl *ebl, int idx)
515441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
516441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (scnref[idx] == 0)
517441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
518441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* No reference so far.  Search following sections, maybe the
519441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	 order is wrong.  */
520441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      size_t cnt;
521441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
522441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      for (cnt = idx + 1; cnt < shnum; ++cnt)
523441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
524cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf_Scn *scn = elf_getscn (ebl->elf, cnt);
525441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  GElf_Shdr shdr_mem;
526cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
527441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (shdr == NULL)
528441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    /* We cannot get the section header so we cannot check it.
529441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       The error to get the section header will be shown
530441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       somewhere else.  */
531441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    continue;
532441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
533441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (shdr->sh_type != SHT_GROUP)
534441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    continue;
535441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
536cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf_Data *data = elf_getdata (scn, NULL);
537441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (data == NULL || data->d_size < sizeof (Elf32_Word))
538441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    /* Cannot check the section.  */
539441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    continue;
540441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
541cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf32_Word *grpdata = (Elf32_Word *) data->d_buf;
542cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t inner = 1; inner < data->d_size / sizeof (Elf32_Word);
543cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       ++inner)
544441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    if (grpdata[inner] == (Elf32_Word) idx)
545441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      goto out;
546441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
547441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
548441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    out:
549441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (cnt == shnum)
550441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
551441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': section with SHF_GROUP flag set not part of a section group\n"),
552cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
553441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
554441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
555441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': section group [%2zu] '%s' does not preceed group member\n"),
556cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx),
557cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       cnt, section_name (ebl, cnt));
558441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
559441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
560441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
561441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
562441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
563cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_symtab (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
564441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
565441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  bool no_xndx_warned = false;
566441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  int no_pt_tls = 0;
567cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
568441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (data == NULL)
569441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
570441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
571cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
572441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return;
573441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
574441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
575cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr strshdr_mem;
576cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
577cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     &strshdr_mem);
578cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (strshdr == NULL)
579cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
580cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
581441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (strshdr->sh_type != SHT_STRTAB)
582cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
583cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"),
584cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     shdr->sh_link, section_name (ebl, shdr->sh_link),
585cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
586cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      strshdr = NULL;
587cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
588441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
589441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Search for an extended section index table section.  */
590441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf_Data *xndxdata = NULL;
591441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf32_Word xndxscnidx = 0;
592cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool found_xndx = false;
593cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t cnt = 1; cnt < shnum; ++cnt)
594441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    if (cnt != (size_t) idx)
595441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      {
596441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	Elf_Scn *xndxscn = elf_getscn (ebl->elf, cnt);
597cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr xndxshdr_mem;
598cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
599cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (xndxshdr == NULL)
600441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  continue;
601441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
602441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX
603441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    && xndxshdr->sh_link == (GElf_Word) idx)
604cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
605cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (found_xndx)
606cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
607cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': symbol table cannot have more than one extended index section\n"),
608cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     idx, section_name (ebl, idx));
609cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
610cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    xndxdata = elf_getdata (xndxscn, NULL);
611cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    xndxscnidx = elf_ndxscn (xndxscn);
612cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    found_xndx = true;
613cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
614441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      }
615441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
616441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT))
617441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("\
618cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2u] '%s': entry size is does not match ElfXX_Sym\n"),
619cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
620441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
621441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Test the zeroth entry.  */
622441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Sym sym_mem;
623441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf32_Word xndx;
624441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, 0, &sym_mem, &xndx);
625441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (sym == NULL)
626441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ERROR (gettext ("section [%2d] '%s': cannot get symbol %d: %s\n"),
627cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx), 0, elf_errmsg (-1));
628441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  else
629441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
630441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (sym->st_name != 0)
631441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
632cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "st_name");
633441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (sym->st_value != 0)
634441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
635cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "st_value");
636441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (sym->st_size != 0)
637441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
638cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "st_size");
639441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (sym->st_info != 0)
640441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
641cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "st_info");
642441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (sym->st_other != 0)
643441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
644cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "st_other");
645441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (sym->st_shndx != 0)
646441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("section [%2d] '%s': '%s' in zeroth entry not zero\n"),
647cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "st_shndx");
648441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (xndxdata != NULL && xndx != 0)
649441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
650441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': XINDEX for zeroth entry not zero\n"),
651cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       xndxscnidx, section_name (ebl, xndxscnidx));
652441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
653441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
654cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t cnt = 1; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
655441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
656441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem, &xndx);
657441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (sym == NULL)
658441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
659441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  ERROR (gettext ("section [%2d] '%s': cannot get symbol %zu: %s\n"),
660cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx), cnt, elf_errmsg (-1));
661441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  continue;
662441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
663441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
664441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      const char *name = NULL;
665cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (strshdr == NULL)
666cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	name = "";
667cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (sym->st_name >= strshdr->sh_size)
668441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
669441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: invalid name value\n"),
670cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
671441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
672441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
673441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  name = elf_strptr (ebl->elf, shdr->sh_link, sym->st_name);
674441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  assert (name != NULL);
675441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
676441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
677441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (sym->st_shndx == SHN_XINDEX)
678441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
679441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (xndxdata == NULL)
680441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
681441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      ERROR (gettext ("\
682441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: too large section index but no extended section index section\n"),
683cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     idx, section_name (ebl, idx), cnt);
684441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      no_xndx_warned = true;
685441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
686441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  else if (xndx < SHN_LORESERVE)
687441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
688441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: XINDEX used for index which would fit in st_shndx (%" PRIu32 ")\n"),
689cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   xndxscnidx, section_name (ebl, xndxscnidx), cnt,
690441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		   xndx);
691441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
692441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if ((sym->st_shndx >= SHN_LORESERVE
693441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		// && sym->st_shndx <= SHN_HIRESERVE    always true
694441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		&& sym->st_shndx != SHN_ABS
695441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		&& sym->st_shndx != SHN_COMMON)
696441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       || (sym->st_shndx >= shnum
697441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		   && (sym->st_shndx < SHN_LORESERVE
698441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       /* || sym->st_shndx > SHN_HIRESERVE  always false */)))
699441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
700441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: invalid section index\n"),
701cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
702441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
703441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	xndx = sym->st_shndx;
704441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
705cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (GELF_ST_TYPE (sym->st_info) >= STT_NUM
706cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && !ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info), NULL, 0))
707441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("section [%2d] '%s': symbol %zu: unknown type\n"),
708cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
709441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
710441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (GELF_ST_BIND (sym->st_info) >= STB_NUM)
711441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
712441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: unknown symbol binding\n"),
713cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
714441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
715441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (xndx == SHN_COMMON)
716441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
717441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* Common symbols can only appear in relocatable files.  */
718441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (ehdr->e_type != ET_REL)
719441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
720441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: COMMON only allowed in relocatable files\n"),
721cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), cnt);
722441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (cnt < shdr->sh_info)
723441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
724441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: local COMMON symbols are nonsense\n"),
725cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), cnt);
726441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (GELF_R_TYPE (sym->st_info) == STT_FUNC)
727441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
728441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"),
729cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), cnt);
730441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
731441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (xndx > 0 && xndx < shnum)
732441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
733441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  GElf_Shdr destshdr_mem;
734441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  GElf_Shdr *destshdr;
735441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
736441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  destshdr = gelf_getshdr (elf_getscn (ebl->elf, xndx), &destshdr_mem);
737441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (destshdr != NULL)
738441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
739cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Addr sh_addr = (ehdr->e_type == ET_REL ? 0
740cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   : destshdr->sh_addr);
741441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      if (GELF_ST_TYPE (sym->st_info) != STT_TLS)
742441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		{
743cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (! ebl_check_special_symbol (ebl, ehdr, sym, name,
744cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						  destshdr))
745cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
746cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      if (sym->st_value - sh_addr > destshdr->sh_size)
747cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			{
748cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  /* GNU ld has severe bugs.  When it decides to remove
749cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     empty sections it leaves symbols referencing them
750cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     behind.  These are symbols in .symtab.  */
751cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  if (!gnuld
752cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      || strcmp (section_name (ebl, idx), ".symtab")
753cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      || (strcmp (name, "__preinit_array_start") != 0
754cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  && strcmp (name, "__preinit_array_end") != 0
755cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  && strcmp (name, "__init_array_start") != 0
756cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  && strcmp (name, "__init_array_end") != 0
757cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  && strcmp (name, "__fini_array_start") != 0
758cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  && strcmp (name, "__fini_array_end") != 0))
759cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    ERROR (gettext ("\
760441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: st_value out of bounds\n"),
761cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   idx, section_name (ebl, idx), cnt);
762cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			}
763cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      else if ((sym->st_value - sh_addr
764cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				+ sym->st_size) > destshdr->sh_size)
765cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			ERROR (gettext ("\
766441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"),
767cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       idx, section_name (ebl, idx), cnt,
768cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       (int) xndx, section_name (ebl, xndx));
769cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
770441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		}
771441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      else
772441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		{
773441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  if ((destshdr->sh_flags & SHF_TLS) == 0)
774441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    ERROR (gettext ("\
775441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: referenced section [%2d] '%s' does not have SHF_TLS flag set\n"),
776cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   idx, section_name (ebl, idx), cnt,
777cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   (int) xndx, section_name (ebl, xndx));
778441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
779441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  if (ehdr->e_type == ET_REL)
780441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    {
781441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      /* For object files the symbol value must fall
782441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project                         into the section.  */
783441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      if (sym->st_value > destshdr->sh_size)
784441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			ERROR (gettext ("\
785441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"),
786cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       idx, section_name (ebl, idx), cnt,
787cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       (int) xndx, section_name (ebl, xndx));
788441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      else if (sym->st_value + sym->st_size
789441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			       > destshdr->sh_size)
790441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			ERROR (gettext ("\
791441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"),
792cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       idx, section_name (ebl, idx), cnt,
793cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       (int) xndx, section_name (ebl, xndx));
794441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    }
795441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  else
796441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    {
797441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      GElf_Phdr phdr_mem;
798441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      GElf_Phdr *phdr = NULL;
799441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      int pcnt;
800441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
801441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      for (pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt)
802441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			{
803441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			  phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem);
804441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			  if (phdr != NULL && phdr->p_type == PT_TLS)
805441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			    break;
806441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			}
807441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
808441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      if (pcnt == ehdr->e_phnum)
809441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			{
810441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			  if (no_pt_tls++ == 0)
811441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			    ERROR (gettext ("\
812441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: TLS symbol but no TLS program header entry\n"),
813cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   idx, section_name (ebl, idx), cnt);
814441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			}
815441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      else
816441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			{
817441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			  if (sym->st_value
818441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			      < destshdr->sh_offset - phdr->p_offset)
819441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			    ERROR (gettext ("\
820441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: st_value short of referenced section [%2d] '%s'\n"),
821cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   idx, section_name (ebl, idx), cnt,
822cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   (int) xndx, section_name (ebl, xndx));
823441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			  else if (sym->st_value
824441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project				   > (destshdr->sh_offset - phdr->p_offset
825441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project				      + destshdr->sh_size))
826441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			    ERROR (gettext ("\
827441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: st_value out of bounds of referenced section [%2d] '%s'\n"),
828cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   idx, section_name (ebl, idx), cnt,
829cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   (int) xndx, section_name (ebl, xndx));
830441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			  else if (sym->st_value + sym->st_size
831441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project				   > (destshdr->sh_offset - phdr->p_offset
832441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project				      + destshdr->sh_size))
833441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			    ERROR (gettext ("\
834441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"),
835cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   idx, section_name (ebl, idx), cnt,
836cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   (int) xndx, section_name (ebl, xndx));
837441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			}
838441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    }
839441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		}
840441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
841441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
842441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
843441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (GELF_ST_BIND (sym->st_info) == STB_LOCAL)
844441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
845441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (cnt >= shdr->sh_info)
846441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
847441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: local symbol outside range described in sh_info\n"),
848cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), cnt);
849441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
850441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
851441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
852441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (cnt < shdr->sh_info)
853441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
854441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: non-local symbol outside range described in sh_info\n"),
855cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), cnt);
856441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
857441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
858441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (GELF_ST_TYPE (sym->st_info) == STT_SECTION
859441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && GELF_ST_BIND (sym->st_info) != STB_LOCAL)
860441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
861441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': symbol %zu: non-local section symbol\n"),
862cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
863441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
864441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (name != NULL)
865441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
866441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
867441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
868cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* Check that address and size match the global offset table.  */
869cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
870cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Shdr destshdr_mem;
871cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf, xndx),
872cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						  &destshdr_mem);
873cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
874cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (destshdr == NULL && xndx == SHN_ABS)
875cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
876cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  /* In a DSO, we have to find the GOT section by name.  */
877cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  Elf_Scn *gotscn = NULL;
878cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  Elf_Scn *gscn = NULL;
879cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  while ((gscn = elf_nextscn (ebl->elf, gscn)) != NULL)
880cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
881cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      destshdr = gelf_getshdr (gscn, &destshdr_mem);
882cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      assert (destshdr != NULL);
883cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      const char *sname = elf_strptr (ebl->elf,
884cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						      ehdr->e_shstrndx,
885cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						      destshdr->sh_name);
886cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      if (sname != NULL)
887cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			{
888cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  if (strcmp (sname, ".got.plt") == 0)
889cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    break;
890cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  if (strcmp (sname, ".got") == 0)
891cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    /* Do not stop looking.
892cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       There might be a .got.plt section.  */
893cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    gotscn = gscn;
894cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			}
895cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
896cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      destshdr = NULL;
897cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
898441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
899cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (destshdr == NULL && gotscn != NULL)
900cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    destshdr = gelf_getshdr (gotscn, &destshdr_mem);
901cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
902cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
903cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      const char *sname = ((destshdr == NULL || xndx == SHN_UNDEF)
904cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   ? NULL
905cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   : elf_strptr (ebl->elf, ehdr->e_shstrndx,
906cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						 destshdr->sh_name));
907cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (sname == NULL)
908441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		{
909cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (xndx != SHN_UNDEF || ehdr->e_type != ET_REL)
910cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    ERROR (gettext ("\
911cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to \
912cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengbad section [%2d]\n"),
913cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   idx, section_name (ebl, idx), xndx);
914cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
915cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      else if (strcmp (sname, ".got.plt") != 0
916cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       && strcmp (sname, ".got") != 0)
917cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ERROR (gettext ("\
918cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to \
919cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s'\n"),
920cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       idx, section_name (ebl, idx), xndx, sname);
921441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
922cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (destshdr != NULL)
923cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
924cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  /* Found it.  */
925cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (!ebl_check_special_symbol (ebl, ehdr, sym, name,
926cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						 destshdr))
927441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    {
928cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      if (ehdr->e_type != ET_REL
929cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  && sym->st_value != destshdr->sh_addr)
930cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			/* This test is more strict than the psABIs which
931cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   usually allow the symbol to be in the middle of
932cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   the .got section, allowing negative offsets.  */
933441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			ERROR (gettext ("\
934cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol value %#" PRIx64 " does not match %s section address %#" PRIx64 "\n"),
935cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       idx, section_name (ebl, idx),
936441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			       (uint64_t) sym->st_value,
937cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       sname, (uint64_t) destshdr->sh_addr);
938441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
939cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      if (!gnuld && sym->st_size != destshdr->sh_size)
940441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			ERROR (gettext ("\
941cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol size %" PRIu64 " does not match %s section size %" PRIu64 "\n"),
942cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       idx, section_name (ebl, idx),
943441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			       (uint64_t) sym->st_size,
944cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       sname, (uint64_t) destshdr->sh_size);
945441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    }
946441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		}
947cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      else
948441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		ERROR (gettext ("\
949441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol present, but no .got section\n"),
950cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       idx, section_name (ebl, idx));
951441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
952441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  else if (strcmp (name, "_DYNAMIC") == 0)
953cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    /* Check that address and size match the dynamic section.
954cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       We locate the dynamic section via the program header
955cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       entry.  */
956cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    for (int pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt)
957cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      {
958cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Phdr phdr_mem;
959cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Phdr *phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem);
960441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
961cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
962cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  {
963cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    if (sym->st_value != phdr->p_vaddr)
964cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      ERROR (gettext ("\
965441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': _DYNAMIC_ symbol value %#" PRIx64 " does not match dynamic segment address %#" PRIx64 "\n"),
966cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     idx, section_name (ebl, idx),
967cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     (uint64_t) sym->st_value,
968cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     (uint64_t) phdr->p_vaddr);
969441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
970cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    if (!gnuld && sym->st_size != phdr->p_memsz)
971cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      ERROR (gettext ("\
972441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': _DYNAMIC symbol size %" PRIu64 " does not match dynamic segment size %" PRIu64 "\n"),
973cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     idx, section_name (ebl, idx),
974cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     (uint64_t) sym->st_size,
975cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     (uint64_t) phdr->p_memsz);
976441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
977cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    break;
978cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  }
979441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
980441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
981441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
982441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
983441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
984441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
985441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic bool
986cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengis_rel_dyn (Ebl *ebl, const GElf_Ehdr *ehdr, int idx, const GElf_Shdr *shdr,
987cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    bool is_rela)
988441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
989441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* If this is no executable or DSO it cannot be a .rel.dyn section.  */
990441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
991441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    return false;
992441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
993441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check the section name.  Unfortunately necessary.  */
994cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (strcmp (section_name (ebl, idx), is_rela ? ".rela.dyn" : ".rel.dyn"))
995441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    return false;
996441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
997441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* When a .rel.dyn section is used a DT_RELCOUNT dynamic section
998441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     entry can be present as well.  */
999441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf_Scn *scn = NULL;
1000441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
1001441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1002441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      GElf_Shdr rcshdr_mem;
1003441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      const GElf_Shdr *rcshdr = gelf_getshdr (scn, &rcshdr_mem);
1004441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      assert (rcshdr != NULL);
1005441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1006441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (rcshdr->sh_type == SHT_DYNAMIC)
1007441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1008441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* Found the dynamic section.  Look through it.  */
1009441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  Elf_Data *d = elf_getdata (scn, NULL);
1010cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  size_t cnt;
1011441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1012441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  for (cnt = 1; cnt < rcshdr->sh_size / rcshdr->sh_entsize; ++cnt)
1013441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
1014441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      GElf_Dyn dyn_mem;
1015441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      GElf_Dyn *dyn = gelf_getdyn (d, cnt, &dyn_mem);
1016441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      assert (dyn != NULL);
1017441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1018441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      if (dyn->d_tag == DT_RELCOUNT)
1019441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		{
1020cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  /* Found it.  Does the type match.  */
1021cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (is_rela)
1022cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    ERROR (gettext ("\
1023cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': DT_RELCOUNT used for this RELA section\n"),
1024cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   idx, section_name (ebl, idx));
1025cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  else
1026cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
1027cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      /* Does the number specified number of relative
1028cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 relocations exceed the total number of
1029cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 relocations?  */
1030cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      if (dyn->d_un.d_val > shdr->sh_size / shdr->sh_entsize)
1031cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			ERROR (gettext ("\
1032cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"),
1033cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       idx, section_name (ebl, idx),
1034cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       (int) dyn->d_un.d_val);
1035cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1036cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      /* Make sure the specified number of relocations are
1037cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 relative.  */
1038cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf,
1039cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng								   idx), NULL);
1040cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      if (reldata != NULL)
1041cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			for (size_t inner = 0;
1042cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     inner < shdr->sh_size / shdr->sh_entsize;
1043cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     ++inner)
1044cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  {
1045cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    GElf_Rel rel_mem;
1046cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    GElf_Rel *rel = gelf_getrel (reldata, inner,
1047cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng							 &rel_mem);
1048cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    if (rel == NULL)
1049cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      /* The problem will be reported elsewhere.  */
1050cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      break;
1051cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1052cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    if (ebl_relative_reloc_p (ebl,
1053cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						      GELF_R_TYPE (rel->r_info)))
1054cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      {
1055cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				if (inner >= dyn->d_un.d_val)
1056cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  ERROR (gettext ("\
1057cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': relative relocations after index %d as specified by DT_RELCOUNT\n"),
1058cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 idx, section_name (ebl, idx),
1059cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 (int) dyn->d_un.d_val);
1060cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      }
1061cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    else if (inner < dyn->d_un.d_val)
1062cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      ERROR (gettext ("\
1063cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': non-relative relocation at index %zu; DT_RELCOUNT specified %d relative relocations\n"),
1064cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     idx, section_name (ebl, idx),
1065cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     inner, (int) dyn->d_un.d_val);
1066cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  }
1067cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
1068cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
1069cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1070cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (dyn->d_tag == DT_RELACOUNT)
1071cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
1072cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  /* Found it.  Does the type match.  */
1073cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (!is_rela)
1074441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    ERROR (gettext ("\
1075cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': DT_RELACOUNT used for this REL section\n"),
1076cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   idx, section_name (ebl, idx));
1077cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  else
1078cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
1079cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      /* Does the number specified number of relative
1080cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 relocations exceed the total number of
1081cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 relocations?  */
1082cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      if (dyn->d_un.d_val > shdr->sh_size / shdr->sh_entsize)
1083cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			ERROR (gettext ("\
1084441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': DT_RELCOUNT value %d too high for this section\n"),
1085cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       idx, section_name (ebl, idx),
1086cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       (int) dyn->d_un.d_val);
1087cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1088cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      /* Make sure the specified number of relocations are
1089cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 relative.  */
1090cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      Elf_Data *reldata = elf_getdata (elf_getscn (ebl->elf,
1091cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng								   idx), NULL);
1092cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      if (reldata != NULL)
1093cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			for (size_t inner = 0;
1094cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     inner < shdr->sh_size / shdr->sh_entsize;
1095cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     ++inner)
1096cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  {
1097cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    GElf_Rela rela_mem;
1098cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    GElf_Rela *rela = gelf_getrela (reldata, inner,
1099cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng							    &rela_mem);
1100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    if (rela == NULL)
1101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      /* The problem will be reported elsewhere.  */
1102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      break;
1103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    if (ebl_relative_reloc_p (ebl,
1105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						      GELF_R_TYPE (rela->r_info)))
1106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      {
1107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				if (inner >= dyn->d_un.d_val)
1108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  ERROR (gettext ("\
1109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': relative relocations after index %d as specified by DT_RELCOUNT\n"),
1110cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 idx, section_name (ebl, idx),
1111cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 (int) dyn->d_un.d_val);
1112cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      }
1113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    else if (inner < dyn->d_un.d_val)
1114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      ERROR (gettext ("\
1115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': non-relative relocation at index %zu; DT_RELCOUNT specified %d relative relocations\n"),
1116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     idx, section_name (ebl, idx),
1117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     inner, (int) dyn->d_un.d_val);
1118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  }
1119cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
1120441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		}
1121441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
1122441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1123441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
1124441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1125441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1126441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1127441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return true;
1128441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
1129441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1130441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstruct loaded_segment
1132441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
1133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr from;
1134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr to;
1135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool read_only;
1136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct loaded_segment *next;
1137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng};
1138441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Check whether binary has text relocation flag set.  */
1141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic bool textrel;
1142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1143cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Keep track of whether text relocation flag is needed.  */
1144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic bool needed_textrel;
1145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic bool
1148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_reloc_shdr (Ebl *ebl, const GElf_Ehdr *ehdr, const GElf_Shdr *shdr,
1149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  int idx, int reltype, GElf_Shdr **destshdrp,
1150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  GElf_Shdr *destshdr_memp, struct loaded_segment **loadedp)
1151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
1152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool reldyn = false;
1153441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1154441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check whether the link to the section we relocate is reasonable.  */
1155441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (shdr->sh_info >= shnum)
1156441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("section [%2d] '%s': invalid destination section index\n"),
1157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
1158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else if (shdr->sh_info != 0)
1159441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      *destshdrp = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_info),
1161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				 destshdr_memp);
1162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (*destshdrp != NULL)
1163441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if((*destshdrp)->sh_type != SHT_PROGBITS
1165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     && (*destshdrp)->sh_type != SHT_NOBITS)
1166441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
1167441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      reldyn = is_rel_dyn (ebl, ehdr, idx, shdr, true);
1168441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      if (!reldyn)
1169441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		ERROR (gettext ("\
1170441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': invalid destination section type\n"),
1171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       idx, section_name (ebl, idx));
1172441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      else
1173441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		{
1174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  /* There is no standard, but we require that .rel{,a}.dyn
1175441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		     sections have a sh_info value of zero.  */
1176441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  if (shdr->sh_info != 0)
1177441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    ERROR (gettext ("\
1178441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': sh_info should be zero\n"),
1179cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   idx, section_name (ebl, idx));
1180441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		}
1181441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
1182441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (((*destshdrp)->sh_flags & (SHF_MERGE | SHF_STRINGS)) != 0)
1184441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
1185441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': no relocations for merge-able sections possible\n"),
1186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx));
1187441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1188441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1189441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr->sh_entsize != gelf_fsize (ebl->elf, reltype, 1, EV_CURRENT))
1191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext (reltype == ELF_T_RELA ? "\
1192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': section entry size does not match ElfXX_Rela\n" : "\
1193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': section entry size does not match ElfXX_Rel\n"),
1194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
1195cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1196cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* In preparation of checking whether relocations are text
1197cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     relocations or not we need to determine whether the file is
1198cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     flagged to have text relocation and we need to determine a) what
1199cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     the loaded segments are and b) which are read-only.  This will
1200cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     also allow us to determine whether the same reloc section is
1201cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     modifying loaded and not loaded segments.  */
1202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (int i = 0; i < ehdr->e_phnum; ++i)
1203441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Phdr phdr_mem;
1205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Phdr *phdr = gelf_getphdr (ebl->elf, i, &phdr_mem);
1206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (phdr == NULL)
1207cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	continue;
1208441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1209cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (phdr->p_type == PT_LOAD)
1210441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1211cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  struct loaded_segment *newp = xmalloc (sizeof (*newp));
1212cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  newp->from = phdr->p_vaddr;
1213cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  newp->to = phdr->p_vaddr + phdr->p_memsz;
1214cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  newp->read_only = (phdr->p_flags & PF_W) == 0;
1215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  newp->next = *loadedp;
1216cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  *loadedp = newp;
1217441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1218cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (phdr->p_type == PT_DYNAMIC)
1219441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1220cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf_Scn *dynscn = gelf_offscn (ebl->elf, phdr->p_offset);
1221cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Shdr dynshdr_mem;
1222cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Shdr *dynshdr = gelf_getshdr (dynscn, &dynshdr_mem);
1223cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf_Data *dyndata = elf_getdata (dynscn, NULL);
1224cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (dynshdr != NULL && dynshdr->sh_type == SHT_DYNAMIC
1225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && dyndata != NULL)
1226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    for (size_t j = 0; j < dynshdr->sh_size / dynshdr->sh_entsize; ++j)
1227cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      {
1228cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Dyn dyn_mem;
1229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Dyn *dyn = gelf_getdyn (dyndata, j, &dyn_mem);
1230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		if (dyn != NULL
1231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    && (dyn->d_tag == DT_TEXTREL
1232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			|| (dyn->d_tag == DT_FLAGS
1233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    && (dyn->d_un.d_val & DF_TEXTREL) != 0)))
1234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  {
1235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    textrel = true;
1236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    break;
1237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  }
1238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      }
1239441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1241441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1242cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* A quick test which can be easily done here (although it is a bit
1243cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     out of place): the text relocation flag makes only sense if there
1244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     is a segment which is not writable.  */
1245cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (textrel)
1246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      struct loaded_segment *seg = *loadedp;
1248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      while (seg != NULL && !seg->read_only)
1249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	seg = seg->next;
1250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (seg == NULL)
1251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
1252cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengtext relocation flag set but there is no read-only segment\n"));
1253441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return reldyn;
1256441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
1257441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1258441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1259cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengenum load_state
1260cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
1261cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    state_undecided,
1262cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    state_loaded,
1263cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    state_unloaded,
1264cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    state_error
1265cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  };
1266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1268441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
1269cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_one_reloc (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *relshdr, int idx,
1270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 size_t cnt, const GElf_Shdr *symshdr, Elf_Data *symdata,
1271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 GElf_Addr r_offset, GElf_Xword r_info,
1272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 const GElf_Shdr *destshdr, bool reldyn,
1273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 struct loaded_segment *loaded, enum load_state *statep)
1274441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
1275441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  bool known_broken = gnuld;
1276441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1277cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (!ebl_reloc_type_check (ebl, GELF_R_TYPE (r_info)))
1278cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("section [%2d] '%s': relocation %zu: invalid type\n"),
1279cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), cnt);
1280cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else if (((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
1281cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    /* The executable/DSO can contain relocation sections with
1282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       all the relocations the linker has applied.  Those sections
1283cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       are marked non-loaded, though.  */
1284cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    || (relshdr->sh_flags & SHF_ALLOC) != 0)
1285cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   && !ebl_reloc_valid_use (ebl, GELF_R_TYPE (r_info)))
1286cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
1287cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': relocation %zu: relocation type invalid for the file type\n"),
1288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), cnt);
1289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1290cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (symshdr != NULL
1291cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      && ((GELF_R_SYM (r_info) + 1)
1292cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  * gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT)
1293cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  > symshdr->sh_size))
1294cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
1295cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': relocation %zu: invalid symbol index\n"),
1296cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), cnt);
1297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* No more tests if this is a no-op relocation.  */
1299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (ebl_none_reloc_p (ebl, GELF_R_TYPE (r_info)))
1300441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    return;
1301cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1302cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (ebl_gotpc_reloc_check (ebl, GELF_R_TYPE (r_info)))
1303441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1304cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *name;
1305cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      char buf[64];
1306cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym sym_mem;
1307cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (r_info), &sym_mem);
1308cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sym != NULL
1309cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Get the name for the symbol.  */
1310cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && (name = elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name))
1311cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && strcmp (name, "_GLOBAL_OFFSET_TABLE_") !=0 )
1312cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
1313cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': relocation %zu: only symbol '_GLOBAL_OFFSET_TABLE_' can be used with %s\n"),
1314cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt,
1315cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       ebl_reloc_type_name (ebl, GELF_R_SYM (r_info),
1316cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				    buf, sizeof (buf)));
1317441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1318441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (reldyn)
1320cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1321cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      // XXX TODO Check .rel.dyn section addresses.
1322cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1323cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else if (!known_broken)
1324cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1325cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (destshdr != NULL
1326cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && GELF_R_TYPE (r_info) != 0
1327cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && (r_offset - (ehdr->e_type == ET_REL ? 0
1328cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  : destshdr->sh_addr)) >= destshdr->sh_size)
1329cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
1330cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': relocation %zu: offset out of bounds\n"),
1331cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
1332cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1333cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1334cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Sym sym_mem;
1335cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Sym *sym = gelf_getsym (symdata, GELF_R_SYM (r_info), &sym_mem);
1336cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1337cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (ebl_copy_reloc_p (ebl, GELF_R_TYPE (r_info))
1338cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Make sure the referenced symbol is an object or unspecified.  */
1339cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      && sym != NULL
1340cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      && GELF_ST_TYPE (sym->st_info) != STT_NOTYPE
1341cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      && GELF_ST_TYPE (sym->st_info) != STT_OBJECT)
1342cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1343cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      char buf[64];
1344cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': relocation %zu: copy relocation against symbol of type %s\n"),
1345cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx), cnt,
1346cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     ebl_symbol_type_name (ebl, GELF_ST_TYPE (sym->st_info),
1347cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   buf, sizeof (buf)));
1348cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1349cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1350cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if ((ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
1351cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      || (relshdr->sh_flags & SHF_ALLOC) != 0)
1352441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1353cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      bool in_loaded_seg = false;
1354cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      while (loaded != NULL)
1355441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1356cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (r_offset < loaded->to
1357cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && r_offset + (sym == NULL ? 0 : sym->st_size) >= loaded->from)
1358441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
1359cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* The symbol is in this segment.  */
1360cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if  (loaded->read_only)
1361441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		{
1362cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (textrel)
1363cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    needed_textrel = true;
1364cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  else
1365cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    ERROR (gettext ("section [%2d] '%s': relocation %zu: read-only section modified but text relocation flag not set\n"),
1366cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   idx, section_name (ebl, idx), cnt);
1367441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		}
1368cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1369cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      in_loaded_seg = true;
1370441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
1371441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1372cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  loaded = loaded->next;
1373cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1374cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1375cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (*statep == state_undecided)
1376cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	*statep = in_loaded_seg ? state_loaded : state_unloaded;
1377cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if ((*statep == state_unloaded && in_loaded_seg)
1378cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       || (*statep == state_loaded && !in_loaded_seg))
1379cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1380cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ERROR (gettext ("\
1381cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': relocations are against loaded and unloaded data\n"),
1382cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx));
1383cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  *statep = state_error;
1384441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1385441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1386cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
1387441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1388cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1389cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
1390cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_rela (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
1391cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
1392cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
1393cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (data == NULL)
1394cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1395cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
1396cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
1397cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
1398cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1399cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1400cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Check the fields of the section header.  */
1401cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr destshdr_mem;
1402cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *destshdr = NULL;
1403cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct loaded_segment *loaded = NULL;
1404cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool reldyn = check_reloc_shdr (ebl, ehdr, shdr, idx, ELF_T_RELA, &destshdr,
1405cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  &destshdr_mem, &loaded);
1406441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1407441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1408441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Shdr symshdr_mem;
1409441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1410441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf_Data *symdata = elf_getdata (symscn, NULL);
1411cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  enum load_state state = state_undecided;
1412441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1413cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
1414441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1415cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Rela rela_mem;
1416cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Rela *rela = gelf_getrela (data, cnt, &rela_mem);
1417cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (rela == NULL)
1418441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1419441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  ERROR (gettext ("\
1420441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': cannot get relocation %zu: %s\n"),
1421cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx), cnt, elf_errmsg (-1));
1422441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  continue;
1423441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1424441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1425cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      check_one_reloc (ebl, ehdr, shdr, idx, cnt, symshdr, symdata,
1426cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       rela->r_offset, rela->r_info, destshdr, reldyn, loaded,
1427cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       &state);
1428cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1429441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1430cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (loaded != NULL)
1431cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1432cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      struct loaded_segment *old = loaded;
1433cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      loaded = loaded->next;
1434cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      free (old);
1435cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1436cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
1437441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1438441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1439cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
1440cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_rel (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
1441cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
1442cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
1443cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (data == NULL)
1444cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1445cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
1446cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
1447cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
1448cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1449cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1450cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Check the fields of the section header.  */
1451cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr destshdr_mem;
1452cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *destshdr = NULL;
1453cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct loaded_segment *loaded = NULL;
1454cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool reldyn = check_reloc_shdr (ebl, ehdr, shdr, idx, ELF_T_REL, &destshdr,
1455cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  &destshdr_mem, &loaded);
1456cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1457cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1458cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr symshdr_mem;
1459cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1460cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *symdata = elf_getdata (symscn, NULL);
1461cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  enum load_state state = state_undecided;
1462cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1463cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
1464cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1465cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Rel rel_mem;
1466cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Rel *rel = gelf_getrel (data, cnt, &rel_mem);
1467cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (rel == NULL)
1468441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1469cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ERROR (gettext ("\
1470cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': cannot get relocation %zu: %s\n"),
1471cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx), cnt, elf_errmsg (-1));
1472cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  continue;
1473441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1474cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1475cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      check_one_reloc (ebl, ehdr, shdr, idx, cnt, symshdr, symdata,
1476cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       rel->r_offset, rel->r_info, destshdr, reldyn, loaded,
1477cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       &state);
1478cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1479cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1480cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (loaded != NULL)
1481cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1482cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      struct loaded_segment *old = loaded;
1483cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      loaded = loaded->next;
1484cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      free (old);
1485441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1486441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
1487441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1488441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1489441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Number of dynamic sections.  */
1490441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic int ndynamic;
1491441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1492441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1493441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
1494cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_dynamic (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
1495441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
1496441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf_Data *data;
1497441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Shdr strshdr_mem;
1498441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Shdr *strshdr;
1499441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  size_t cnt;
1500441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  static const bool dependencies[DT_NUM][DT_NUM] =
1501441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1502441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_NEEDED] = { [DT_STRTAB] = true },
1503441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_PLTRELSZ] = { [DT_JMPREL] = true },
1504441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_HASH] = { [DT_SYMTAB] = true },
1505441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_STRTAB] = { [DT_STRSZ] = true },
1506cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      [DT_SYMTAB] = { [DT_STRTAB] = true, [DT_SYMENT] = true },
1507441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_RELA] = { [DT_RELASZ] = true, [DT_RELAENT] = true },
1508441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_RELASZ] = { [DT_RELA] = true },
1509441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_RELAENT] = { [DT_RELA] = true },
1510441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_STRSZ] = { [DT_STRTAB] = true },
1511441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_SYMENT] = { [DT_SYMTAB] = true },
1512441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_SONAME] = { [DT_STRTAB] = true },
1513441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_RPATH] = { [DT_STRTAB] = true },
1514441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_REL] = { [DT_RELSZ] = true, [DT_RELENT] = true },
1515441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_RELSZ] = { [DT_REL] = true },
1516441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_RELENT] = { [DT_REL] = true },
1517441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_JMPREL] = { [DT_PLTRELSZ] = true, [DT_PLTREL] = true },
1518441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_RUNPATH] = { [DT_STRTAB] = true },
1519441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_PLTREL] = { [DT_JMPREL] = true },
1520441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    };
1521441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  bool has_dt[DT_NUM];
1522cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool has_val_dt[DT_VALNUM];
1523cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool has_addr_dt[DT_ADDRNUM];
1524441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  static const bool level2[DT_NUM] =
1525441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1526441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_RPATH] = true,
1527441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_SYMBOLIC] = true,
1528441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_TEXTREL] = true,
1529441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_BIND_NOW] = true
1530441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    };
1531441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  static const bool mandatory[DT_NUM] =
1532441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1533441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_NULL] = true,
1534441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_STRTAB] = true,
1535441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_SYMTAB] = true,
1536441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_STRSZ] = true,
1537441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      [DT_SYMENT] = true
1538441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    };
1539441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Addr reladdr = 0;
1540441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Word relsz = 0;
1541441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Addr pltreladdr = 0;
1542441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Word pltrelsz = 0;
1543441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1544441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  memset (has_dt, '\0', sizeof (has_dt));
1545cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  memset (has_val_dt, '\0', sizeof (has_val_dt));
1546cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  memset (has_addr_dt, '\0', sizeof (has_addr_dt));
1547441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1548441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (++ndynamic == 2)
1549441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("more than one dynamic section present\n"));
1550441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1551cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
1552441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (data == NULL)
1553441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1554441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
1555cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
1556441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return;
1557441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1558441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1559441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link), &strshdr_mem);
1560441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (strshdr != NULL && strshdr->sh_type != SHT_STRTAB)
1561441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("\
1562441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': referenced as string table for section [%2d] '%s' but type is not SHT_STRTAB\n"),
1563cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   shdr->sh_link, section_name (ebl, shdr->sh_link),
1564cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
1565441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1566441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (shdr->sh_entsize != gelf_fsize (ebl->elf, ELF_T_DYN, 1, EV_CURRENT))
1567441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("\
1568441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': section entry size does not match ElfXX_Dyn\n"),
1569cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
1570441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1571441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (shdr->sh_info != 0)
1572441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("section [%2d] '%s': sh_info not zero\n"),
1573cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
1574441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1575441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  bool non_null_warned = false;
1576441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  for (cnt = 0; cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
1577441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1578441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      GElf_Dyn dyn_mem;
1579cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Dyn *dyn = gelf_getdyn (data, cnt, &dyn_mem);
1580441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (dyn == NULL)
1581441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1582441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  ERROR (gettext ("\
1583441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': cannot get dynamic section entry %zu: %s\n"),
1584cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx), cnt, elf_errmsg (-1));
1585441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  continue;
1586441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1587441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1588441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (has_dt[DT_NULL] && dyn->d_tag != DT_NULL && ! non_null_warned)
1589441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1590441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  ERROR (gettext ("\
1591441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': non-DT_NULL entries follow DT_NULL entry\n"),
1592cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx));
1593441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  non_null_warned = true;
1594441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1595441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1596441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (!ebl_dynamic_tag_check (ebl, dyn->d_tag))
1597441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("section [%2d] '%s': entry %zu: unknown tag\n"),
1598cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
1599441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1600cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (dyn->d_tag >= 0 && dyn->d_tag < DT_NUM)
1601441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1602441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (has_dt[dyn->d_tag]
1603441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      && dyn->d_tag != DT_NEEDED
1604441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      && dyn->d_tag != DT_NULL
1605441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      && dyn->d_tag != DT_POSFLAG_1)
1606441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
1607441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      char buf[50];
1608441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      ERROR (gettext ("\
1609441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': entry %zu: more than one entry with tag %s\n"),
1610cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     idx, section_name (ebl, idx), cnt,
1611441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		     ebl_dynamic_tag_name (ebl, dyn->d_tag,
1612441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project					   buf, sizeof (buf)));
1613441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
1614441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1615441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (be_strict && level2[dyn->d_tag])
1616441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
1617441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      char buf[50];
1618441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      ERROR (gettext ("\
1619441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': entry %zu: level 2 tag %s used\n"),
1620cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     idx, section_name (ebl, idx), cnt,
1621441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		     ebl_dynamic_tag_name (ebl, dyn->d_tag,
1622441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project					   buf, sizeof (buf)));
1623441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
1624441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1625441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  has_dt[dyn->d_tag] = true;
1626441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1627cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (dyn->d_tag <= DT_VALRNGHI
1628cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       && DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
1629cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	has_val_dt[DT_VALTAGIDX (dyn->d_tag)] = true;
1630cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (dyn->d_tag <= DT_ADDRRNGHI
1631cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       && DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
1632cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	has_addr_dt[DT_ADDRTAGIDX (dyn->d_tag)] = true;
1633441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1634441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (dyn->d_tag == DT_PLTREL && dyn->d_un.d_val != DT_REL
1635441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && dyn->d_un.d_val != DT_RELA)
1636441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
1637441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': entry %zu: DT_PLTREL value must be DT_REL or DT_RELA\n"),
1638cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
1639441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1640441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (dyn->d_tag == DT_REL)
1641441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	reladdr = dyn->d_un.d_ptr;
1642441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (dyn->d_tag == DT_RELSZ)
1643441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	relsz = dyn->d_un.d_val;
1644441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (dyn->d_tag == DT_JMPREL)
1645441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	pltreladdr = dyn->d_un.d_ptr;
1646441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (dyn->d_tag == DT_PLTRELSZ)
1647441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	pltrelsz = dyn->d_un.d_val;
1648cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1649cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Check that addresses for entries are in loaded segments.  */
1650cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      switch (dyn->d_tag)
1651cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
1652cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  size_t n;
1653cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_STRTAB:
1654cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* We require the referenced section is the same as the one
1655cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     specified in sh_link.  */
1656cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (strshdr->sh_addr != dyn->d_un.d_val)
1657cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1658cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
1659cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %zu: pointer does not match address of section [%2d] '%s' referenced by sh_link\n"),
1660cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     idx, section_name (ebl, idx), cnt,
1661cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     shdr->sh_link, section_name (ebl, shdr->sh_link));
1662cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      break;
1663cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1664cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  goto check_addr;
1665cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1666cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	default:
1667cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (dyn->d_tag < DT_ADDRRNGLO || dyn->d_tag > DT_ADDRRNGHI)
1668cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    /* Value is no pointer.  */
1669cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    break;
1670cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* FALLTHROUGH */
1671cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1672cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_AUXILIARY:
1673cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_FILTER:
1674cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_FINI:
1675cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_FINI_ARRAY:
1676cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_HASH:
1677cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_INIT:
1678cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_INIT_ARRAY:
1679cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_JMPREL:
1680cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_PLTGOT:
1681cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_REL:
1682cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_RELA:
1683cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_SYMBOLIC:
1684cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_SYMTAB:
1685cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_VERDEF:
1686cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_VERNEED:
1687cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_VERSYM:
1688cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	check_addr:
1689cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (n = 0; n < ehdr->e_phnum; ++n)
1690cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1691cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Phdr phdr_mem;
1692cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Phdr *phdr = gelf_getphdr (ebl->elf, n, &phdr_mem);
1693cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (phdr != NULL && phdr->p_type == PT_LOAD
1694cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  && phdr->p_vaddr <= dyn->d_un.d_ptr
1695cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  && phdr->p_vaddr + phdr->p_memsz > dyn->d_un.d_ptr)
1696cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		break;
1697cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1698cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (unlikely (n >= ehdr->e_phnum))
1699cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1700cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      char buf[50];
1701cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
1702cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %zu: %s value must point into loaded segment\n"),
1703cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     idx, section_name (ebl, idx), cnt,
1704cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     ebl_dynamic_tag_name (ebl, dyn->d_tag, buf,
1705cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   sizeof (buf)));
1706cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1707cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  break;
1708cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1709cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_NEEDED:
1710cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_RPATH:
1711cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_RUNPATH:
1712cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case DT_SONAME:
1713cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (dyn->d_un.d_ptr >= strshdr->sh_size)
1714cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
1715cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      char buf[50];
1716cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
1717cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %zu: %s value must be valid offset in section [%2d] '%s'\n"),
1718cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     idx, section_name (ebl, idx), cnt,
1719cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     ebl_dynamic_tag_name (ebl, dyn->d_tag, buf,
1720cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   sizeof (buf)),
1721cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     shdr->sh_link, section_name (ebl, shdr->sh_link));
1722cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
1723cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  break;
1724cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
1725441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1726441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1727441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  for (cnt = 1; cnt < DT_NUM; ++cnt)
1728441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    if (has_dt[cnt])
1729441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      {
1730cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	for (int inner = 0; inner < DT_NUM; ++inner)
1731441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (dependencies[cnt][inner] && ! has_dt[inner])
1732441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
1733441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      char buf1[50];
1734441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      char buf2[50];
1735441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1736441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      ERROR (gettext ("\
1737441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': contains %s entry but not %s\n"),
1738cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     idx, section_name (ebl, idx),
1739441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		     ebl_dynamic_tag_name (ebl, cnt, buf1, sizeof (buf1)),
1740441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		     ebl_dynamic_tag_name (ebl, inner, buf2, sizeof (buf2)));
1741441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
1742441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      }
1743441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    else
1744441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      {
1745441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	if (mandatory[cnt])
1746441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  {
1747441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    char buf[50];
1748441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
1749441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': mandatory tag %s not present\n"),
1750cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx),
1751441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		   ebl_dynamic_tag_name (ebl, cnt, buf, sizeof (buf)));
1752441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  }
1753441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      }
1754441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1755cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Make sure we have an hash table.  */
1756cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (!has_dt[DT_HASH] && !has_addr_dt[DT_ADDRTAGIDX (DT_GNU_HASH)])
1757cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
1758cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': no hash section present\n"),
1759cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
1760cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1761cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* The GNU-style hash table also needs a symbol table.  */
1762cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (!has_dt[DT_HASH] && has_addr_dt[DT_ADDRTAGIDX (DT_GNU_HASH)]
1763cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      && !has_dt[DT_SYMTAB])
1764cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
1765cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': contains %s entry but not %s\n"),
1766cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx),
1767cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   "DT_GNU_HASH", "DT_SYMTAB");
1768cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1769441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check the rel/rela tags.  At least one group must be available.  */
1770441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if ((has_dt[DT_RELA] || has_dt[DT_RELASZ] || has_dt[DT_RELAENT])
1771441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      && (!has_dt[DT_RELA] || !has_dt[DT_RELASZ] || !has_dt[DT_RELAENT]))
1772441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("\
1773441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': not all of %s, %s, and %s are present\n"),
1774cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx),
1775441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   "DT_RELA", "DT_RELASZ", "DT_RELAENT");
1776441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1777441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if ((has_dt[DT_REL] || has_dt[DT_RELSZ] || has_dt[DT_RELENT])
1778441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      && (!has_dt[DT_REL] || !has_dt[DT_RELSZ] || !has_dt[DT_RELENT]))
1779441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("\
1780441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': not all of %s, %s, and %s are present\n"),
1781cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx),
1782441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   "DT_REL", "DT_RELSZ", "DT_RELENT");
1783cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1784cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Check that all prelink sections are present if any of them is.  */
1785cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (has_val_dt[DT_VALTAGIDX (DT_GNU_PRELINKED)]
1786cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      || has_val_dt[DT_VALTAGIDX (DT_CHECKSUM)])
1787cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1788cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (!has_val_dt[DT_VALTAGIDX (DT_GNU_PRELINKED)])
1789cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
1790cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': %s tag missing in DSO marked during prelinking\n"),
1791cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "DT_GNU_PRELINKED");
1792cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (!has_val_dt[DT_VALTAGIDX (DT_CHECKSUM)])
1793cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
1794cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': %s tag missing in DSO marked during prelinking\n"),
1795cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "DT_CHECKSUM");
1796cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1797cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Only DSOs can be marked like this.  */
1798cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (ehdr->e_type != ET_DYN)
1799cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
1800cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': non-DSO file marked as dependency during prelink\n"),
1801cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
1802cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1803cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1804cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (has_val_dt[DT_VALTAGIDX (DT_GNU_CONFLICTSZ)]
1805cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      || has_val_dt[DT_VALTAGIDX (DT_GNU_LIBLISTSZ)]
1806cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      || has_addr_dt[DT_ADDRTAGIDX (DT_GNU_CONFLICT)]
1807cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      || has_addr_dt[DT_ADDRTAGIDX (DT_GNU_LIBLIST)])
1808cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1809cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (!has_val_dt[DT_VALTAGIDX (DT_GNU_CONFLICTSZ)])
1810cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
1811cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': %s tag missing in prelinked executable\n"),
1812cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "DT_GNU_CONFLICTSZ");
1813cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (!has_val_dt[DT_VALTAGIDX (DT_GNU_LIBLISTSZ)])
1814cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
1815cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': %s tag missing in prelinked executable\n"),
1816cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "DT_GNU_LIBLISTSZ");
1817cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (!has_addr_dt[DT_ADDRTAGIDX (DT_GNU_CONFLICT)])
1818cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
1819cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': %s tag missing in prelinked executable\n"),
1820cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "DT_GNU_CONFLICT");
1821cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (!has_addr_dt[DT_ADDRTAGIDX (DT_GNU_LIBLIST)])
1822cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
1823cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': %s tag missing in prelinked executable\n"),
1824cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), "DT_GNU_LIBLIST");
1825cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1826441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
1827441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1828441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1829441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
1830cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_symtab_shndx (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
1831441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
1832cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (ehdr->e_type != ET_REL)
1833cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
1834cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("\
1835cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': only relocatable files can have extended section index\n"),
1836cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
1837cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
1838cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1839441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1840cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
1841cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr symshdr_mem;
1842cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
1843441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (symshdr != NULL && symshdr->sh_type != SHT_SYMTAB)
1844441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("\
1845441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': extended section index section not for symbol table\n"),
1846cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
1847cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *symdata = elf_getdata (symscn, NULL);
1848441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (symdata == NULL)
1849441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("cannot get data for symbol section\n"));
1850441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1851441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (shdr->sh_entsize != sizeof (Elf32_Word))
1852441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("\
1853441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': entry size does not match Elf32_Word\n"),
1854cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
1855441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1856441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (symshdr != NULL
1857441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      && (shdr->sh_size / shdr->sh_entsize
1858441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  < symshdr->sh_size / symshdr->sh_entsize))
1859441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("\
1860441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': extended index table too small for symbol table\n"),
1861cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
1862441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1863441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (shdr->sh_info != 0)
1864441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("section [%2d] '%s': sh_info not zero\n"),
1865cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
1866441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1867cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t cnt = idx + 1; cnt < shnum; ++cnt)
1868441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1869441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      GElf_Shdr rshdr_mem;
1870cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Shdr *rshdr = gelf_getshdr (elf_getscn (ebl->elf, cnt), &rshdr_mem);
1871441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (rshdr != NULL && rshdr->sh_type == SHT_SYMTAB_SHNDX
1872441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && rshdr->sh_link == shdr->sh_link)
1873441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1874441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  ERROR (gettext ("\
1875441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': extended section index in section [%2zu] '%s' refers to same symbol table\n"),
1876cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx),
1877cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 cnt, section_name (ebl, cnt));
1878441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
1879441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1880441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1881441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1882cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
1883441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1884441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (*((Elf32_Word *) data->d_buf) != 0)
1885441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("symbol 0 should have zero extended section index\n"));
1886441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1887cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t cnt = 1; cnt < data->d_size / sizeof (Elf32_Word); ++cnt)
1888441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1889441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      Elf32_Word xndx = ((Elf32_Word *) data->d_buf)[cnt];
1890441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1891441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (xndx != 0)
1892441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1893441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  GElf_Sym sym_data;
1894441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  GElf_Sym *sym = gelf_getsym (symdata, cnt, &sym_data);
1895441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (sym == NULL)
1896441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
1897441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      ERROR (gettext ("cannot get data for symbol %zu\n"), cnt);
1898441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      continue;
1899441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
1900441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1901441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (sym->st_shndx != SHN_XINDEX)
1902441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
1903441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectextended section index is %" PRIu32 " but symbol index is not XINDEX\n"),
1904441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		   (uint32_t) xndx);
1905441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1906441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1907441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
1908441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1909441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1910441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
1911cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_sysv_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx,
1912cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 GElf_Shdr *symshdr)
1913441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
1914cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0];
1915cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1];
1916441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1917cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize)
1918cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
1919cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"),
1920cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), (long int) shdr->sh_size,
1921cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   (long int) ((2 + nbucket + nchain) * shdr->sh_entsize));
1922cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1923cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t maxidx = nchain;
1924cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1925cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (symshdr != NULL)
1926441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1927cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t symsize = symshdr->sh_size / symshdr->sh_entsize;
1928441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1929cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (nchain > symshdr->sh_size / symshdr->sh_entsize)
1930cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("section [%2d] '%s': chain array too large\n"),
1931cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
1932441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1933cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      maxidx = symsize;
1934cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1935441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1936cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t cnt;
1937cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (cnt = 2; cnt < 2 + nbucket; ++cnt)
1938cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (((Elf32_Word *) data->d_buf)[cnt] >= maxidx)
1939cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("\
1940cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': hash bucket reference %zu out of bounds\n"),
1941cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx), cnt - 2);
1942441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1943cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (; cnt < 2 + nbucket + nchain; ++cnt)
1944cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (((Elf32_Word *) data->d_buf)[cnt] >= maxidx)
1945441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ERROR (gettext ("\
1946cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': hash chain reference %zu out of bounds\n"),
1947cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx), cnt - 2 - nbucket);
1948cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
1949cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1950441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1951cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
1952cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_sysv_hash64 (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx,
1953cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 GElf_Shdr *symshdr)
1954cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
1955cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0];
1956cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1];
1957441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1958441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (shdr->sh_size < (2 + nbucket + nchain) * shdr->sh_entsize)
1959441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("\
1960441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"),
1961cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), (long int) shdr->sh_size,
1962441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   (long int) ((2 + nbucket + nchain) * shdr->sh_entsize));
1963441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1964cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t maxidx = nchain;
1965cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1966441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (symshdr != NULL)
1967441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1968441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      size_t symsize = symshdr->sh_size / symshdr->sh_entsize;
1969441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1970cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (nchain > symshdr->sh_size / symshdr->sh_entsize)
1971cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("section [%2d] '%s': chain array too large\n"),
1972cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
1973441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1974cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      maxidx = symsize;
1975cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
1976cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1977cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t cnt;
1978cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (cnt = 2; cnt < 2 + nbucket; ++cnt)
1979cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (((Elf64_Xword *) data->d_buf)[cnt] >= maxidx)
1980cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("\
1981441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': hash bucket reference %zu out of bounds\n"),
1982cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx), cnt - 2);
1983441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1984cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (; cnt < 2 + nbucket + nchain; ++cnt)
1985cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (((Elf64_Xword *) data->d_buf)[cnt] >= maxidx)
1986cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("\
1987cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': hash chain reference %" PRIu64 " out of bounds\n"),
1988cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx), (uint64_t) (cnt - 2 - nbucket));
1989441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
1990441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1991441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1992441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
1993cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_gnu_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx,
1994cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Shdr *symshdr)
1995441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
1996cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf32_Word nbuckets = ((Elf32_Word *) data->d_buf)[0];
1997cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf32_Word symbias = ((Elf32_Word *) data->d_buf)[1];
1998cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf32_Word bitmask_words = ((Elf32_Word *) data->d_buf)[2];
1999441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2000cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (!powerof2 (bitmask_words))
2001cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
2002cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': bitmask size not power of 2: %u\n"),
2003cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), bitmask_words);
2004441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2005cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t bitmask_idxmask = bitmask_words - 1;
2006cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (gelf_getclass (ebl->elf) == ELFCLASS64)
2007cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    bitmask_words *= 2;
2008cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf32_Word shift = ((Elf32_Word *) data->d_buf)[3];
2009441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2010cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr->sh_size < (4 + bitmask_words + nbuckets) * sizeof (Elf32_Word))
2011441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
2012441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ERROR (gettext ("\
2013cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': hash table section is too small (is %ld, expected at least%ld)\n"),
2014cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx), (long int) shdr->sh_size,
2015cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     (long int) ((4 + bitmask_words + nbuckets) * sizeof (Elf32_Word)));
2016441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return;
2017441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
2018441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2019cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shift > 31)
2020cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
2021cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': 2nd hash function shift too big: %u\n"),
2022cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), shift);
2023441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2024cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t maxidx = shdr->sh_size / sizeof (Elf32_Word) - (4 + bitmask_words
2025cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng							 + nbuckets);
2026441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2027cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (symshdr != NULL)
2028cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    maxidx = MIN (maxidx, symshdr->sh_size / symshdr->sh_entsize);
2029441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2030cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* We need the symbol section data.  */
2031cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *symdata = elf_getdata (elf_getscn (ebl->elf, shdr->sh_link), NULL);
2032441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2033cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  union
2034cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
2035cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    Elf32_Word *p32;
2036cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    Elf64_Xword *p64;
2037cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  } bitmask = { .p32 = &((Elf32_Word *) data->d_buf)[4] },
2038cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      collected = { .p32 = xcalloc (bitmask_words, sizeof (Elf32_Word)) };
2039cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2040cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t classbits = gelf_getclass (ebl->elf) == ELFCLASS32 ? 32 : 64;
2041cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2042cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t cnt;
2043cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (cnt = 4 + bitmask_words; cnt < 4 + bitmask_words + nbuckets; ++cnt)
2044441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
2045cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf32_Word symidx = ((Elf32_Word *) data->d_buf)[cnt];
2046441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2047cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (symidx == 0)
2048cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	continue;
2049441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2050cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (symidx < symbias)
2051441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
2052cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ERROR (gettext ("\
2053cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': hash chain for bucket %zu lower than symbol index bias\n"),
2054cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx), cnt - (4 + bitmask_words));
2055cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  continue;
2056441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
2057441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2058cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      while (symidx - symbias < maxidx)
2059441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
2060cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf32_Word chainhash = ((Elf32_Word *) data->d_buf)[4
2061cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng							      + bitmask_words
2062cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng							      + nbuckets
2063cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng							      + symidx
2064cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng							      - symbias];
2065441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2066cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (symdata != NULL)
2067441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
2068cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* Check that the referenced symbol is not undefined.  */
2069cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Sym sym_mem;
2070cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Sym *sym = gelf_getsym (symdata, symidx, &sym_mem);
2071cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (sym != NULL && sym->st_shndx == SHN_UNDEF
2072cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  && GELF_ST_TYPE (sym->st_info) != STT_FUNC)
2073441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		ERROR (gettext ("\
2074cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': symbol %u referenced in chain for bucket %zu is undefined\n"),
2075cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       idx, section_name (ebl, idx), symidx,
2076cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       cnt - (4 + bitmask_words));
2077cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2078cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      const char *symname = elf_strptr (ebl->elf, symshdr->sh_link,
2079cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						sym->st_name);
2080cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (symname != NULL)
2081cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
2082cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  Elf32_Word hval = elf_gnu_hash (symname);
2083cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if ((hval & ~1u) != (chainhash & ~1u))
2084cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    ERROR (gettext ("\
2085cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': hash value for symbol %u in chain for bucket %zu wrong\n"),
2086cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   idx, section_name (ebl, idx), symidx,
2087cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   cnt - (4 + bitmask_words));
2088cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2089cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  /* Set the bits in the bitmask.  */
2090cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  size_t maskidx = (hval / classbits) & bitmask_idxmask;
2091cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (classbits == 32)
2092cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
2093cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      collected.p32[maskidx]
2094cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			|= UINT32_C (1) << (hval & (classbits - 1));
2095cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      collected.p32[maskidx]
2096cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			|= UINT32_C (1) << ((hval >> shift) & (classbits - 1));
2097cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
2098cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  else
2099cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
2100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      collected.p64[maskidx]
2101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			|= UINT64_C (1) << (hval & (classbits - 1));
2102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      collected.p64[maskidx]
2103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			|= UINT64_C (1) << ((hval >> shift) & (classbits - 1));
2104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
2105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
2106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
2107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if ((chainhash & 1) != 0)
2109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    break;
2110cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2111cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ++symidx;
2112cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (symidx - symbias >= maxidx)
2115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': hash chain for bucket %zu out of bounds\n"),
2117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt - (4 + bitmask_words));
2118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (symshdr != NULL
2119cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       && symidx > symshdr->sh_size / symshdr->sh_entsize)
2120cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': symbol reference in chain for bucket %zu out of bounds\n"),
2122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt - (4 + bitmask_words));
2123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2125cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (memcmp (collected.p32, bitmask.p32, bitmask_words * sizeof (Elf32_Word)))
2126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
2127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': bitmask does not match names in the hash table\n"),
2128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
2129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  free (collected.p32);
2131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
2135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_hash (int tag, Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
2136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (ehdr->e_type == ET_REL)
2138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("\
2140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': relocatable files cannot have hash tables\n"),
2141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
2142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
2143cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
2146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (data == NULL)
2147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
2149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
2150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
2151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2153cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr symshdr_mem;
2154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *symshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     &symshdr_mem);
2156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (symshdr != NULL && symshdr->sh_type != SHT_DYNSYM)
2157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
2158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': hash table not for dynamic symbol table\n"),
2159cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
2160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr->sh_entsize != (tag == SHT_GNU_HASH
2162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   ? (gelf_getclass (ebl->elf) == ELFCLASS32
2163cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      ? sizeof (Elf32_Word) : 0)
2164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   : (size_t) ebl_sysvhash_entrysize (ebl)))
2165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
2166cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': hash table entry size incorrect\n"),
2167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
2168cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if ((shdr->sh_flags & SHF_ALLOC) == 0)
2170cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("section [%2d] '%s': not marked to be allocated\n"),
2171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
2172cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2173cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr->sh_size < (tag == SHT_GNU_HASH ? 4 : 2) * (shdr->sh_entsize ?: 4))
2174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2175cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("\
2176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': hash table has not even room for initial administrative entries\n"),
2177cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
2178cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
2179cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2180cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2181cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  switch (tag)
2182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case SHT_HASH:
2184cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (ebl_sysvhash_entrysize (ebl) == sizeof (Elf64_Xword))
2185cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	check_sysv_hash64 (ebl, shdr, data, idx, symshdr);
2186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
2187cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	check_sysv_hash (ebl, shdr, data, idx, symshdr);
2188cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
2189cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case SHT_GNU_HASH:
2191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      check_gnu_hash (ebl, shdr, data, idx, symshdr);
2192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
2193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    default:
2195cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      assert (! "should not happen");
2196cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2197cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2198cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2199cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2200cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Compare content of both hash tables, it must be identical.  */
2201cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
2202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcompare_hash_gnu_hash (Ebl *ebl, GElf_Ehdr *ehdr, size_t hash_idx,
2203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       size_t gnu_hash_idx)
2204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *hash_scn = elf_getscn (ebl->elf, hash_idx);
2206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *hash_data = elf_getdata (hash_scn, NULL);
2207cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr hash_shdr_mem;
2208cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *hash_shdr = gelf_getshdr (hash_scn, &hash_shdr_mem);
2209cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *gnu_hash_scn = elf_getscn (ebl->elf, gnu_hash_idx);
2210cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *gnu_hash_data = elf_getdata (gnu_hash_scn, NULL);
2211cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr gnu_hash_shdr_mem;
2212cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *gnu_hash_shdr = gelf_getshdr (gnu_hash_scn, &gnu_hash_shdr_mem);
2213cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2214cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (hash_shdr == NULL || gnu_hash_shdr == NULL
2215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      || hash_data == NULL || gnu_hash_data == NULL)
2216cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* None of these pointers should be NULL since we used the
2217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng       sections already.  We are careful nonetheless.  */
2218cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
2219cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2220cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* The link must point to the same symbol table.  */
2221cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (hash_shdr->sh_link != gnu_hash_shdr->sh_link)
2222cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2223cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("\
2224cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsh_link in hash sections [%2zu] '%s' and [%2zu] '%s' not identical\n"),
2225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     hash_idx, elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name),
2226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     gnu_hash_idx,
2227cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name));
2228cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
2229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *sym_scn = elf_getscn (ebl->elf, hash_shdr->sh_link);
2232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *sym_data = elf_getdata (sym_scn, NULL);
2233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr sym_shdr_mem;
2234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *sym_shdr = gelf_getshdr (sym_scn, &sym_shdr_mem);
2235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (sym_data == NULL || sym_shdr == NULL)
2237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
2238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  int nentries = sym_shdr->sh_size / sym_shdr->sh_entsize;
2240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  char *used = alloca (nentries);
2241cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  memset (used, '\0', nentries);
2242cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2243cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* First go over the GNU_HASH table and mark the entries as used.  */
2244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const Elf32_Word *gnu_hasharr = (Elf32_Word *) gnu_hash_data->d_buf;
2245cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf32_Word gnu_nbucket = gnu_hasharr[0];
2246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const int bitmap_factor = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 1 : 2;
2247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const Elf32_Word *gnu_bucket = (gnu_hasharr
2248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  + (4 + gnu_hasharr[2] * bitmap_factor));
2249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const Elf32_Word *gnu_chain = gnu_bucket + gnu_hasharr[0] - gnu_hasharr[1];
2250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (Elf32_Word cnt = 0; cnt < gnu_nbucket; ++cnt)
2252cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf32_Word symidx = gnu_bucket[cnt];
2254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (symidx != STN_UNDEF)
2255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	do
2256cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  used[symidx] |= 1;
2257cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	while ((gnu_chain[symidx++] & 1u) == 0);
2258cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2259cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2260cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Now go over the old hash table and check that we cover the same
2261cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     entries.  */
2262cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (hash_shdr->sh_entsize == sizeof (Elf32_Word))
2263cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2264cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const Elf32_Word *hasharr = (Elf32_Word *) hash_data->d_buf;
2265cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf32_Word nbucket = hasharr[0];
2266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const Elf32_Word *bucket = &hasharr[2];
2267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const Elf32_Word *chain = &hasharr[2 + nbucket];
2268cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2269cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (Elf32_Word cnt = 0; cnt < nbucket; ++cnt)
2270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf32_Word symidx = bucket[cnt];
2272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  while (symidx != STN_UNDEF)
2273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
2274cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      used[symidx] |= 2;
2275cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      symidx = chain[symidx];
2276cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
2277cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2278cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2279cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else
2280cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2281cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const Elf64_Xword *hasharr = (Elf64_Xword *) hash_data->d_buf;
2282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf64_Xword nbucket = hasharr[0];
2283cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const Elf64_Xword *bucket = &hasharr[2];
2284cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const Elf64_Xword *chain = &hasharr[2 + nbucket];
2285cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2286cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (Elf64_Xword cnt = 0; cnt < nbucket; ++cnt)
2287cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf64_Xword symidx = bucket[cnt];
2289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  while (symidx != STN_UNDEF)
2290cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
2291cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      used[symidx] |= 2;
2292cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      symidx = chain[symidx];
2293cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
2294cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2295cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2296cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Now see which entries are not set in one or both hash tables
2298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     (unless the symbol is undefined in which case it can be omitted
2299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     in the new table format).  */
2300cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if ((used[0] & 1) != 0)
2301cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("section [%2zu] '%s': reference to symbol index 0\n"),
2302cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   gnu_hash_idx,
2303cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name));
2304cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if ((used[0] & 2) != 0)
2305cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("section [%2zu] '%s': reference to symbol index 0\n"),
2306cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   hash_idx, elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name));
2307cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2308cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (int cnt = 1; cnt < nentries; ++cnt)
2309cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (used[cnt] != 0 && used[cnt] != 3)
2310cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
2311cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (used[cnt] == 1)
2312cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ERROR (gettext ("\
2313cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsymbol %d referenced in new hash table in [%2zu] '%s' but not in old hash table in [%2zu] '%s'\n"),
2314cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 cnt, gnu_hash_idx,
2315cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name),
2316cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 hash_idx,
2317cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name));
2318cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	else
2319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
2320cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    GElf_Sym sym_mem;
2321cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    GElf_Sym *sym = gelf_getsym (sym_data, cnt, &sym_mem);
2322cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2323cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (sym != NULL && sym->st_shndx != STN_UNDEF)
2324cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
2325cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsymbol %d referenced in old hash table in [%2zu] '%s' but not in new hash table in [%2zu] '%s'\n"),
2326cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     cnt, hash_idx,
2327cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     elf_strptr (ebl->elf, shstrndx, hash_shdr->sh_name),
2328cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     gnu_hash_idx,
2329cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     elf_strptr (ebl->elf, shstrndx, gnu_hash_shdr->sh_name));
2330cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
2331cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
2332cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2333cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2334cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2335cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
2336cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_null (Ebl *ebl, GElf_Shdr *shdr, int idx)
2337cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2338cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define TEST(name, extra) \
2339cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (extra && shdr->sh_##name != 0)					      \
2340cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("section [%2d] '%s': nonzero sh_%s for NULL section\n"),  \
2341cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), #name)
2342cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2343cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  TEST (name, 1);
2344cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  TEST (flags, 1);
2345cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  TEST (addr, 1);
2346cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  TEST (offset, 1);
2347cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  TEST (size, idx != 0);
2348cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  TEST (link, idx != 0);
2349cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  TEST (info, 1);
2350cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  TEST (addralign, 1);
2351cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  TEST (entsize, 1);
2352cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2353cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2354cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2355cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
2356cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_group (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
2357cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2358cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (ehdr->e_type != ET_REL)
2359cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2360cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("\
2361cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': section groups only allowed in relocatable object files\n"),
2362cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
2363cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
2364cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2365cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2366cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Check that sh_link is an index of a symbol table.  */
2367cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
2368cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr symshdr_mem;
2369cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
2370cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (symshdr == NULL)
2371cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("section [%2d] '%s': cannot get symbol table: %s\n"),
2372cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), elf_errmsg (-1));
2373cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else
2374cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2375cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (symshdr->sh_type != SHT_SYMTAB)
2376cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2377cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': section reference in sh_link is no symbol table\n"),
2378cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
2379cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2380cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (shdr->sh_info >= symshdr->sh_size / gelf_fsize (ebl->elf, ELF_T_SYM,
2381cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng							  1, EV_CURRENT))
2382cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2383cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': invalid symbol index in sh_info\n"),
2384cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
2385cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2386cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (shdr->sh_flags != 0)
2387cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("section [%2d] '%s': sh_flags not zero\n"),
2388cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
2389cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2390cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym sym_data;
2391cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym *sym = gelf_getsym (elf_getdata (symscn, NULL), shdr->sh_info,
2392cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   &sym_data);
2393cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sym == NULL)
2394cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2395cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': cannot get symbol for signature\n"),
2396cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
2397cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (strcmp (elf_strptr (ebl->elf, symshdr->sh_link, sym->st_name),
2398cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       "") == 0)
2399cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2400cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': signature symbol canot be empty string\n"),
2401cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
2402cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2403cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (be_strict
2404cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && shdr->sh_entsize != elf32_fsize (ELF_T_WORD, 1, EV_CURRENT))
2405cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("section [%2d] '%s': sh_flags not set correctly\n"),
2406cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
2407cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2408cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2409cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
2410cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (data == NULL)
2411cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("section [%2d] '%s': cannot get data: %s\n"),
2412cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), elf_errmsg (-1));
2413cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else
2414cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2415cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t elsize = elf32_fsize (ELF_T_WORD, 1, EV_CURRENT);
2416cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      size_t cnt;
2417cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      Elf32_Word val;
2418cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2419cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (data->d_size % elsize != 0)
2420cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2421cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': section size not multiple of sizeof(Elf32_Word)\n"),
2422cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
2423cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2424cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (data->d_size < elsize)
2425cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2426cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': section group without flags word\n"),
2427cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
2428cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (be_strict)
2429cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2430cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (data->d_size < 2 * elsize)
2431cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
2432cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': section group without member\n"),
2433cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx));
2434cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else if (data->d_size < 3 * elsize)
2435cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
2436cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': section group with only one member\n"),
2437cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx));
2438cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2439cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2440cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#if ALLOW_UNALIGNED
2441cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      val = *((Elf32_Word *) data->d_buf);
2442cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#else
2443cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      memcpy (&val, data->d_buf, elsize);
2444cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#endif
2445cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if ((val & ~GRP_COMDAT) != 0)
2446cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("section [%2d] '%s': unknown section group flags\n"),
2447cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx));
2448cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2449cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (cnt = elsize; cnt < data->d_size; cnt += elsize)
2450cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2451cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#if ALLOW_UNALIGNED
2452cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  val = *((Elf32_Word *) ((char *) data->d_buf + cnt));
2453cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#else
2454cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  memcpy (&val, (char *) data->d_buf + cnt, elsize);
2455cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#endif
2456cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2457cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (val > shnum)
2458cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
2459cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': section index %Zu out of range\n"),
2460cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), cnt / elsize);
2461cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
2462cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
2463cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Shdr refshdr_mem;
2464cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Shdr *refshdr = gelf_getshdr (elf_getscn (ebl->elf, val),
2465cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						 &refshdr_mem);
2466cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (refshdr == NULL)
2467cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ERROR (gettext ("\
2468cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': cannot get section header for element %zu: %s\n"),
2469cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       idx, section_name (ebl, idx), cnt / elsize,
2470cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       elf_errmsg (-1));
2471441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      else
2472441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		{
2473441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  if (refshdr->sh_type == SHT_GROUP)
2474441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    ERROR (gettext ("\
2475441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': section group contains another group [%2d] '%s'\n"),
2476cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   idx, section_name (ebl, idx),
2477cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   val, section_name (ebl, val));
2478441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2479441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  if ((refshdr->sh_flags & SHF_GROUP) == 0)
2480441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    ERROR (gettext ("\
2481441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s': element %Zu references section [%2d] '%s' without SHF_GROUP flag set\n"),
2482cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   idx, section_name (ebl, idx), cnt / elsize,
2483cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   val, section_name (ebl, val));
2484441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		}
2485441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
2486441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      if (++scnref[val] == 2)
2487441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		ERROR (gettext ("\
2488441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s' is contained in more than one section group\n"),
2489cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       val, section_name (ebl, val));
2490441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
2491441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
2492441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
2493cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2494cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2495cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2496cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic const char *
2497cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection_flags_string (GElf_Word flags, char *buf, size_t len)
2498cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2499cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (flags == 0)
2500cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return "none";
2501cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2502cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  static const struct
2503cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
2504cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    GElf_Word flag;
2505cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    const char *name;
2506cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  } known_flags[] =
2507cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2508cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define NEWFLAG(name) { SHF_##name, #name }
2509cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      NEWFLAG (WRITE),
2510cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      NEWFLAG (ALLOC),
2511cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      NEWFLAG (EXECINSTR),
2512cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      NEWFLAG (MERGE),
2513cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      NEWFLAG (STRINGS),
2514cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      NEWFLAG (INFO_LINK),
2515cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      NEWFLAG (LINK_ORDER),
2516cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      NEWFLAG (OS_NONCONFORMING),
2517cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      NEWFLAG (GROUP),
2518cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      NEWFLAG (TLS)
2519cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    };
2520cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#undef NEWFLAG
2521cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const size_t nknown_flags = sizeof (known_flags) / sizeof (known_flags[0]);
2522cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2523cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  char *cp = buf;
2524cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2525cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t cnt = 0; cnt < nknown_flags; ++cnt)
2526cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (flags & known_flags[cnt].flag)
2527cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
2528cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (cp != buf && len > 1)
2529cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
2530cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    *cp++ = '|';
2531cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    --len;
2532cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
2533cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2534cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	size_t ncopy = MIN (len - 1, strlen (known_flags[cnt].name));
2535cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	cp = mempcpy (cp, known_flags[cnt].name, ncopy);
2536cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	len -= ncopy;
2537cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2538cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	flags ^= known_flags[cnt].flag;
2539cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
2540cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2541cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (flags != 0 || cp == buf)
2542cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    snprintf (cp, len - 1, "%" PRIx64, (uint64_t) flags);
2543cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2544cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  *cp = '\0';
2545cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2546cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return buf;
2547cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2548cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2549cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2550cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
2551cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chenghas_copy_reloc (Ebl *ebl, unsigned int symscnndx, unsigned int symndx)
2552cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2553cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* First find the relocation section for the symbol table.  */
2554cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *scn = NULL;
2555cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr shdr_mem;
2556cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *shdr = NULL;
2557cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
2558cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2559cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      shdr = gelf_getshdr (scn, &shdr_mem);
2560cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (shdr != NULL
2561cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
2562cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && shdr->sh_link == symscnndx)
2563cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	/* Found the section.  */
2564cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	break;
2565cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2566cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2567cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (scn == NULL)
2568cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return 0;
2569cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2570cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (scn, NULL);
2571cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (data == NULL)
2572cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return 0;
2573cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2574cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr->sh_type == SHT_REL)
2575cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    for (int i = 0; (size_t) i < shdr->sh_size / shdr->sh_entsize; ++i)
2576cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
2577cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Rel rel_mem;
2578cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Rel *rel = gelf_getrel (data, i, &rel_mem);
2579cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (rel == NULL)
2580cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  continue;
2581cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2582cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (GELF_R_SYM (rel->r_info) == symndx
2583cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rel->r_info)))
2584cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return 1;
2585cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
2586cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else
2587cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    for (int i = 0; (size_t) i < shdr->sh_size / shdr->sh_entsize; ++i)
2588cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
2589cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Rela rela_mem;
2590cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Rela *rela = gelf_getrela (data, i, &rela_mem);
2591cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (rela == NULL)
2592cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  continue;
2593cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2594cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (GELF_R_SYM (rela->r_info) == symndx
2595cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    && ebl_copy_reloc_p (ebl, GELF_R_TYPE (rela->r_info)))
2596cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return 1;
2597cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
2598cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2599cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return 0;
2600cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2601cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2602cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2603cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
2604cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengin_nobits_scn (Ebl *ebl, unsigned int shndx)
2605cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2606cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr shdr_mem;
2607cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, shndx), &shdr_mem);
2608cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return shdr != NULL && shdr->sh_type == SHT_NOBITS;
2609cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2610cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2611cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2612cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic struct version_namelist
2613cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2614cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const char *objname;
2615cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const char *name;
2616cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Versym ndx;
2617cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  enum { ver_def, ver_need } type;
2618cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct version_namelist *next;
2619cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng} *version_namelist;
2620cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2621cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2622cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
2623cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengadd_version (const char *objname, const char *name, GElf_Versym ndx, int type)
2624cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2625cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Check that there are no duplications.  */
2626cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct version_namelist *nlp = version_namelist;
2627cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (nlp != NULL)
2628cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2629cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (((nlp->objname == NULL && objname == NULL)
2630cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   || (nlp->objname != NULL && objname != NULL
2631cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       && strcmp (nlp->objname, objname) == 0))
2632cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && strcmp (nlp->name, name) == 0)
2633cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return nlp->type == ver_def ? 1 : -1;
2634cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      nlp = nlp->next;
2635cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2636cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2637cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  nlp = xmalloc (sizeof (*nlp));
2638cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  nlp->objname = objname;
2639cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  nlp->name = name;
2640cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  nlp->ndx = ndx;
2641cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  nlp->type = type;
2642cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  nlp->next = version_namelist;
2643cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  version_namelist = nlp;
2644cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2645cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return 0;
2646cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2647cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2648cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2649cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
2650cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_versym (Ebl *ebl, int idx)
2651cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2652cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *scn = elf_getscn (ebl->elf, idx);
2653cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr shdr_mem;
2654cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2655cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr == NULL)
2656cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* The error has already been reported.  */
2657cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
2658cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2659cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (scn, NULL);
2660cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (data == NULL)
2661cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2662cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
2663cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
2664cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
2665cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2666cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2667cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
2668cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr symshdr_mem;
2669cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
2670cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (symshdr == NULL)
2671cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* The error has already been reported.  */
2672cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
2673cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2674cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (symshdr->sh_type != SHT_DYNSYM)
2675cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2676cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("\
2677cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s' refers in sh_link to section [%2d] '%s' which is no dynamic symbol table\n"),
2678cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx),
2679cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     shdr->sh_link, section_name (ebl, shdr->sh_link));
2680cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
2681cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2682cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2683cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* The number of elements in the version symbol table must be the
2684cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     same as the number of symbols.  */
2685cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr->sh_size / shdr->sh_entsize
2686cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      != symshdr->sh_size / symshdr->sh_entsize)
2687cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
2688cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s' has different number of entries than symbol table [%2d] '%s'\n"),
2689cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx),
2690cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   shdr->sh_link, section_name (ebl, shdr->sh_link));
2691cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2692cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *symdata = elf_getdata (symscn, NULL);
2693cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (symdata == NULL)
2694cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* The error has already been reported.  */
2695cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
2696cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2697cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (int cnt = 1; (size_t) cnt < shdr->sh_size / shdr->sh_entsize; ++cnt)
2698cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2699cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Versym versym_mem;
2700cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Versym *versym = gelf_getversym (data, cnt, &versym_mem);
2701cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (versym == NULL)
2702cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2703cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ERROR (gettext ("\
2704cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': symbol %d: cannot read version data\n"),
2705cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx), cnt);
2706cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  break;
2707cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2708cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2709cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym sym_mem;
2710cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Sym *sym = gelf_getsym (symdata, cnt, &sym_mem);
2711cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sym == NULL)
2712cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	/* Already reported elsewhere.  */
2713cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	continue;
2714cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2715cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (*versym == VER_NDX_GLOBAL)
2716cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2717cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Global symbol.  Make sure it is not defined as local.  */
2718cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (GELF_ST_BIND (sym->st_info) == STB_LOCAL)
2719cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
2720cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': symbol %d: local symbol with global scope\n"),
2721cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), cnt);
2722cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2723cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (*versym != VER_NDX_LOCAL)
2724cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2725cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Versioned symbol.  Make sure it is not defined as local.  */
2726cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (!gnuld && GELF_ST_BIND (sym->st_info) == STB_LOCAL)
2727cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
2728cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': symbol %d: local symbol with version\n"),
2729cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), cnt);
2730cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2731cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Look through the list of defined versions and locate the
2732cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     index we need for this symbol.  */
2733cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  struct version_namelist *runp = version_namelist;
2734cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  while (runp != NULL)
2735cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (runp->ndx == (*versym & (GElf_Versym) 0x7fff))
2736cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      break;
2737cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    else
2738cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      runp = runp->next;
2739cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2740cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (runp == NULL)
2741cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
2742cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': symbol %d: invalid version index %d\n"),
2743cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), cnt, (int) *versym);
2744cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else if (sym->st_shndx == SHN_UNDEF
2745cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   && runp->type == ver_def)
2746cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
2747cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': symbol %d: version index %d is for defined version\n"),
2748cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), cnt, (int) *versym);
2749cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else if (sym->st_shndx != SHN_UNDEF
2750cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   && runp->type == ver_need)
2751cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
2752cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* Unless this symbol has a copy relocation associated
2753cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 this must not happen.  */
2754cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (!has_copy_reloc (ebl, shdr->sh_link, cnt)
2755cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  && !in_nobits_scn (ebl, sym->st_shndx))
2756cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ERROR (gettext ("\
2757cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': symbol %d: version index %d is for requested version\n"),
2758cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       idx, section_name (ebl, idx), cnt, (int) *versym);
2759cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
2760cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2761cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2762cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2763cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2764cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2765cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int
2766cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengunknown_dependency_p (Elf *elf, GElf_Ehdr *ehdr, const char *fname)
2767cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2768cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Phdr phdr_mem;
2769cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Phdr *phdr = NULL;
2770cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2771cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  int i;
2772cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (i = 0; i < ehdr->e_phnum; ++i)
2773cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if ((phdr = gelf_getphdr (elf, i, &phdr_mem)) != NULL
2774cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	&& phdr->p_type == PT_DYNAMIC)
2775cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
2776cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2777cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (i == ehdr->e_phnum)
2778cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return 1;
2779cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  assert (phdr != NULL);
2780cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Scn *scn = gelf_offscn (elf, phdr->p_offset);
2781cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr shdr_mem;
2782cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
2783cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (scn, NULL);
2784cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC && data != NULL)
2785cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    for (size_t j = 0; j < shdr->sh_size / shdr->sh_entsize; ++j)
2786cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
2787cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Dyn dyn_mem;
2788cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
2789cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (dyn != NULL && dyn->d_tag == DT_NEEDED)
2790cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
2791cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    const char *str = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val);
2792cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (str != NULL && strcmp (str, fname) == 0)
2793cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* Found it.  */
2794cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      return 0;
2795cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
2796cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
2797cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2798cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return 1;
2799cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2800cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2801cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2802cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic unsigned int nverneed;
2803cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2804cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
2805cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_verneed (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
2806cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2807cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (++nverneed == 2)
2808cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("more than one version reference section present\n"));
2809cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2810cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr strshdr_mem;
2811cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2812cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     &strshdr_mem);
2813cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (strshdr == NULL)
2814cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
2815cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (strshdr->sh_type != SHT_STRTAB)
2816cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
2817cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': sh_link does not link to string table\n"),
2818cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
2819cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2820cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
2821cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (data == NULL)
2822cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2823cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
2824cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
2825cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
2826cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2827cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  unsigned int offset = 0;
2828cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (int cnt = shdr->sh_info; --cnt >= 0; )
2829cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2830cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Get the data at the next offset.  */
2831cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Verneed needmem;
2832cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Verneed *need = gelf_getverneed (data, offset, &needmem);
2833cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (need == NULL)
2834cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	break;
2835cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2836cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      unsigned int auxoffset = offset + need->vn_aux;
2837cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2838cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (need->vn_version != EV_CURRENT)
2839cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2840cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has wrong version %d\n"),
2841cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt, (int) need->vn_version);
2842cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2843cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (need->vn_cnt > 0 && need->vn_aux < gelf_fsize (ebl->elf, ELF_T_VNEED,
2844cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng							 1, EV_CURRENT))
2845cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2846cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has wrong offset of auxiliary data\n"),
2847cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
2848cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2849cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *libname = elf_strptr (ebl->elf, shdr->sh_link,
2850cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					need->vn_file);
2851cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (libname == NULL)
2852cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2853cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ERROR (gettext ("\
2854cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has invalid file reference\n"),
2855cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx), cnt);
2856cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  goto next_need;
2857cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2858cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2859cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Check that there is a DT_NEEDED entry for the referenced library.  */
2860cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (unknown_dependency_p (ebl->elf, ehdr, libname))
2861cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2862cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d references unknown dependency\n"),
2863cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
2864cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2865cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (int cnt2 = need->vn_cnt; --cnt2 >= 0; )
2866cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2867cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Vernaux auxmem;
2868cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Vernaux *aux = gelf_getvernaux (data, auxoffset, &auxmem);
2869cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (aux == NULL)
2870cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    break;
2871cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2872cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if ((aux->vna_flags & ~VER_FLG_WEAK) != 0)
2873cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
2874cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': auxiliary entry %d of entry %d has unknown flag\n"),
2875cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), need->vn_cnt - cnt2, cnt);
2876cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2877cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  const char *verstr = elf_strptr (ebl->elf, shdr->sh_link,
2878cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   aux->vna_name);
2879cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (verstr == NULL)
2880cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
2881cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': auxiliary entry %d of entry %d has invalid name reference\n"),
2882cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), need->vn_cnt - cnt2, cnt);
2883cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
2884cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
2885cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Word hashval = elf_hash (verstr);
2886cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (hashval != aux->vna_hash)
2887cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ERROR (gettext ("\
2888cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': auxiliary entry %d of entry %d has wrong hash value: %#x, expected %#x\n"),
2889cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       idx, section_name (ebl, idx), need->vn_cnt - cnt2,
2890cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       cnt, (int) hashval, (int) aux->vna_hash);
2891cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2892cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      int res = add_version (libname, verstr, aux->vna_other,
2893cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     ver_need);
2894cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (unlikely (res !=0))
2895cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
2896cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  assert (res > 0);
2897cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  ERROR (gettext ("\
2898cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': auxiliary entry %d of entry %d has duplicate version name '%s'\n"),
2899cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 idx, section_name (ebl, idx), need->vn_cnt - cnt2,
2900cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 cnt, verstr);
2901cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
2902cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
2903cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2904cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if ((aux->vna_next != 0 || cnt2 > 0)
2905cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && aux->vna_next < gelf_fsize (ebl->elf, ELF_T_VNAUX, 1,
2906cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					     EV_CURRENT))
2907cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
2908cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
2909cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': auxiliary entry %d of entry %d has wrong next field\n"),
2910cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     idx, section_name (ebl, idx), need->vn_cnt - cnt2, cnt);
2911cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      break;
2912cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
2913cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2914cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  auxoffset += MAX (aux->vna_next,
2915cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    gelf_fsize (ebl->elf, ELF_T_VNAUX, 1, EV_CURRENT));
2916cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2917cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2918cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Find the next offset.  */
2919cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    next_need:
2920cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      offset += need->vn_next;
2921cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2922cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if ((need->vn_next != 0 || cnt > 0)
2923cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && offset < auxoffset)
2924cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2925cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has invalid offset to next entry\n"),
2926cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
2927cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2928cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
2929cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2930cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2931cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic unsigned int nverdef;
2932cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2933cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
2934cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_verdef (Ebl *ebl, GElf_Shdr *shdr, int idx)
2935cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
2936cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (++nverdef == 2)
2937cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("more than one version definition section present\n"));
2938cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2939cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr strshdr_mem;
2940cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *strshdr = gelf_getshdr (elf_getscn (ebl->elf, shdr->sh_link),
2941cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     &strshdr_mem);
2942cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (strshdr == NULL)
2943cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
2944cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (strshdr->sh_type != SHT_STRTAB)
2945cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
2946cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': sh_link does not link to string table\n"),
2947cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
2948cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2949cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
2950cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (data == NULL)
2951cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2952cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    no_data:
2953cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
2954cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
2955cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
2956cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
2957cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2958cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Iterate over all version definition entries.  We check that there
2959cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     is a BASE entry and that each index is unique.  To do the later
2960cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     we collection the information in a list which is later
2961cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     examined.  */
2962cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct namelist
2963cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
2964cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    const char *name;
2965cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    struct namelist *next;
2966cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  } *namelist = NULL;
2967cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  struct namelist *refnamelist = NULL;
2968cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2969cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool has_base = false;
2970cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  unsigned int offset = 0;
2971cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (int cnt = shdr->sh_info; --cnt >= 0; )
2972cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
2973cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Get the data at the next offset.  */
2974cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Verdef defmem;
2975cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Verdef *def = gelf_getverdef (data, offset, &defmem);
2976cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (def == NULL)
2977cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	goto no_data;
2978cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2979cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if ((def->vd_flags & VER_FLG_BASE) != 0)
2980cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
2981cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (has_base)
2982cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
2983cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': more than one BASE definition\n"),
2984cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx));
2985cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (def->vd_ndx != VER_NDX_GLOBAL)
2986cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
2987cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': BASE definition must have index VER_NDX_GLOBAL\n"),
2988cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx));
2989cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  has_base = true;
2990cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
2991cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if ((def->vd_flags & ~(VER_FLG_BASE|VER_FLG_WEAK)) != 0)
2992cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2993cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has unknown flag\n"),
2994cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
2995cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
2996cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (def->vd_version != EV_CURRENT)
2997cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
2998cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has wrong version %d\n"),
2999cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt, (int) def->vd_version);
3000cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3001cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (def->vd_cnt > 0 && def->vd_aux < gelf_fsize (ebl->elf, ELF_T_VDEF,
3002cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						       1, EV_CURRENT))
3003cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
3004cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has wrong offset of auxiliary data\n"),
3005cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
3006cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3007cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      unsigned int auxoffset = offset + def->vd_aux;
3008cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Verdaux auxmem;
3009cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Verdaux *aux = gelf_getverdaux (data, auxoffset, &auxmem);
3010cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (aux == NULL)
3011cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	goto no_data;
3012cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3013cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *name = elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name);
3014cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (name == NULL)
3015cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
3016cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ERROR (gettext ("\
3017cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has invalid name reference\n"),
3018cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx), cnt);
3019cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  goto next_def;
3020cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
3021cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      GElf_Word hashval = elf_hash (name);
3022cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (def->vd_hash != hashval)
3023cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
3024cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has wrong hash value: %#x, expected %#x\n"),
3025cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt, (int) hashval,
3026cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       (int) def->vd_hash);
3027cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3028cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      int res = add_version (NULL, name, def->vd_ndx, ver_def);
3029cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (unlikely (res !=0))
3030cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
3031cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  assert (res > 0);
3032cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ERROR (gettext ("\
3033cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has duplicate version name '%s'\n"),
3034cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx), cnt, name);
3035cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
3036cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3037cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      struct namelist *newname = alloca (sizeof (*newname));
3038cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      newname->name = name;
3039cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      newname->next = namelist;
3040cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      namelist = newname;
3041cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3042cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      auxoffset += aux->vda_next;
3043cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (int cnt2 = 1; cnt2 < def->vd_cnt; ++cnt2)
3044cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
3045cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  aux = gelf_getverdaux (data, auxoffset, &auxmem);
3046cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (aux == NULL)
3047cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    goto no_data;
3048cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3049cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  name = elf_strptr (ebl->elf, shdr->sh_link, aux->vda_name);
3050cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (name == NULL)
3051cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
3052cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has invalid name reference in auxiliary data\n"),
3053cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   idx, section_name (ebl, idx), cnt);
3054cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
3055cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
3056cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      newname = alloca (sizeof (*newname));
3057cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      newname->name = name;
3058cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      newname->next = refnamelist;
3059cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      refnamelist = newname;
3060cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
3061cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3062cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if ((aux->vda_next != 0 || cnt2 + 1 < def->vd_cnt)
3063cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && aux->vda_next < gelf_fsize (ebl->elf, ELF_T_VDAUX, 1,
3064cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					     EV_CURRENT))
3065cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
3066cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
3067cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has wrong next field in auxiliary data\n"),
3068cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     idx, section_name (ebl, idx), cnt);
3069cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      break;
3070cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
3071cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3072cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  auxoffset += MAX (aux->vda_next,
3073cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    gelf_fsize (ebl->elf, ELF_T_VDAUX, 1, EV_CURRENT));
3074cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
3075cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3076cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Find the next offset.  */
3077cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    next_def:
3078cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      offset += def->vd_next;
3079cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3080cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if ((def->vd_next != 0 || cnt > 0)
3081cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && offset < auxoffset)
3082cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
3083cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': entry %d has invalid offset to next entry\n"),
3084cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), cnt);
3085cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
3086cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3087cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (!has_base)
3088cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("section [%2d] '%s': no BASE definition\n"),
3089cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
3090cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3091cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Check whether the referenced names are available.  */
3092cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (namelist != NULL)
3093cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
3094cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      struct version_namelist *runp = version_namelist;
3095cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      while (runp != NULL)
3096cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
3097cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (runp->type == ver_def
3098cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && strcmp (runp->name, namelist->name) == 0)
3099cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    break;
3100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  runp = runp->next;
3101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
3102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (runp == NULL)
3104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
3105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': unknown parent version '%s'\n"),
3106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), namelist->name);
3107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      namelist = namelist->next;
3109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
3110cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
3111cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3112cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
3113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_attributes (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
3114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
3115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr->sh_size == 0)
3116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
3117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': empty object attributes section\n"),
3118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
3119cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
3120cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
3121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_rawdata (elf_getscn (ebl->elf, idx), NULL);
3123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (data == NULL || data->d_size == 0)
3124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
3125cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
3126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
3127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
3128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
3129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  inline size_t pos (const unsigned char *p)
3131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
3132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return p - (const unsigned char *) data->d_buf;
3133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  }
3134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const unsigned char *p = data->d_buf;
3136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (*p++ != 'A')
3137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
3138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': unrecognized attribute format\n"),
3139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
3140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
3141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
3142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3143cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  inline size_t left (void)
3144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
3145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return (const unsigned char *) data->d_buf + data->d_size - p;
3146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  }
3147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (left () >= 4)
3149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
3150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      uint32_t len;
3151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      memcpy (&len, p, sizeof len);
3152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3153cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (len == 0)
3154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
3155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: zero length field in attribute section\n"),
3156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), pos (p));
3157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
3159cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	CONVERT (len);
3160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (len > left ())
3162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
3163cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ERROR (gettext ("\
3164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: invalid length in attribute section\n"),
3165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx), pos (p));
3166cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  break;
3167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
3168cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const unsigned char *name = p + sizeof len;
3170cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      p += len;
3171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3172cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      unsigned const char *q = memchr (name, '\0', len);
3173cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (q == NULL)
3174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
3175cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ERROR (gettext ("\
3176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: unterminated vendor name string\n"),
3177cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 idx, section_name (ebl, idx), pos (p));
3178cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  continue;
3179cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
3180cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ++q;
3181cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (q - name == sizeof "gnu" && !memcmp (name, "gnu", sizeof "gnu"))
3183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	while (q < p)
3184cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
3185cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    unsigned const char *chunk = q;
3186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3187cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    unsigned int subsection_tag;
3188cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    get_uleb128 (subsection_tag, q);
3189cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (q >= p)
3191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      {
3192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ERROR (gettext ("\
3193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: endless ULEB128 in attribute subsection tag\n"),
3194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       idx, section_name (ebl, idx), pos (chunk));
3195cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		break;
3196cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      }
3197cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3198cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    uint32_t subsection_len;
3199cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (p - q < (ptrdiff_t) sizeof subsection_len)
3200cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      {
3201cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ERROR (gettext ("\
3202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: truncated attribute section\n"),
3203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       idx, section_name (ebl, idx), pos (q));
3204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		break;
3205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      }
3206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3207cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    memcpy (&subsection_len, q, sizeof subsection_len);
3208cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (subsection_len == 0)
3209cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      {
3210cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ERROR (gettext ("\
3211cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: zero length field in attribute subsection\n"),
3212cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       idx, section_name (ebl, idx), pos (q));
3213cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3214cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		q += sizeof subsection_len;
3215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		continue;
3216cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      }
3217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3218cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (MY_ELFDATA != ehdr->e_ident[EI_DATA])
3219cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      CONVERT (subsection_len);
3220cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3221cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (p - chunk < (ptrdiff_t) subsection_len)
3222cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      {
3223cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ERROR (gettext ("\
3224cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: invalid length in attribute subsection\n"),
3225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       idx, section_name (ebl, idx), pos (q));
3226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		break;
3227cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      }
3228cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    const unsigned char *subsection_end = chunk + subsection_len;
3230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    chunk = q;
3231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    q = subsection_end;
3232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (subsection_tag != 1) /* Tag_File */
3234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
3235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: attribute subsection has unexpected tag %u\n"),
3236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     idx, section_name (ebl, idx), pos (chunk), subsection_tag);
3237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    else
3238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      {
3239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		chunk += sizeof subsection_len;
3240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		while (chunk < q)
3241cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  {
3242cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    unsigned int tag;
3243cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    get_uleb128 (tag, chunk);
3244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3245cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    uint64_t value = 0;
3246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    const unsigned char *r = chunk;
3247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    if (tag == 32 || (tag & 1) == 0)
3248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      {
3249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			get_uleb128 (value, r);
3250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			if (r > q)
3251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  {
3252cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    ERROR (gettext ("\
3253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: endless ULEB128 in attribute tag\n"),
3254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   idx, section_name (ebl, idx), pos (chunk));
3255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    break;
3256cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  }
3257cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      }
3258cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    if (tag == 32 || (tag & 1) != 0)
3259cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      {
3260cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			r = memchr (r, '\0', q - r);
3261cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			if (r == NULL)
3262cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  {
3263cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    ERROR (gettext ("\
3264cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: unterminated string in attribute\n"),
3265cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				   idx, section_name (ebl, idx), pos (chunk));
3266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    break;
3267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  }
3268cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			++r;
3269cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      }
3270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    const char *tag_name = NULL;
3272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    const char *value_name = NULL;
3273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    if (!ebl_check_object_attribute (ebl, (const char *) name,
3274cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						     tag, value,
3275cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						     &tag_name, &value_name))
3276cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      ERROR (gettext ("\
3277cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: unrecognized attribute tag %u\n"),
3278cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     idx, section_name (ebl, idx), pos (chunk), tag);
3279cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    else if ((tag & 1) == 0 && value_name == NULL)
3280cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      ERROR (gettext ("\
3281cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: unrecognized %s attribute value %" PRIu64 "\n"),
3282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     idx, section_name (ebl, idx), pos (chunk),
3283cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     tag_name, value);
3284cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3285cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    chunk = r;
3286cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  }
3287cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      }
3288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
3289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
3290cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("\
3291cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: vendor '%s' unknown\n"),
3292cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       idx, section_name (ebl, idx), pos (p), name);
3293cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
3294441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3295cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (left () != 0)
3296cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
3297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': offset %zu: extra bytes after last attribute section\n"),
3298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), pos (p));
3299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
3300441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3301441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic bool has_loadable_segment;
3302441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic bool has_interp_segment;
3303441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3304441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic const struct
3305441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
3306441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  const char *name;
3307441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  size_t namelen;
3308441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Word type;
3309cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  enum { unused, exact, atleast, exact_or_gnuld } attrflag;
3310441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Word attr;
3311441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Word attr2;
3312441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project} special_sections[] =
3313441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  {
3314441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    /* See figure 4-14 in the gABI.  */
3315441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".bss", 5, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE, 0 },
3316441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".comment", 8, SHT_PROGBITS, exact, 0, 0 },
3317441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".data", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 },
3318441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".data1", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 },
3319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    { ".debug_str", 11, SHT_PROGBITS, exact_or_gnuld, SHF_MERGE | SHF_STRINGS, 0 },
3320cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    { ".debug", 6, SHT_PROGBITS, exact, 0, 0 },
3321441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".dynamic", 9, SHT_DYNAMIC, atleast, SHF_ALLOC, SHF_WRITE },
3322441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".dynstr", 8, SHT_STRTAB, exact, SHF_ALLOC, 0 },
3323441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".dynsym", 8, SHT_DYNSYM, exact, SHF_ALLOC, 0 },
3324441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".fini", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 },
3325441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".fini_array", 12, SHT_FINI_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 },
3326441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".got", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more info?
3327441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".hash", 6, SHT_HASH, exact, SHF_ALLOC, 0 },
3328441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".init", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 },
3329441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".init_array", 12, SHT_INIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 },
3330441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".interp", 8, SHT_PROGBITS, atleast, 0, SHF_ALLOC }, // XXX more tests?
3331441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".line", 6, SHT_PROGBITS, exact, 0, 0 },
3332cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    { ".note", 6, SHT_NOTE, atleast, 0, SHF_ALLOC },
3333441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".plt", 5, SHT_PROGBITS, unused, 0, 0 }, // XXX more tests
3334441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".preinit_array", 15, SHT_PREINIT_ARRAY, exact, SHF_ALLOC | SHF_WRITE, 0 },
3335441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".rela", 5, SHT_RELA, atleast, 0, SHF_ALLOC }, // XXX more tests
3336441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".rel", 4, SHT_REL, atleast, 0, SHF_ALLOC }, // XXX more tests
3337cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    { ".rodata", 8, SHT_PROGBITS, atleast, SHF_ALLOC, SHF_MERGE | SHF_STRINGS },
3338cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    { ".rodata1", 9, SHT_PROGBITS, atleast, SHF_ALLOC, SHF_MERGE | SHF_STRINGS },
3339441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".shstrtab", 10, SHT_STRTAB, exact, 0, 0 },
3340441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".strtab", 8, SHT_STRTAB, atleast, 0, SHF_ALLOC }, // XXX more tests
3341441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".symtab", 8, SHT_SYMTAB, atleast, 0, SHF_ALLOC }, // XXX more tests
3342441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".symtab_shndx", 14, SHT_SYMTAB_SHNDX, atleast, 0, SHF_ALLOC }, // XXX more tests
3343441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".tbss", 6, SHT_NOBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 },
3344441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".tdata", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 },
3345441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    { ".tdata1", 8, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE | SHF_TLS, 0 },
3346cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    { ".text", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_EXECINSTR, 0 },
3347cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3348cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* The following are GNU extensions.  */
3349cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    { ".gnu.version", 13, SHT_GNU_versym, exact, SHF_ALLOC, 0 },
3350cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    { ".gnu.version_d", 15, SHT_GNU_verdef, exact, SHF_ALLOC, 0 },
3351cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    { ".gnu.version_r", 15, SHT_GNU_verneed, exact, SHF_ALLOC, 0 },
3352cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    { ".gnu.attributes", 16, SHT_GNU_ATTRIBUTES, exact, 0, 0 },
3353441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  };
3354441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#define nspecial_sections \
3355441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  (sizeof (special_sections) / sizeof (special_sections[0]))
3356441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3357cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define IS_KNOWN_SPECIAL(idx, string, prefix)			      \
3358cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  (special_sections[idx].namelen == sizeof string - (prefix ? 1 : 0)  \
3359cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   && !memcmp (special_sections[idx].name, string, \
3360cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       sizeof string - (prefix ? 1 : 0)))
3361441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3362441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
3363441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectcheck_sections (Ebl *ebl, GElf_Ehdr *ehdr)
3364441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
3365441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_shoff == 0)
3366441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    /* No section header.  */
3367441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    return;
3368441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3369441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Allocate array to count references in section groups.  */
3370441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  scnref = (int *) xcalloc (shnum, sizeof (int));
3371441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3372441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check the zeroth section first.  It must not have any contents
3373441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     and the section header must contain nonzero value at most in the
3374441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     sh_size and sh_link fields.  */
3375cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr shdr_mem;
3376cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Shdr *shdr = gelf_getshdr (elf_getscn (ebl->elf, 0), &shdr_mem);
3377441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (shdr == NULL)
3378441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("cannot get section header of zeroth section\n"));
3379441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  else
3380441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
3381441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_name != 0)
3382441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("zeroth section has nonzero name\n"));
3383441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_type != 0)
3384441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("zeroth section has nonzero type\n"));
3385441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_flags != 0)
3386441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("zeroth section has nonzero flags\n"));
3387441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_addr != 0)
3388441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("zeroth section has nonzero address\n"));
3389441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_offset != 0)
3390441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("zeroth section has nonzero offset\n"));
3391441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_info != 0)
3392441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("zeroth section has nonzero info field\n"));
3393441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_addralign != 0)
3394441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("zeroth section has nonzero align value\n"));
3395441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_entsize != 0)
3396441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("zeroth section has nonzero entry size value\n"));
3397441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3398441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_size != 0 && ehdr->e_shnum != 0)
3399441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
3400441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectzeroth section has nonzero size value while ELF header has nonzero shnum value\n"));
3401441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3402441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_link != 0 && ehdr->e_shstrndx != SHN_XINDEX)
3403441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
3404441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectzeroth section has nonzero link value while ELF header does not signal overflow in shstrndx\n"));
3405441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
3406441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3407cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  int *segment_flags = xcalloc (ehdr->e_phnum, sizeof segment_flags[0]);
3408441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3409cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool dot_interp_section = false;
3410cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3411cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t hash_idx = 0;
3412cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t gnu_hash_idx = 0;
3413cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3414cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t versym_scnndx = 0;
3415cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  for (size_t cnt = 1; cnt < shnum; ++cnt)
3416cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
3417cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      shdr = gelf_getshdr (elf_getscn (ebl->elf, cnt), &shdr_mem);
3418441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr == NULL)
3419441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
3420441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  ERROR (gettext ("\
3421441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectcannot get section header for section [%2zu] '%s': %s\n"),
3422cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 cnt, section_name (ebl, cnt), elf_errmsg (-1));
3423441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  continue;
3424441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
3425441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3426441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      const char *scnname = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
3427441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3428441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (scnname == NULL)
3429441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("section [%2zu]: invalid name\n"), cnt);
3430441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
3431441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
3432441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* Check whether it is one of the special sections defined in
3433441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	     the gABI.  */
3434441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  size_t s;
3435441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  for (s = 0; s < nspecial_sections; ++s)
3436441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    if (strncmp (scnname, special_sections[s].name,
3437441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			 special_sections[s].namelen) == 0)
3438441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      {
3439441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		char stbuf1[100];
3440441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		char stbuf2[100];
3441441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		char stbuf3[100];
3442441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3443cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		GElf_Word good_type = special_sections[s].type;
3444cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		if (IS_KNOWN_SPECIAL (s, ".plt", false)
3445cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    && ebl_bss_plt_p (ebl, ehdr))
3446cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  good_type = SHT_NOBITS;
3447cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3448cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		/* In a debuginfo file, any normal section can be SHT_NOBITS.
3449cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   This is only invalid for DWARF sections and .shstrtab.  */
3450cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		if (shdr->sh_type != good_type
3451cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    && (shdr->sh_type != SHT_NOBITS
3452cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			|| !is_debuginfo
3453cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			|| IS_KNOWN_SPECIAL (s, ".debug_str", false)
3454cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			|| IS_KNOWN_SPECIAL (s, ".debug", true)
3455cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			|| IS_KNOWN_SPECIAL (s, ".shstrtab", false)))
3456441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  ERROR (gettext ("\
3457441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2d] '%s' has wrong type: expected %s, is %s\n"),
3458441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			 (int) cnt, scnname,
3459441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			 ebl_section_type_name (ebl, special_sections[s].type,
3460441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						stbuf1, sizeof (stbuf1)),
3461441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			 ebl_section_type_name (ebl, shdr->sh_type,
3462441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						stbuf2, sizeof (stbuf2)));
3463441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3464cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		if (special_sections[s].attrflag == exact
3465cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    || special_sections[s].attrflag == exact_or_gnuld)
3466441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  {
3467441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    /* Except for the link order and group bit all the
3468441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       other bits should match exactly.  */
3469441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    if ((shdr->sh_flags & ~(SHF_LINK_ORDER | SHF_GROUP))
3470cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			!= special_sections[s].attr
3471cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			&& (special_sections[s].attrflag == exact || !gnuld))
3472441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      ERROR (gettext ("\
3473441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s' has wrong flags: expected %s, is %s\n"),
3474441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     cnt, scnname,
3475441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     section_flags_string (special_sections[s].attr,
3476441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						   stbuf1, sizeof (stbuf1)),
3477441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     section_flags_string (shdr->sh_flags
3478441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						   & ~SHF_LINK_ORDER,
3479441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						   stbuf2, sizeof (stbuf2)));
3480441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  }
3481441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		else if (special_sections[s].attrflag == atleast)
3482441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  {
3483441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    if ((shdr->sh_flags & special_sections[s].attr)
3484441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			!= special_sections[s].attr
3485441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			|| ((shdr->sh_flags & ~(SHF_LINK_ORDER | SHF_GROUP
3486441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						| special_sections[s].attr
3487441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						| special_sections[s].attr2))
3488441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			    != 0))
3489441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      ERROR (gettext ("\
3490441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s' has wrong flags: expected %s and possibly %s, is %s\n"),
3491441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     cnt, scnname,
3492441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     section_flags_string (special_sections[s].attr,
3493441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						   stbuf1, sizeof (stbuf1)),
3494441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     section_flags_string (special_sections[s].attr2,
3495441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						   stbuf2, sizeof (stbuf2)),
3496441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     section_flags_string (shdr->sh_flags
3497441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						   & ~(SHF_LINK_ORDER
3498441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						       | SHF_GROUP),
3499441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						   stbuf3, sizeof (stbuf3)));
3500441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  }
3501441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3502441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		if (strcmp (scnname, ".interp") == 0)
3503441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  {
3504441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    dot_interp_section = true;
3505441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3506441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    if (ehdr->e_type == ET_REL)
3507441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      ERROR (gettext ("\
3508441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s' present in object file\n"),
3509441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     cnt, scnname);
3510441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3511441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    if ((shdr->sh_flags & SHF_ALLOC) != 0
3512441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			&& !has_loadable_segment)
3513441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      ERROR (gettext ("\
3514441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s' has SHF_ALLOC flag set but there is no loadable segment\n"),
3515441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     cnt, scnname);
3516441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    else if ((shdr->sh_flags & SHF_ALLOC) == 0
3517441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     && has_loadable_segment)
3518441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      ERROR (gettext ("\
3519441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s' has SHF_ALLOC flag not set but there are loadable segments\n"),
3520441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     cnt, scnname);
3521441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  }
3522441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		else
3523441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  {
3524441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    if (strcmp (scnname, ".symtab_shndx") == 0
3525441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			&& ehdr->e_type != ET_REL)
3526441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      ERROR (gettext ("\
3527441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s' is extension section index table in non-object file\n"),
3528441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     cnt, scnname);
3529441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3530441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    /* These sections must have the SHF_ALLOC flag set iff
3531441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       a loadable segment is available.
3532441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3533441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       .relxxx
3534441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       .strtab
3535441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       .symtab
3536441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       .symtab_shndx
3537441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3538441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       Check that if there is a reference from the
3539441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       loaded section these sections also have the
3540441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       ALLOC flag set.  */
3541441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#if 0
3542441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    // XXX TODO
3543441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    if ((shdr->sh_flags & SHF_ALLOC) != 0
3544441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			&& !has_loadable_segment)
3545441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      ERROR (gettext ("\
3546441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s' has SHF_ALLOC flag set but there is no loadable segment\n"),
3547441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     cnt, scnname);
3548441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    else if ((shdr->sh_flags & SHF_ALLOC) == 0
3549441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     && has_loadable_segment)
3550441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      ERROR (gettext ("\
3551441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s' has SHF_ALLOC flag not set but there are loadable segments\n"),
3552441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			     cnt, scnname);
3553441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#endif
3554441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  }
3555441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3556441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		break;
3557441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      }
3558441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
3559441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3560441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_entsize != 0 && shdr->sh_size % shdr->sh_entsize)
3561441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
3562441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s': size not multiple of entry size\n"),
3563cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       cnt, section_name (ebl, cnt));
3564441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3565441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (elf_strptr (ebl->elf, shstrndx, shdr->sh_name) == NULL)
3566441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("cannot get section header\n"));
3567441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3568441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_type >= SHT_NUM
3569cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && shdr->sh_type != SHT_GNU_ATTRIBUTES
3570441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && shdr->sh_type != SHT_GNU_LIBLIST
3571441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && shdr->sh_type != SHT_CHECKSUM
3572441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && shdr->sh_type != SHT_GNU_verdef
3573441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && shdr->sh_type != SHT_GNU_verneed
3574cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && shdr->sh_type != SHT_GNU_versym
3575cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && ebl_section_type_name (ebl, shdr->sh_type, NULL, 0) == NULL)
3576cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	ERROR (gettext ("section [%2zu] '%s' has unsupported type %d\n"),
3577cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       cnt, section_name (ebl, cnt),
3578cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       (int) shdr->sh_type);
3579441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3580441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#define ALL_SH_FLAGS (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR | SHF_MERGE \
3581441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      | SHF_STRINGS | SHF_INFO_LINK | SHF_LINK_ORDER \
3582441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      | SHF_OS_NONCONFORMING | SHF_GROUP | SHF_TLS)
3583cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (shdr->sh_flags & ~(GElf_Xword) ALL_SH_FLAGS)
3584cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
3585cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Xword sh_flags = shdr->sh_flags & ~(GElf_Xword) ALL_SH_FLAGS;
3586cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (sh_flags & SHF_MASKPROC)
3587cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
3588cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (!ebl_machine_section_flag_check (ebl,
3589cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						   sh_flags & SHF_MASKPROC))
3590cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		ERROR (gettext ("section [%2zu] '%s'"
3591cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				" contains invalid processor-specific flag(s)"
3592cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				" %#" PRIx64 "\n"),
3593cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		       cnt, section_name (ebl, cnt), sh_flags & SHF_MASKPROC);
3594cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      sh_flags &= ~(GElf_Xword) SHF_MASKPROC;
3595cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
3596cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (sh_flags != 0)
3597cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("section [%2zu] '%s' contains unknown flag(s)"
3598cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    " %#" PRIx64 "\n"),
3599cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   cnt, section_name (ebl, cnt), sh_flags);
3600cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
3601cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (shdr->sh_flags & SHF_TLS)
3602441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
3603441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  // XXX Correct?
3604441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (shdr->sh_addr != 0 && !gnuld)
3605441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
3606441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s': thread-local data sections address not zero\n"),
3607cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   cnt, section_name (ebl, cnt));
3608441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3609441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  // XXX TODO more tests!?
3610441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
3611441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3612441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_link >= shnum)
3613441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
3614441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s': invalid section reference in link value\n"),
3615cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       cnt, section_name (ebl, cnt));
3616441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3617441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (SH_INFO_LINK_P (shdr) && shdr->sh_info >= shnum)
3618441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
3619441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s': invalid section reference in info value\n"),
3620cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       cnt, section_name (ebl, cnt));
3621441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3622441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if ((shdr->sh_flags & SHF_MERGE) == 0
3623441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && (shdr->sh_flags & SHF_STRINGS) != 0
3624441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && be_strict)
3625441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
3626441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s': strings flag set without merge flag\n"),
3627cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       cnt, section_name (ebl, cnt));
3628441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3629441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if ((shdr->sh_flags & SHF_MERGE) != 0 && shdr->sh_entsize == 0)
3630441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
3631441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s': merge flag set but entry size is zero\n"),
3632cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       cnt, section_name (ebl, cnt));
3633441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3634441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (shdr->sh_flags & SHF_GROUP)
3635cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	check_scn_group (ebl, cnt);
3636cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3637cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (shdr->sh_flags & SHF_EXECINSTR)
3638cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
3639cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  switch (shdr->sh_type)
3640cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
3641cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    case SHT_PROGBITS:
3642cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      break;
3643cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3644cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    case SHT_NOBITS:
3645cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (is_debuginfo)
3646cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		break;
3647cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    default:
3648cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
3649cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2zu] '%s' has unexpected type %d for an executable section\n"),
3650cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     cnt, section_name (ebl, cnt), shdr->sh_type);
3651cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      break;
3652cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
3653cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3654cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if ((shdr->sh_flags & SHF_WRITE)
3655cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      && !ebl_check_special_section (ebl, cnt, shdr,
3656cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					     section_name (ebl, cnt)))
3657cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
3658cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2zu] '%s' is both executable and writable\n"),
3659cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   cnt, section_name (ebl, cnt));
3660cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
3661441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3662441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_type != ET_REL && (shdr->sh_flags & SHF_ALLOC) != 0)
3663441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
3664441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* Make sure the section is contained in a loaded segment
3665441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	     and that the initialization part matches NOBITS sections.  */
3666441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  int pcnt;
3667441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  GElf_Phdr phdr_mem;
3668441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  GElf_Phdr *phdr;
3669441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3670441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  for (pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt)
3671441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    if ((phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem)) != NULL
3672441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		&& ((phdr->p_type == PT_LOAD
3673441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		     && (shdr->sh_flags & SHF_TLS) == 0)
3674441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    || (phdr->p_type == PT_TLS
3675441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			&& (shdr->sh_flags & SHF_TLS) != 0))
3676441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		&& phdr->p_offset <= shdr->sh_offset
3677cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		&& (phdr->p_offset + phdr->p_filesz > shdr->sh_offset
3678cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    || (phdr->p_offset + phdr->p_memsz > shdr->sh_offset
3679cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			&& shdr->sh_type == SHT_NOBITS)))
3680441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      {
3681441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		/* Found the segment.  */
3682441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		if (phdr->p_offset + phdr->p_memsz
3683441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    < shdr->sh_offset + shdr->sh_size)
3684441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  ERROR (gettext ("\
3685441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s' not fully contained in segment of program header entry %d\n"),
3686cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 cnt, section_name (ebl, cnt), pcnt);
3687441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3688441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		if (shdr->sh_type == SHT_NOBITS)
3689441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  {
3690cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    if (shdr->sh_offset < phdr->p_offset + phdr->p_filesz
3691cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			&& !is_debuginfo)
3692441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      ERROR (gettext ("\
3693441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s' has type NOBITS but is read from the file in segment of program header entry %d\n"),
3694cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 cnt, section_name (ebl, cnt), pcnt);
3695441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  }
3696441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		else
3697441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  {
3698cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    const GElf_Off end = phdr->p_offset + phdr->p_filesz;
3699cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    if (shdr->sh_offset > end ||
3700cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			(shdr->sh_offset == end && shdr->sh_size != 0))
3701441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      ERROR (gettext ("\
3702441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s' has not type NOBITS but is not read from the file in segment of program header entry %d\n"),
3703cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 cnt, section_name (ebl, cnt), pcnt);
3704cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  }
3705cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3706cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		if (shdr->sh_type != SHT_NOBITS)
3707cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  {
3708cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    if ((shdr->sh_flags & SHF_EXECINSTR) != 0)
3709cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      {
3710cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			segment_flags[pcnt] |= PF_X;
3711cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			if ((phdr->p_flags & PF_X) == 0)
3712cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  ERROR (gettext ("\
3713cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2zu] '%s' is executable in nonexecutable segment %d\n"),
3714cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				 cnt, section_name (ebl, cnt), pcnt);
3715cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      }
3716cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3717cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    if ((shdr->sh_flags & SHF_WRITE) != 0)
3718cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      {
3719cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			segment_flags[pcnt] |= PF_W;
3720cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			if (0	/* XXX vdso images have this */
3721cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    && (phdr->p_flags & PF_W) == 0)
3722cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  ERROR (gettext ("\
3723cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2zu] '%s' is writable in unwritable segment %d\n"),
3724cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				 cnt, section_name (ebl, cnt), pcnt);
3725cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      }
3726441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  }
3727441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3728441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		break;
3729441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      }
3730441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3731441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (pcnt == ehdr->e_phnum)
3732441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
3733441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s': alloc flag set but section not in any loaded segment\n"),
3734cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   cnt, section_name (ebl, cnt));
3735441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
3736441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3737441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (cnt == shstrndx && shdr->sh_type != SHT_STRTAB)
3738441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
3739441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectsection [%2zu] '%s': ELF header says this is the section header string table but type is not SHT_TYPE\n"),
3740cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       cnt, section_name (ebl, cnt));
3741441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3742441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      switch (shdr->sh_type)
3743441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
3744441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	case SHT_DYNSYM:
3745cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (ehdr->e_type == ET_REL)
3746cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
3747cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2zu] '%s': relocatable files cannot have dynamic symbol tables\n"),
3748cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   cnt, section_name (ebl, cnt));
3749cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* FALLTHROUGH */
3750cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case SHT_SYMTAB:
3751cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_symtab (ebl, ehdr, shdr, cnt);
3752441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
3753441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3754441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	case SHT_RELA:
3755cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_rela (ebl, ehdr, shdr, cnt);
3756441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
3757441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3758441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	case SHT_REL:
3759cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_rel (ebl, ehdr, shdr, cnt);
3760441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
3761441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3762441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	case SHT_DYNAMIC:
3763cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_dynamic (ebl, ehdr, shdr, cnt);
3764441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
3765441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3766441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	case SHT_SYMTAB_SHNDX:
3767cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_symtab_shndx (ebl, ehdr, shdr, cnt);
3768441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
3769441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3770441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	case SHT_HASH:
3771cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_hash (shdr->sh_type, ebl, ehdr, shdr, cnt);
3772cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  hash_idx = cnt;
3773cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  break;
3774cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3775cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case SHT_GNU_HASH:
3776cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_hash (shdr->sh_type, ebl, ehdr, shdr, cnt);
3777cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  gnu_hash_idx = cnt;
3778441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
3779441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3780441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	case SHT_NULL:
3781cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_null (ebl, shdr, cnt);
3782441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
3783441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3784441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	case SHT_GROUP:
3785441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  check_group (ebl, ehdr, shdr, cnt);
3786441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
3787441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3788cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case SHT_NOTE:
3789cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_note_section (ebl, ehdr, shdr, cnt);
3790cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  break;
3791cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3792441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	case SHT_GNU_versym:
3793cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* We cannot process this section now since we have no guarantee
3794cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     that the verneed and verdef sections have already been read.
3795cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     Just remember the section index.  */
3796cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (versym_scnndx != 0)
3797cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("more than one version symbol table present\n"));
3798cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  versym_scnndx = cnt;
3799cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  break;
3800cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3801cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case SHT_GNU_verneed:
3802cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_verneed (ebl, ehdr, shdr, cnt);
3803cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  break;
3804cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3805cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case SHT_GNU_verdef:
3806cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_verdef (ebl, shdr, cnt);
3807cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  break;
3808cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3809cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	case SHT_GNU_ATTRIBUTES:
3810cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  check_attributes (ebl, ehdr, shdr, cnt);
3811441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
3812441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3813441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	default:
3814441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* Nothing.  */
3815441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
3816441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
3817441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
3818441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3819441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (has_interp_segment && !dot_interp_section)
3820441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("INTERP program header entry but no .interp section\n"));
3821441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3822cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (!is_debuginfo)
3823cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    for (int pcnt = 0; pcnt < ehdr->e_phnum; ++pcnt)
3824cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
3825cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Phdr phdr_mem;
3826cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	GElf_Phdr *phdr = gelf_getphdr (ebl->elf, pcnt, &phdr_mem);
3827cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (phdr != NULL && (phdr->p_type == PT_LOAD || phdr->p_type == PT_TLS))
3828cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
3829cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if ((phdr->p_flags & PF_X) != 0
3830cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		&& (segment_flags[pcnt] & PF_X) == 0)
3831cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
3832cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengloadable segment [%u] is executable but contains no executable sections\n"),
3833cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     pcnt);
3834441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3835cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if ((phdr->p_flags & PF_W) != 0
3836cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		&& (segment_flags[pcnt] & PF_W) == 0)
3837cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
3838cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengloadable segment [%u] is writable but contains no writable sections\n"),
3839cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     pcnt);
3840cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
3841cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
3842441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3843cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  free (segment_flags);
3844441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3845cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (version_namelist != NULL)
3846441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
3847cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (versym_scnndx == 0)
3848cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
3849cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengno .gnu.versym section present but .gnu.versym_d or .gnu.versym_r section exist\n"));
3850cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
3851cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	check_versym (ebl, versym_scnndx);
3852441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3853cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Check for duplicate index numbers.  */
3854cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      do
3855441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
3856cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  struct version_namelist *runp = version_namelist->next;
3857cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  while (runp != NULL)
3858441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
3859cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (version_namelist->ndx == runp->ndx)
3860cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
3861cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  ERROR (gettext ("duplicate version index %d\n"),
3862cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			 (int) version_namelist->ndx);
3863cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  break;
3864cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
3865cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      runp = runp->next;
3866441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
3867cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3868cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  struct version_namelist *old = version_namelist;
3869cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  version_namelist = version_namelist->next;
3870cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  free (old);
3871441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
3872cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      while (version_namelist != NULL);
3873cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
3874cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else if (versym_scnndx != 0)
3875cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
3876cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng.gnu.versym section present without .gnu.versym_d or .gnu.versym_r\n"));
3877441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3878cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (hash_idx != 0 && gnu_hash_idx != 0)
3879cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    compare_hash_gnu_hash (ebl, ehdr, hash_idx, gnu_hash_idx);
3880441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3881cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  free (scnref);
3882cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
3883441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3884cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3885cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic GElf_Off
3886cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_note_data (Ebl *ebl, const GElf_Ehdr *ehdr,
3887cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 Elf_Data *data, int shndx, int phndx, GElf_Off start)
3888cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
3889cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t offset = 0;
3890cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t last_offset = 0;
3891cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Nhdr nhdr;
3892cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t name_offset;
3893cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t desc_offset;
3894cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (offset < data->d_size
3895cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 && (offset = gelf_getnote (data, offset,
3896cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				    &nhdr, &name_offset, &desc_offset)) > 0)
3897cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
3898cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      last_offset = offset;
3899441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3900441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* Make sure it is one of the note types we know about.  */
3901441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ehdr->e_type == ET_CORE)
3902cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	switch (nhdr.n_type)
3903cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
3904cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_PRSTATUS:
3905cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_FPREGSET:
3906cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_PRPSINFO:
3907cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_TASKSTRUCT:		/* NT_PRXREG on Solaris.  */
3908cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_PLATFORM:
3909cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_AUXV:
3910cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_GWINDOWS:
3911cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_ASRS:
3912cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_PSTATUS:
3913cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_PSINFO:
3914cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_PRCRED:
3915cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_UTSNAME:
3916cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_LWPSTATUS:
3917cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_LWPSINFO:
3918cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_PRFPXREG:
3919cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    /* Known type.  */
3920cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    break;
3921cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3922cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  default:
3923cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (shndx == 0)
3924cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
3925cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengphdr[%d]: unknown core file note type %" PRIu32 " at offset %" PRIu64 "\n"),
3926cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     phndx, (uint32_t) nhdr.n_type, start + offset);
3927cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    else
3928cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
3929cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': unknown core file note type %" PRIu32
3930cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      " at offset %Zu\n"),
3931cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     shndx, section_name (ebl, shndx),
3932cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     (uint32_t) nhdr.n_type, offset);
3933cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
3934cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
3935cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	switch (nhdr.n_type)
3936cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  {
3937cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_GNU_ABI_TAG:
3938cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_GNU_HWCAP:
3939cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case NT_GNU_BUILD_ID:
3940cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    break;
3941cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3942cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  case 0:
3943cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    /* Linux vDSOs use a type 0 note for the kernel version word.  */
3944cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (nhdr.n_namesz == sizeof "Linux"
3945cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		&& !memcmp (data->d_buf + name_offset, "Linux", sizeof "Linux"))
3946441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      break;
3947441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3948cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  default:
3949cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    if (shndx == 0)
3950441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      ERROR (gettext ("\
3951cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengphdr[%d]: unknown object file note type %" PRIu32 " at offset %Zu\n"),
3952cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     phndx, (uint32_t) nhdr.n_type, offset);
3953cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    else
3954cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ERROR (gettext ("\
3955cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': unknown object file note type %" PRIu32
3956cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      " at offset %Zu\n"),
3957cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     shndx, section_name (ebl, shndx),
3958cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		     (uint32_t) nhdr.n_type, offset);
3959cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  }
3960cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
3961441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3962cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return last_offset;
3963cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
3964441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3965cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
3966cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_note (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Phdr *phdr, int cnt)
3967cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
3968cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL
3969cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
3970cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
3971cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengphdr[%d]: no note entries defined for the type of file\n"),
3972cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   cnt);
3973cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3974cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (is_debuginfo)
3975cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* The p_offset values in a separate debug file are bogus.  */
3976cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
3977cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3978cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (phdr->p_filesz == 0)
3979cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
3980441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3981cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Off notes_size = 0;
3982cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata_rawchunk (ebl->elf,
3983cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 phdr->p_offset, phdr->p_filesz,
3984cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					 ELF_T_NHDR);
3985cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (data != NULL)
3986cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    notes_size = check_note_data (ebl, ehdr, data, 0, cnt, phdr->p_offset);
3987cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
3988cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (notes_size == 0)
3989cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("phdr[%d]: cannot get content of note section: %s\n"),
3990cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   cnt, elf_errmsg (-1));
3991cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else if (notes_size != phdr->p_filesz)
3992cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("phdr[%d]: extra %" PRIu64 " bytes after last note\n"),
3993cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   cnt, phdr->p_filesz - notes_size);
3994441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
3995441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
3996cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic void
3997cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_note_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
3998cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
3999cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (shdr->sh_size == 0)
4000cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return;
4001cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
4002cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
4003cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (data == NULL)
4004cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
4005cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ERROR (gettext ("section [%2d] '%s': cannot get section data\n"),
4006cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
4007cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return;
4008cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
4009cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
4010cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (ehdr->e_type != ET_CORE && ehdr->e_type != ET_REL
4011cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
4012cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("\
4013cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengsection [%2d] '%s': no note entries defined for the type of file\n"),
4014cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     idx, section_name (ebl, idx));
4015cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
4016cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Off notes_size = check_note_data (ebl, ehdr, data, idx, 0, 0);
4017cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
4018cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (notes_size == 0)
4019cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("section [%2d] '%s': cannot get content of note section\n"),
4020cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx));
4021cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else if (notes_size != shdr->sh_size)
4022cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("section [%2d] '%s': extra %" PRIu64
4023cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    " bytes after last note\n"),
4024cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	   idx, section_name (ebl, idx), shdr->sh_size - notes_size);
4025cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
4026441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4027441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
4028441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectcheck_program_header (Ebl *ebl, GElf_Ehdr *ehdr)
4029441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
4030441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_phoff == 0)
4031441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    return;
4032441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4033441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN
4034441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      && ehdr->e_type != ET_CORE)
4035441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    ERROR (gettext ("\
4036441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectonly executables, shared objects, and core files can have program headers\n"));
4037441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4038441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  int num_pt_interp = 0;
4039441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  int num_pt_tls = 0;
4040441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  int num_pt_relro = 0;
4041441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4042441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  for (int cnt = 0; cnt < ehdr->e_phnum; ++cnt)
4043441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
4044441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      GElf_Phdr phdr_mem;
4045441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      GElf_Phdr *phdr;
4046441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4047441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      phdr = gelf_getphdr (ebl->elf, cnt, &phdr_mem);
4048441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (phdr == NULL)
4049441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
4050441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  ERROR (gettext ("cannot get program header entry %d: %s\n"),
4051441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		 cnt, elf_errmsg (-1));
4052441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  continue;
4053441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
4054441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4055441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (phdr->p_type >= PT_NUM && phdr->p_type != PT_GNU_EH_FRAME
4056cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && phdr->p_type != PT_GNU_STACK && phdr->p_type != PT_GNU_RELRO
4057cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Check for a known machine-specific type.  */
4058cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && ebl_segment_type_name (ebl, phdr->p_type, NULL, 0) == NULL)
4059441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
4060cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengprogram header entry %d: unknown program header entry type %#" PRIx64 "\n"),
4061cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       cnt, (uint64_t) phdr->p_type);
4062441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4063441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (phdr->p_type == PT_LOAD)
4064441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	has_loadable_segment = true;
4065441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (phdr->p_type == PT_INTERP)
4066441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
4067441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (++num_pt_interp != 1)
4068441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
4069441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      if (num_pt_interp == 2)
4070441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		ERROR (gettext ("\
4071441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectmore than one INTERP entry in program header\n"));
4072441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
4073441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  has_interp_segment = true;
4074441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
4075441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (phdr->p_type == PT_TLS)
4076441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
4077441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (++num_pt_tls == 2)
4078441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("more than one TLS entry in program header\n"));
4079441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
4080441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (phdr->p_type == PT_NOTE)
4081441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	check_note (ebl, ehdr, phdr, cnt);
4082cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (phdr->p_type == PT_DYNAMIC)
4083cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
4084cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (ehdr->e_type == ET_EXEC && ! has_interp_segment)
4085cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
4086cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic executable cannot have dynamic sections\n"));
4087cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
4088cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
4089cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* Check that the .dynamic section, if it exists, has
4090cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 the same address.  */
4091cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      Elf_Scn *scn = NULL;
4092cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
4093cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		{
4094cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  GElf_Shdr shdr_mem;
4095cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
4096cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC)
4097cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    {
4098cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      if (phdr->p_offset != shdr->sh_offset)
4099cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			ERROR (gettext ("\
4100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengdynamic section reference in program header has wrong offset\n"));
4101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      if (phdr->p_memsz != shdr->sh_size)
4102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			ERROR (gettext ("\
4103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengdynamic section size mismatch in program and section header\n"));
4104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      break;
4105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    }
4106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		}
4107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
4108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
4109441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (phdr->p_type == PT_GNU_RELRO)
4110441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
4111441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (++num_pt_relro == 2)
4112441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
4113441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectmore than one GNU_RELRO entry in program header\n"));
4114441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  else
4115441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
4116441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      /* Check that the region is in a writable segment.  */
4117441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      int inner;
4118441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      for (inner = 0; inner < ehdr->e_phnum; ++inner)
4119441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		{
4120441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  GElf_Phdr phdr2_mem;
4121441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  GElf_Phdr *phdr2;
4122441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  phdr2 = gelf_getphdr (ebl->elf, inner, &phdr2_mem);
4124441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  if (phdr2 == NULL)
4125441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    continue;
4126441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4127441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  if (phdr2->p_type == PT_LOAD
4128441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      && phdr->p_vaddr >= phdr2->p_vaddr
4129441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      && (phdr->p_vaddr + phdr->p_memsz
4130441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			  <= phdr2->p_vaddr + phdr2->p_memsz))
4131441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    {
4132441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      if ((phdr2->p_flags & PF_W) == 0)
4133441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			ERROR (gettext ("\
4134441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectloadable segment GNU_RELRO applies to is not writable\n"));
4135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      if ((phdr2->p_flags &~ PF_W) != (phdr->p_flags &~ PF_W))
4136441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			ERROR (gettext ("\
4137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengloadable segment [%u] flags do not match GNU_RELRO [%u] flags\n"),
4138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       cnt, inner);
4139441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      break;
4140441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    }
4141441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		}
4142441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4143441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      if (inner >= ehdr->e_phnum)
4144441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		ERROR (gettext ("\
4145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng%s segment not contained in a loaded segment\n"), "GNU_RELRO");
4146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
4147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
4148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (phdr->p_type == PT_PHDR)
4149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
4150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Check that the region is in a writable segment.  */
4151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  int inner;
4152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (inner = 0; inner < ehdr->e_phnum; ++inner)
4153cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
4154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Phdr phdr2_mem;
4155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      GElf_Phdr *phdr2;
4156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
4157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      phdr2 = gelf_getphdr (ebl->elf, inner, &phdr2_mem);
4158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (phdr2 != NULL
4159cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  && phdr2->p_type == PT_LOAD
4160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  && phdr->p_vaddr >= phdr2->p_vaddr
4161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  && (phdr->p_vaddr + phdr->p_memsz
4162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		      <= phdr2->p_vaddr + phdr2->p_memsz))
4163cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		break;
4164441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
4165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
4166cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (inner >= ehdr->e_phnum)
4167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
4168cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng%s segment not contained in a loaded segment\n"), "PHDR");
4169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
4170cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Check that offset in segment corresponds to offset in ELF
4171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     header.  */
4172cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (phdr->p_offset != ehdr->e_phoff)
4173cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    ERROR (gettext ("\
4174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengprogram header offset in ELF header and PHDR entry do not match"));
4175441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
4176441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4177cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (phdr->p_filesz > phdr->p_memsz
4178cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  && (phdr->p_memsz != 0 || phdr->p_type != PT_NOTE))
4179441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	ERROR (gettext ("\
4180441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectprogram header entry %d: file size greater than memory size\n"),
4181441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       cnt);
4182441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4183441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (phdr->p_align > 1)
4184441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
4185441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (!powerof2 (phdr->p_align))
4186441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
4187441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectprogram header entry %d: alignment not a power of 2\n"), cnt);
4188441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  else if ((phdr->p_vaddr - phdr->p_offset) % phdr->p_align != 0)
4189441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    ERROR (gettext ("\
4190441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectprogram header entry %d: file offset and virtual address not module of alignment\n"), cnt);
4191441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
4192441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
4193441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
4194441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4195441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4196441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Process one file.  */
4197441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic void
4198441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectprocess_elf_file (Elf *elf, const char *prefix, const char *suffix,
4199441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  const char *fname, size_t size, bool only_one)
4200441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
4201441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Reset variables.  */
4202441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  ndynamic = 0;
4203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  nverneed = 0;
4204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  nverdef = 0;
4205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  textrel = false;
4206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  needed_textrel = false;
4207cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  has_loadable_segment = false;
4208cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  has_interp_segment = false;
4209441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4210441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Ehdr ehdr_mem;
4211441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
4212441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Ebl *ebl;
4213441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4214441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Print the file name.  */
4215441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (!only_one)
4216441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
4217441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (prefix != NULL)
4218441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	printf ("\n%s(%s)%s:\n", prefix, fname, suffix);
4219441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
4220441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	printf ("\n%s:\n", fname);
4221441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
4222441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4223441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ehdr == NULL)
4224441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
4225441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ERROR (gettext ("cannot read ELF header: %s\n"), elf_errmsg (-1));
4226441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return;
4227441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
4228441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4229441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  ebl = ebl_openbackend (elf);
4230441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* If there is no appropriate backend library we cannot test
4231441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     architecture and OS specific features.  Any encountered extension
4232441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     is an error.  */
4233441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4234441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Go straight by the gABI, check all the parts in turn.  */
4235441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  check_elf_header (ebl, ehdr, size);
4236441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4237441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Check the program header.  */
4238441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  check_program_header (ebl, ehdr);
4239441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4240441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Next the section headers.  It is OK if there are no section
4241441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     headers at all.  */
4242441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  check_sections (ebl, ehdr);
4243441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
4244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Report if no relocation section needed the text relocation flag.  */
4245cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (textrel && !needed_textrel)
4246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ERROR (gettext ("text relocation flag set but not needed\n"));
4247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
4248441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Free the resources.  */
4249441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  ebl_closebackend (ebl);
4250441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
4251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
4252cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
4253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "debugpred.h"
4254